commit e8dbcfb1c3482f8e2931f21d3a66a9094256eef0
parent fa8cc692e2f6b3c9798b895b0b3105ee82d8109c
Author: triesap <triesap@radroots.dev>
Date: Sun, 28 Dec 2025 17:02:40 +0000
backup: switch tangle db backup to json and add export UI
- Replace db export/import backup calls with export_json/import_json
- Add settings action to export database with optional Nostr signer
- Surface export failures via handle_err and localized alert
- Bump packages submodule to include new database export API
Diffstat:
3 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/app/src/lib/utils/backup/export.ts b/app/src/lib/utils/backup/export.ts
@@ -55,7 +55,7 @@ const export_nostr_keystore_state = async (): Promise<ExportedAppState["nostr_ke
const export_tangle_db_state = async (): Promise<ExportedAppState["database"]> => {
await app_init();
const store_key = db.get_store_key();
- const backup = await db.export_backup();
+ const backup = await db.export_json();
if ("err" in backup) throw_err(backup);
return { store_key, backup };
};
diff --git a/app/src/lib/utils/backup/import.ts b/app/src/lib/utils/backup/import.ts
@@ -110,7 +110,7 @@ const restore_tangle_db_state = async (state: ImportableAppState["database"]): P
}
await reset_sql_cipher(current_store_key);
await db.reinit();
- await db.import_backup(state.backup);
+ await db.import_json(state.backup);
};
export const import_app_state = async (payload: ImportableAppState): Promise<AppImportStateResult | IError<string>> => {
diff --git a/app/src/routes/(app)/settings/+page.svelte b/app/src/routes/(app)/settings/+page.svelte
@@ -1,6 +1,62 @@
<script lang="ts">
import { ls } from "$lib/utils/i18n";
import { Settings } from "@radroots/apps-lib-pwa";
+ import { get_store, handle_err } from "@radroots/apps-lib";
+ import { nostr_event_sign } from "@radroots/nostr";
+ import { app_init, datastore, db, nostr_keys, notif } from "$lib/utils/app";
+ import type { cfg_datastore_key_obj_map_types } from "$lib/utils/config";
+ import type { NostrEventEnvelope, TangleDatabaseExportSigner } from "@radroots/client/tangle";
+
+ declare const __APP_NAME__: string;
+ declare const __APP_VERSION__: string;
+
+ const ls_val = get_store(ls);
+
+ const logout = async (): Promise<void> => {
+ alert("not implemented");
+ };
+
+ const export_database = async (): Promise<void> => {
+ try {
+ await app_init();
+ const app_data = await datastore.get_obj<cfg_datastore_key_obj_map_types["app_data"]>("app_data");
+ let signer: TangleDatabaseExportSigner | undefined;
+ if (!("err" in app_data)) {
+ const active_key = app_data.result.active_key;
+ const secret_key = await nostr_keys.read(active_key);
+ if (!("err" in secret_key)) {
+ const key = secret_key.secret_key;
+ signer = async ({ db_sha256, manifest }): Promise<NostrEventEnvelope | null> => {
+ const payload = JSON.stringify({
+ db_sha256,
+ export_version: manifest.rs.export_version,
+ schema_hash: manifest.rs.schema_hash
+ });
+ const event = nostr_event_sign({
+ secret_key: key,
+ event: {
+ kind: 1,
+ created_at: Math.floor(Date.now() / 1000),
+ tags: [["t", "radroots:tangle-db-export"]],
+ content: payload
+ }
+ });
+ return event;
+ };
+ }
+ }
+
+ const res = await db.export_database({
+ app_name: __APP_NAME__,
+ app_version: __APP_VERSION__,
+ signer
+ });
+ if (res && "err" in res) throw new Error(res.err);
+ } catch (e) {
+ handle_err(e, "settings.export_database");
+ await notif.alert(`${ls_val(`error.backup.export_failure`)}`);
+ }
+ };
</script>
<Settings
@@ -14,7 +70,7 @@
label: {
left: [
{
- value: `${$ls(`common.logout`)}`,
+ value: "export database",
classes: `capitalize`,
},
],
@@ -24,9 +80,26 @@
key: `caret-right`,
},
},
- callback: async () => {
- alert("not implemented");
+ callback: export_database,
+ },
+ },
+ {
+ hide_active: true,
+ touch: {
+ label: {
+ left: [
+ {
+ value: `${$ls(`common.logout`)}`,
+ classes: `capitalize`,
+ },
+ ],
+ },
+ end: {
+ glyph: {
+ key: `caret-right`,
+ },
},
+ callback: logout,
},
},
],