web


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

+page.svelte (6402B)


      1 <script lang="ts">
      2     import {
      3         __APP_INFO__,
      4         app_init,
      5         app_init_reset,
      6         datastore,
      7         db,
      8         nostr_keys,
      9         notif,
     10     } from "$lib/utils/app";
     11     import type { cfg_datastore_key_obj_map_types } from "$lib/utils/config";
     12     import { ls } from "$lib/utils/i18n";
     13     import { get_store, handle_err } from "@radroots/apps-lib";
     14     import { Settings } from "@radroots/apps-lib-pwa";
     15     import type {
     16         NostrEventEnvelope,
     17         ReplicaDatabaseExportSigner,
     18         ReplicaNostrSyncSigner
     19     } from "@radroots/client/replica";
     20     import { nostr_event_sign } from "@radroots/nostr";
     21 
     22     const ls_val = get_store(ls);
     23 
     24     const logout = async (): Promise<void> => {
     25         app_init_reset();
     26     };
     27 
     28     const load_sync_signers = async (): Promise<ReplicaNostrSyncSigner[]> => {
     29         const keys_res = await nostr_keys.keys();
     30         if ("err" in keys_res) throw new Error(keys_res.err);
     31         const signers: ReplicaNostrSyncSigner[] = [];
     32         for (const public_key of keys_res.results) {
     33             const secret_res = await nostr_keys.read(public_key);
     34             if ("err" in secret_res) throw new Error(secret_res.err);
     35             const secret_key = secret_res.secret_key;
     36             if (!secret_key || typeof secret_key !== "string") continue;
     37             signers.push({ secret_key });
     38         }
     39         if (!signers.length) throw new Error("nostr sync requires signer keys");
     40         return signers;
     41     };
     42 
     43     const load_sync_relays = async (public_key: string): Promise<string[]> => {
     44         const relays_res = await db.nostr_relay_find_many({
     45             rel: {
     46                 on_profile: {
     47                     public_key,
     48                 },
     49             },
     50         });
     51         if ("err" in relays_res) throw new Error(relays_res.err);
     52         const relays = Array.from(
     53             new Set(
     54                 relays_res.results
     55                     .map((relay) => relay.url)
     56                     .filter((url) => typeof url === "string" && url.trim().length)
     57                     .map((url) => url.trim())
     58             )
     59         );
     60         if (!relays.length) throw new Error("nostr sync requires relays");
     61         return relays;
     62     };
     63 
     64     const sync_nostr_events = async (public_key: string): Promise<void> => {
     65         const signers = await load_sync_signers();
     66         const relays = await load_sync_relays(public_key);
     67         const sync_res = await db.nostr_sync_all({
     68             relays,
     69             signers,
     70             publish_timeout_ms: 10000,
     71         });
     72         if (sync_res && "err" in sync_res) throw new Error(sync_res.err);
     73     };
     74 
     75     const export_database = async (): Promise<void> => {
     76         try {
     77             await app_init();
     78             console.log(`done app_init()`);
     79             const app_data =
     80                 await datastore.get_obj<
     81                     cfg_datastore_key_obj_map_types["app_data"]
     82                 >("app_data");
     83             console.log(JSON.stringify(app_data, null, 4), `app_data`);
     84             if ("err" in app_data) throw new Error(app_data.err);
     85             await sync_nostr_events(app_data.result.active_key);
     86             let signer: ReplicaDatabaseExportSigner | undefined;
     87             const active_key = app_data.result.active_key;
     88             const secret_key = await nostr_keys.read(active_key);
     89             if (!("err" in secret_key)) {
     90                 const key = secret_key.secret_key;
     91                 signer = async ({
     92                     db_sha256,
     93                     manifest,
     94                 }): Promise<NostrEventEnvelope | null> => {
     95                     const payload = JSON.stringify({
     96                         db_sha256,
     97                         export_version: manifest.rust.export_version,
     98                         schema_hash: manifest.rust.schema_hash,
     99                     });
    100                     const event = nostr_event_sign({
    101                         secret_key: key,
    102                         event: {
    103                             kind: 1,
    104                             created_at: Math.floor(Date.now() / 1000),
    105                             tags: [["t", "radroots:replica-db-export"]],
    106                             content: payload,
    107                         },
    108                     });
    109                     return event;
    110                 };
    111             }
    112 
    113             const res = await db.export_database({
    114                 app_name: __APP_INFO__.name,
    115                 app_version: __APP_INFO__.version,
    116                 signer,
    117             });
    118             console.log(`res `, res);
    119             if (res && "err" in res) throw new Error(res.err);
    120         } catch (e) {
    121             handle_err(e, "settings.export_database");
    122             await notif.alert(`${ls_val(`error.backup.export_failure`)}`);
    123         }
    124     };
    125 </script>
    126 
    127 <Settings
    128     basis={{
    129         trellis_ext: [
    130             {
    131                 list: [
    132                     {
    133                         hide_active: true,
    134                         touch: {
    135                             label: {
    136                                 left: [
    137                                     {
    138                                         value: "export database",
    139                                         classes: `capitalize`,
    140                                     },
    141                                 ],
    142                             },
    143                             end: {
    144                                 glyph: {
    145                                     key: `caret-right`,
    146                                 },
    147                             },
    148                             callback: export_database,
    149                         },
    150                     },
    151                     {
    152                         hide_active: true,
    153                         touch: {
    154                             label: {
    155                                 left: [
    156                                     {
    157                                         value: `${$ls(`common.logout`)}`,
    158                                         classes: `capitalize`,
    159                                     },
    160                                 ],
    161                             },
    162                             end: {
    163                                 glyph: {
    164                                     key: `caret-right`,
    165                                 },
    166                             },
    167                             callback: logout,
    168                         },
    169                     },
    170                 ],
    171             },
    172         ],
    173     }}
    174 />