monoidentity 0.17.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/+client.d.ts CHANGED
@@ -3,5 +3,5 @@ export { getLoginRecognized, relog, getVerification, getStorage, getScopedFS, co
3
3
  export type { SyncStrategy } from "./storage/utils-storage.js";
4
4
  export { retrieveVerification } from "./verification-client.js";
5
5
  export { attest as rawAttest } from "./verification/attest.js";
6
- export { trackReady } from "./trackready.js";
6
+ export { syncFinished, readyUp } from "./readyup.js";
7
7
  export { default as Monoidentity } from "./Monoidentity.svelte";
package/dist/+client.js CHANGED
@@ -2,5 +2,5 @@ export * from "./+common.js";
2
2
  export { getLoginRecognized, relog, getVerification, getStorage, getScopedFS, completeSync, } from "./storage.js";
3
3
  export { retrieveVerification } from "./verification-client.js";
4
4
  export { attest as rawAttest } from "./verification/attest.js";
5
- export { trackReady } from "./trackready.js";
5
+ export { syncFinished, readyUp } from "./readyup.js";
6
6
  export { default as Monoidentity } from "./Monoidentity.svelte";
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
- import { trackReady } from "./trackready.js";
3
+ import { readyUp } from "./readyup.js";
4
4
  import type { Intent } from "./utils-transport.js";
5
5
  import type { SyncStrategy } from "./storage/utils-storage.js";
6
6
 
@@ -17,7 +17,7 @@
17
17
  } = $props();
18
18
 
19
19
  let backup: (() => void) | undefined = $state();
