web


git clone https://radroots.dev/git/web.git
Log | Files | Refs | Submodules | README | LICENSE

export.ts (3707B)


      1 import { app_init, datastore, db, nostr_keys, notif } from "$lib/utils/app";
      2 import { ls } from "$lib/utils/i18n";
      3 import { download_json, get_store, handle_err } from "@radroots/apps-lib";
      4 import type { ExportedAppState } from "@radroots/apps-lib-pwa/types/app";
      5 import { throw_err } from "@radroots/utils";
      6 import { createStore, get as idb_get, keys as idb_keys, type UseStore } from "idb-keyval";
      7 import { app_cfg } from "../app/config";
      8 
      9 const ls_val = get_store(ls);
     10 
     11 const parse_idb_entry = async (key: IDBValidKey, store: UseStore): Promise<[string, string] | undefined> => {
     12     if (typeof key !== "string") return undefined;
     13     const value = await idb_get(key, store);
     14     if (typeof value === "undefined") return undefined;
     15     return [key, value];
     16 };
     17 
     18 const export_datastore_state = async (): Promise<ExportedAppState["datastore"]> => {
     19     await datastore.init();
     20     const ds_cfg = datastore.get_config();
     21     if (!ds_cfg) throw_err(ls_val(`error.app.export.missing_datastore_config`));
     22     const ds_store = createStore(ds_cfg.database, ds_cfg.store);
     23     const ds_keys = await idb_keys(ds_store);
     24     const entries: Record<string, unknown> = {};
     25     for (const key of ds_keys) {
     26         const entry = await parse_idb_entry(key, ds_store);
     27         if (entry) entries[entry[0]] = entry[1];
     28     }
     29     return { config: ds_cfg, entries };
     30 };
     31 
     32 const export_nostr_keystore_state = async (): Promise<ExportedAppState["nostr_keystore"]> => {
     33     const nostr_cfg = nostr_keys.get_config();
     34     if (!nostr_cfg) throw_err(ls_val(`error.app.export.missing_nostr_keystore_config`));
     35 
     36     const keys: ExportedAppState["nostr_keystore"]["keys"] = [];
     37     try {
     38         const nostr_keys_all = await nostr_keys.keys();
     39         if ("err" in nostr_keys_all) throw_err(nostr_keys_all.err);
     40         for (const public_key of nostr_keys_all.results) {
     41             const secret_key = await nostr_keys.read(public_key);
     42             if ("err" in secret_key) throw_err(secret_key.err);
     43             keys.push({
     44                 public_key,
     45                 secret_key: secret_key.secret_key
     46             });
     47         }
     48     } catch { }
     49     return {
     50         config: nostr_cfg,
     51         keys
     52     };
     53 };
     54 
     55 const export_replica_db_state = async (): Promise<ExportedAppState["database"]> => {
     56     await app_init();
     57     const store_key = db.get_store_key();
     58     const backup = await db.export_json();
     59     if ("err" in backup) throw_err(backup);
     60     return { store_key, backup };
     61 };
     62 
     63 export const export_app_state = async (): Promise<void> => {
     64     try {
     65         if (typeof window === "undefined") return;
     66         const [
     67             datastore_state,
     68             nostr_keystore_state,
     69             replica_db_state
     70         ] = await Promise.all([
     71             export_datastore_state(),
     72             export_nostr_keystore_state(),
     73             export_replica_db_state()
     74         ]);
     75         const payload: ExportedAppState = {
     76             backup_version: app_cfg.backup.version,
     77             exported_at: new Date().toISOString(),
     78             versions: {
     79                 app: app_cfg.version,
     80                 replica_db: replica_db_state.backup.replica_db_version,
     81                 backup_format: replica_db_state.backup.format_version
     82             },
     83             datastore: datastore_state,
     84             nostr_keystore: nostr_keystore_state,
     85             database: replica_db_state
     86         };
     87         const ts = payload.exported_at.replace(/[:.]/g, "-");
     88         const filename_prefix = ls_val(`common.radroots_app_state_filename_prefix`);
     89         download_json(payload, `${filename_prefix}-${ts}.json`);
     90     } catch (e) {
     91         handle_err(e, `export_app_state`);
     92         await notif.alert(`${ls_val(`error.backup.export_failure`)}`);
     93     }
     94 };