20
- const ready = trackReady(
20
+ readyUp(
21
21
  app,
22
22
  intents || [],
23
23
  getSyncStrategy,
@@ -35,11 +35,7 @@
35
35
  <button class="primary" onclick={yes}>Connect</button>
36
36
  {/snippet}
37
37
 
38
- {#await ready}
39
- <p class="center">Setting up</p>
40
- {:then}
41
- {@render children()}
42
- {/await}
38
+ {@render children()}
43
39
  {#if backup}
44
40
  <div class="backup toast">
45
41
  {@render backupUI(backup, () => (backup = undefined))}
@@ -88,7 +84,4 @@
88
84
  top: 1rem;
89
85
  z-index: 1000;
90
86
  }
91
- .center {
92
- margin: auto;
93
- }
94
87
  </style>
@@ -0,0 +1,4 @@
1
+ import { type Intent } from "./utils-transport.js";
2
+ import type { SyncStrategy } from "./storage/utils-storage.js";
3
+ export declare const syncFinished: Promise<void>;
4
+ export declare const readyUp: (app: string, intents: Intent[], getSyncStrategy: (path: string) => SyncStrategy, requestBackup: (startBackup: () => void) => void) => void;
@@ -6,7 +6,11 @@ import { conf, setLoginRecognized } from "./storage.js";
6
6
  import { backupLocally } from "./storage/backuplocally.js";
7
7
  import { backupCloud } from "./storage/backupcloud.js";
8
8
  import { switchToHub } from "./utils-hub.js";
9
- export const trackReady = async (app, intents, getSyncStrategy, requestBackup) => {
9
+ let resolveSyncFinished;
10
+ export const syncFinished = new Promise((resolve) => {
11
+ resolveSyncFinished = resolve;
12
+ });
13
+ export const readyUp = (app, intents, getSyncStrategy, requestBackup) => {
10
14
  conf(app);
11
15
  let setup = localStorage["monoidentity-x/setup"]
12
16
  ? JSON.parse(localStorage["monoidentity-x/setup"])
@@ -27,15 +31,18 @@ export const trackReady = async (app, intents, getSyncStrategy, requestBackup) =
27
31
  if (!setup) {
28
32
  switchToHub([{ storage: true }, ...intents]);
29
33
  }
30
- if (setup.method == "localStorage") {
31
- await backupLocally(getSyncStrategy, requestBackup);
32
- }
33
- if (setup.method == "cloud") {
34
- await backupCloud(getSyncStrategy, setup);
35
- }
36
34
  for (const provision of provisions) {
37
35
  if ("createLoginRecognized" in provision) {
38
36
  setLoginRecognized(provision.createLoginRecognized);
39
37
  }
40
38
  }
39
+ (async () => {
40
+ if (setup.method == "localStorage") {
41
+ await backupLocally(getSyncStrategy, requestBackup);
42
+ }
43
+ if (setup.method == "cloud") {
44
+ await backupCloud(getSyncStrategy, setup);
45
+ }
46
+ resolveSyncFinished();
47
+ })();
41
48
  };
@@ -2,9 +2,26 @@ import { AwsClient } from "aws4fetch";
2
2
  import { storageClient, STORAGE_EVENT } from "./storageclient.svelte.js";
3
3
  import { addToSync } from "../storage.js";
4
4
  import { shouldPersist, enqueueSync } from "./utils-storage.js";
5
- const CLOUD_CACHE_KEY = "monoidentity-x/cloud-cache";
5
+ import { get, set } from "idb-keyval";
6
+ import { store } from "./utils-idb.js";
7
+ const CLOUD_CACHE_KEY = "cloud-cache";
6
8
  let unmount;
9
+ let cache;
10
+ const initCache = async () => {
11
+ cache = (await get(CLOUD_CACHE_KEY, store)) || {};
12
+ };
13
+ const getCache = () => {
14
+ if (!cache)
15
+ throw new Error("Cache not initialized");
16
+ return cache;
17
+ };
18
+ const saveCache = async () => {
19
+ if (!cache)
20
+ throw new Error("Cache not initialized");
21
+ await set(CLOUD_CACHE_KEY, cache, store);
22
+ };
7
23
  const loadFromCloud = async (getSyncStrategy, base, client) => {
24
+ const cachePromise = initCache();
8
25
  const listResp = await client.fetch(base);
9
26
  if (!listResp.ok)
10
27
  throw new Error(`List bucket failed: ${listResp.status}`);
@@ -12,8 +29,9 @@ const loadFromCloud = async (getSyncStrategy, base, client) => {
12
29
  const objects = [...listXml.matchAll(/<Key>(.*?)<\/Key>.*?<ETag>(.*?)<\/ETag>/gs)]
13
30
  .map((m) => m.slice(1).map((s) => s.replaceAll("&quot;", `"`).replaceAll("&apos;", `'`)))
14
31
  .map(([key, etag]) => ({ key, etag: etag.replaceAll(`"`, "") }))
15
- .filter(({ key }) => getSyncStrategy(key).mode != "none");
16
- const prevCache = JSON.parse(localStorage[CLOUD_CACHE_KEY] || "{}");
32
+ .filter(({ key }) => getSyncStrategy(key));
33
+ await cachePromise;
34
+ const prevCache = getCache();
17
35
  const nextCache = {};
18
36
  const model = {};
19
37
  await Promise.all(objects.map(async ({ key, etag }) => {
@@ -42,7 +60,8 @@ const loadFromCloud = async (getSyncStrategy, base, client) => {
42
60
  model[key] = content;
43
61
  nextCache[key] = { etag, content };
44
62
  }));
45
- localStorage[CLOUD_CACHE_KEY] = JSON.stringify(nextCache);
63
+ cache = nextCache;
64
+ saveCache();
46
65
  return model;
47
66
  };
48
67
  const syncFromCloud = async (getSyncStrategy, bucket, client) => {
@@ -72,7 +91,7 @@ export const backupCloud = async (getSyncStrategy, bucket) => {
72
91
  // Continuous sync: mirror local changes to cloud
73
92
  const write = async (key, value) => {
74
93
  const strategy = getSyncStrategy(key);
75
- if (strategy.mode == "none") {
94
+ if (!strategy) {
76
95
  if (!shouldPersist(key))
77
96
  console.warn("[monoidentity cloud]", key, "isn't marked to be backed up or saved");
78
97
  return;
@@ -91,9 +110,8 @@ export const backupCloud = async (getSyncStrategy, bucket) => {
91
110
  // Update cache
92
111
  const etag = r.headers.get("etag")?.replaceAll('"', "");
93
112
  if (etag) {
94
- const cache = JSON.parse(localStorage[CLOUD_CACHE_KEY] || "{}");
95
- cache[key] = { etag, content: value };
96
- localStorage[CLOUD_CACHE_KEY] = JSON.stringify(cache);
113
+ getCache()[key] = { etag, content: value };
114
+ saveCache();
97
115
  }
98
116
  }
99
117
  else {
@@ -101,9 +119,6 @@ export const backupCloud = async (getSyncStrategy, bucket) => {
101
119
  const r = await client.fetch(url, { method: "DELETE" });
102
120
  if (!r.ok && r.status != 404)
103
121
  throw new Error(`DELETE ${key} failed: ${r.status}`);
104
- const cache = JSON.parse(localStorage[CLOUD_CACHE_KEY] || "{}");
105
- delete cache[key];
106
- localStorage[CLOUD_CACHE_KEY] = JSON.stringify(cache);
107
122
  }
108
123
  };
109
124
  const writeWrapped = async (key, value) => write(key, value).catch((err) => {
@@ -115,7 +130,7 @@ export const backupCloud = async (getSyncStrategy, bucket) => {
115
130
  return;
116
131
  const key = fullKey.slice("monoidentity/".length);
117
132
  const strategy = getSyncStrategy(key);
118
- if (strategy.mode == "none")
133
+ if (!strategy)
119
134
  return;
120
135
  if (strategy.mode == "immediate") {
121
136
  addToSync(writeWrapped(key, event.detail.value));
@@ -1,7 +1,10 @@
1
- import { createStore, get, set } from "idb-keyval";
1
+ import { get, set } from "idb-keyval";
2
2
  import { STORAGE_EVENT, storageClient } from "./storageclient.svelte.js";
3
3
  import { canBackup } from "../utils-localstorage.js";
4
4
  import { shouldPersist } from "./utils-storage.js";
5
+ import { store } from "./utils-idb.js";
6
+ const TOGGLE_KEY = "monoidentity-x/local-backup";
7
+ const HANDLE_KEY = "backup-handle";
5
8
  let unmount;
6
9
  const saveToDir = (getSyncStrategy, dir) => {
7
10
  let dirCache = {};
@@ -39,7 +42,7 @@ const saveToDir = (getSyncStrategy, dir) => {
39
42
  return;
40
43
  const key = fullKey.slice("monoidentity/".length);
41
44
  const strategy = getSyncStrategy(key);
42
- if (strategy.mode == "none") {
45
+ if (!strategy) {
43
46
  if (!shouldPersist(key))
44
47
  console.warn("[monoidentity backup]", key, "isn't marked to be backed up or saved");
45
48
  return;
@@ -55,22 +58,21 @@ const saveToDir = (getSyncStrategy, dir) => {
55
58
  export const backupLocally = async (getSyncStrategy, requestBackup) => {
56
59
  if (!canBackup)
57
60
  return;
58
- if (localStorage["monoidentity-x/backup"] == "off")
61
+ if (localStorage[TOGGLE_KEY] == "off")
59
62
  return;
60
63
  unmount?.();
61
- const handles = createStore("monoidentity-x", "handles");
62
- if (localStorage["monoidentity-x/backup"] == "on") {
63
- const dir = await get("backup", handles);
64
+ if (localStorage[TOGGLE_KEY] == "on") {
65
+ const dir = await get(HANDLE_KEY, store);
64
66
  if (!dir)
65
67
  throw new Error("No backup handle found");
66
68
  unmount = saveToDir(getSyncStrategy, dir);
67
69
  }
68
70
  else {
69
- localStorage["monoidentity-x/backup"] = "off";
71
+ localStorage[TOGGLE_KEY] = "off";
70
72
  requestBackup(async () => {
71
73
  const dir = await showDirectoryPicker({ mode: "readwrite" });
72
- await set("backup", dir, handles);
73
- localStorage["monoidentity-x/backup"] = "on";
74
+ await set(HANDLE_KEY, dir, store);
75
+ localStorage[TOGGLE_KEY] = "on";
74
76
  // Restore from backup
75
77
  const backup = {};
76
78
  const traverse = async (d, path) => {
@@ -0,0 +1 @@
1
+ export declare const store: import("idb-keyval").UseStore;
@@ -0,0 +1,2 @@
1
+ import { createStore } from "idb-keyval";
2
+ export const store = createStore("monoidentity-x", "keyval");
@@ -1,7 +1,5 @@
1
1
  export declare const shouldPersist: (key: string) => boolean;
2
- export type SyncStrategy = {
3
- mode: "none";
4
- } | {
2
+ export type SyncStrategy = undefined | {
5
3
  mode: "immediate";
6
4
  } | {
7
5
  mode: "debounced";
@@ -1,4 +1,4 @@
1
- export const shouldPersist = (key) => key.includes(".cache/");
1
+ export const shouldPersist = (key) => key.startsWith(".cache/") || key.startsWith(".local/");
2
2
  const syncQueue = {};
3
3
  export const enqueueSync = (key, debounceMs, sync) => {
4
4
  // Cancel existing timeout if any
package/dist/storage.js CHANGED
@@ -15,9 +15,13 @@ export const addToSync = (p) => {
15
15
  syncPromise = syncPromise.then(() => p);
16
16
  };
17
17
  export const completeSync = () => syncPromise;
18
- const LOGIN_RECOGNIZED_PATH = ".core/login.encjson";
18
+ const LOGIN_RECOGNIZED_PATH = ".local/login.encjson";
19
19
  export const getLoginRecognized = () => {
20
20
  const client = storageClient();
21
+ if (client[".core/login.encjson"]) {
22
+ client[LOGIN_RECOGNIZED_PATH] = client[".core/login.encjson"];
23
+ delete client[".core/login.encjson"];
24
+ }
21
25
  const login = client[LOGIN_RECOGNIZED_PATH];
22
26
  if (!login)
23
27
  throw new Error("No login found");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monoidentity",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "license": "ISC",
5
5
  "repository": "KTibow/monoidentity",
6
6
  "author": {
@@ -1,3 +0,0 @@
1
- import { type Intent } from "./utils-transport.js";
2
- import type { SyncStrategy } from "./storage/utils-storage.js";
3
- export declare const trackReady: (app: string, intents: Intent[], getSyncStrategy: (path: string) => SyncStrategy, requestBackup: (startBackup: () => void) => void) => Promise<void>;