@interncom/diplomatic 0.0.34 → 0.0.36

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.
@@ -13,17 +13,21 @@ declare class IDBStore implements IClientStateStore {
13
13
  setHostID(id: string): Promise<void>;
14
14
  getLastFetchedAt(): Promise<Date | undefined>;
15
15
  setLastFetchedAt(ts: Date): Promise<void>;
16
- uploadQueue: Map<string, Uint8Array>;
17
- enqueueUpload: (sha256: string, cipherOp: Uint8Array) => Promise<void>;
18
- dequeueUpload: (sha256: string) => Promise<void>;
19
- peekUpload: (sha256: string) => Promise<Uint8Array | undefined>;
20
- listUploads: () => Promise<string[]>;
16
+ enqueueUpload: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
17
+ dequeueUpload: (sha256: Uint8Array) => Promise<void>;
18
+ peekUpload: (sha256: Uint8Array) => Promise<Uint8Array | undefined>;
19
+ listUploads: () => Promise<Uint8Array[]>;
21
20
  numUploads: () => Promise<number>;
22
21
  downloadQueue: Set<string>;
23
- enqueueDownload: (path: string) => Promise<void>;
24
- dequeueDownload: (path: string) => Promise<void>;
25
- listDownloads: () => Promise<string[]>;
22
+ enqueueDownload: (sha256: Uint8Array, recordedAt: Date) => Promise<void>;
23
+ dequeueDownload: (sha256: Uint8Array) => Promise<void>;
24
+ listDownloads: () => Promise<{
25
+ sha256: Uint8Array;
26
+ recordedAt: Date;
27
+ }[]>;
26
28
  numDownloads: () => Promise<number>;
29
+ storeOp: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
30
+ clearOp: (sha256: Uint8Array) => Promise<void>;
27
31
  }
28
32
  export declare const idbStore: IDBStore;
29
33
  export {};
package/dist/index.mjs CHANGED
@@ -154,33 +154,51 @@ var LocalStorageStore = class {
154
154
  }
155
155
  uploadQueue = /* @__PURE__ */ new Map();
156
156
  enqueueUpload = async (sha256, cipherOp) => {
157
- this.uploadQueue.set(sha256, cipherOp);
157
+ const hex = btoh(sha256);
158
+ this.uploadQueue.set(hex, cipherOp);
158
159
  };
159
160
  dequeueUpload = async (sha256) => {
160
- this.uploadQueue.delete(sha256);
161
+ const hex = btoh(sha256);
162
+ this.uploadQueue.delete(hex);
161
163
  };
162
164
  peekUpload = async (sha256) => {
163
- return this.uploadQueue.get(sha256);
165
+ const hex = btoh(sha256);
166
+ return this.uploadQueue.get(hex);
164
167
  };
165
168
  listUploads = async () => {
166
- return Array.from(this.uploadQueue.keys());
169
+ const hexes = Array.from(this.uploadQueue.keys());
170
+ return hexes.map(htob);
167
171
  };
168
172
  numUploads = async () => {
169
173
  return this.uploadQueue.size;
170
174
  };
171
- downloadQueue = /* @__PURE__ */ new Set();
172
- enqueueDownload = async (path) => {
173
- this.downloadQueue.add(path);
175
+ downloadQueue = /* @__PURE__ */ new Map();
176
+ enqueueDownload = async (sha256, recordedAt) => {
177
+ const hex = btoh(sha256);
178
+ this.downloadQueue.set(hex, recordedAt);
174
179
  };
175
- dequeueDownload = async (path) => {
176
- this.downloadQueue.delete(path);
180
+ dequeueDownload = async (sha256) => {
181
+ const hex = btoh(sha256);
182
+ this.downloadQueue.delete(hex);
177
183
  };
178
184
  listDownloads = async () => {
179
- return Array.from(this.downloadQueue.keys());
185
+ const list = Array.from(this.downloadQueue.entries());
186
+ return list.map(([hex, recordedAt]) => {
187
+ return { sha256: htob(hex), recordedAt };
188
+ });
180
189
  };
181
190
  numDownloads = async () => {
182
191
  return this.downloadQueue.size;
183
192
  };
193
+ ops = /* @__PURE__ */ new Map();
194
+ storeOp = async (sha256, cipherOp) => {
195
+ const hex = btoh(sha256);
196
+ this.ops.set(hex, cipherOp);
197
+ };
198
+ clearOp = async (sha256) => {
199
+ const hex = btoh(sha256);
200
+ this.ops.delete(hex);
201
+ };
184
202
  };
185
203
  var localStorageStore = new LocalStorageStore();
186
204
 
@@ -420,14 +438,17 @@ replaceTraps((oldTraps) => ({
420
438
  }));
421
439
 
422
440
  // src/idbStore.ts
423
- var db = await openDB("client-store-db", 2, {
441
+ var db = await openDB("client-store-db", 5, {
424
442
  upgrade(db3) {
425
443
  db3.createObjectStore("metaKV");
444
+ db3.createObjectStore("ops", {
445
+ keyPath: "sha256"
446
+ });
426
447
  db3.createObjectStore("uploadQueue", {
427
448
  keyPath: "sha256"
428
449
  });
429
450
  db3.createObjectStore("downloadQueue", {
430
- keyPath: "path"
451
+ keyPath: "sha256"
431
452
  });
432
453
  }
433
454
  });
@@ -479,40 +500,52 @@ var IDBStore = class {
479
500
  const str = ts.toISOString();
480
501
  await db.put("metaKV", str, "lastFetchedAt");
481
502
  }
482
- uploadQueue = /* @__PURE__ */ new Map();
483
503
  enqueueUpload = async (sha256, cipherOp) => {
484
- await db.put("uploadQueue", { sha256, cipherOp });
504
+ const hex = btoh(sha256);
505
+ await db.put("uploadQueue", { sha256: hex, cipherOp });
485
506
  };
486
507
  dequeueUpload = async (sha256) => {
487
- await db.delete("uploadQueue", sha256);
508
+ const hex = btoh(sha256);
509
+ await db.delete("uploadQueue", hex);
488
510
  };
489
511
  peekUpload = async (sha256) => {
490
- const row = await db.get("uploadQueue", sha256);
512
+ const hex = btoh(sha256);
513
+ const row = await db.get("uploadQueue", hex);
491
514
  return row?.cipherOp;
492
515
  };
493
516
  listUploads = async () => {
494
- const sha256s = await db.getAllKeys("uploadQueue");
495
- return sha256s;
517
+ const hexes = await db.getAllKeys("uploadQueue");
518
+ return hexes.map(htob);
496
519
  };
497
520
  numUploads = async () => {
498
521
  const num = await db.count("uploadQueue");
499
522
  return num;
500
523
  };
501
524
  downloadQueue = /* @__PURE__ */ new Set();
502
- enqueueDownload = async (path) => {
503
- await db.put("downloadQueue", { path });
525
+ enqueueDownload = async (sha256, recordedAt) => {
526
+ const hex = btoh(sha256);
527
+ await db.put("downloadQueue", { sha256: hex, recordedAt });
504
528
  };
505
- dequeueDownload = async (path) => {
506
- await db.delete("downloadQueue", path);
529
+ dequeueDownload = async (sha256) => {
530
+ const hex = btoh(sha256);
531
+ await db.delete("downloadQueue", hex);
507
532
  };
508
533
  listDownloads = async () => {
509
- const paths = await db.getAllKeys("downloadQueue");
510
- return paths;
534
+ const list = await db.getAll("downloadQueue");
535
+ return list.map((item) => ({ sha256: htob(item.sha256), recordedAt: item.recordedAt }));
511
536
  };
512
537
  numDownloads = async () => {
513
538
  const num = await db.count("downloadQueue");
514
539
  return num;
515
540
  };
541
+ storeOp = async (sha256, cipherOp) => {
542
+ const hex = btoh(sha256);
543
+ await db.put("ops", { sha256: hex, cipherOp });
544
+ };
545
+ clearOp = async (sha256) => {
546
+ const hex = btoh(sha256);
547
+ await db.delete("ops", hex);
548
+ };
516
549
  };
517
550
  var idbStore = new IDBStore();
518
551
 
@@ -8721,8 +8754,9 @@ var DiplomaticClientAPI = class {
8721
8754
  const opPath = await response.text();
8722
8755
  return opPath;
8723
8756
  }
8724
- async getDelta(hostURL, opPath, keyPair) {
8757
+ async getDelta(hostURL, sha256, keyPair) {
8725
8758
  const url = new URL(hostURL);
8759
+ const opPath = btoh(sha256);
8726
8760
  url.pathname = `/ops/${opPath}`;
8727
8761
  const sig = await this.crypto.signEd25519(opPath, keyPair.privateKey);
8728
8762
  const sigHex = btoh(sig);
@@ -8744,7 +8778,7 @@ var DiplomaticClientAPI = class {
8744
8778
  }
8745
8779
  return resp.cipher;
8746
8780
  }
8747
- async getDeltaPaths(hostURL, begin, keyPair) {
8781
+ async listDeltas(hostURL, begin, keyPair) {
8748
8782
  const t = begin.toISOString();
8749
8783
  const path = `/ops?begin=${t}`;
8750
8784
  const url = new URL(hostURL);
@@ -8958,33 +8992,34 @@ var DiplomaticClient = class {
8958
8992
  const lastFetchedAt = await this.store.getLastFetchedAt();
8959
8993
  const begin = lastFetchedAt ?? /* @__PURE__ */ new Date(0);
8960
8994
  const { hostURL, hostKeyPair } = this;
8961
- const pathResp = await api_default.getDeltaPaths(hostURL, begin, hostKeyPair);
8962
- const paths = pathResp.paths;
8963
- for (const path of paths) {
8964
- await this.store.enqueueDownload(path);
8995
+ const resp = await api_default.listDeltas(hostURL, begin, hostKeyPair);
8996
+ for (const item of resp.deltas) {
8997
+ await this.store.enqueueDownload(item.sha256, item.recordedAt);
8965
8998
  this.emitUpdate();
8966
8999
  }
8967
- await this.store.setLastFetchedAt(new Date(pathResp.fetchedAt));
9000
+ await this.store.setLastFetchedAt(new Date(resp.fetchedAt));
8968
9001
  }
8969
9002
  async fetchAndExecQueuedOps() {
8970
9003
  if (!this.hostURL || !this.hostKeyPair || !this.encKey) {
8971
9004
  return [];
8972
9005
  }
8973
9006
  const { hostURL, hostKeyPair, encKey } = this;
8974
- const paths = await this.store.listDownloads();
8975
- paths.sort((p1, p2) => p1.localeCompare(p2));
8976
- for (const path of paths) {
8977
- const cipher = await api_default.getDelta(hostURL, path, hostKeyPair);
9007
+ const items = await this.store.listDownloads();
9008
+ items.sort((i1, i2) => i1.recordedAt.getTime() - i2.recordedAt.getTime());
9009
+ for (const item of items) {
9010
+ const cipher = await api_default.getDelta(hostURL, item.sha256, hostKeyPair);
8978
9011
  const packed = await crypto_default.decryptXSalsa20Poly1305Combined(cipher, encKey);
8979
9012
  const op = decode(packed);
8980
9013
  try {
9014
+ const sha256 = await crypto_default.sha256Hash(cipher);
9015
+ await this.store.storeOp(sha256, cipher);
8981
9016
  await this.stateManager.apply(op);
8982
- await this.store.dequeueDownload(path);
9017
+ await this.store.dequeueDownload(sha256);
8983
9018
  this.emitUpdate();
8984
9019
  } catch {
8985
9020
  const transient = true;
8986
9021
  if (!transient) {
8987
- await this.store.dequeueDownload(path);
9022
+ await this.store.dequeueDownload(item.sha256);
8988
9023
  this.emitUpdate();
8989
9024
  }
8990
9025
  }
@@ -9017,17 +9052,17 @@ var DiplomaticClient = class {
9017
9052
  const packed = encode(op);
9018
9053
  const cipherOp = await crypto_default.encryptXSalsa20Poly1305Combined(packed, this.encKey);
9019
9054
  const sha256 = await crypto_default.sha256Hash(cipherOp);
9020
- const shaHex = btoh(sha256);
9021
- await this.store.enqueueUpload(shaHex, cipherOp);
9055
+ await this.store.storeOp(sha256, cipherOp);
9056
+ await this.store.enqueueUpload(sha256, cipherOp);
9022
9057
  this.emitUpdate();
9023
9058
  try {
9024
9059
  await this.stateManager.apply(op);
9025
9060
  } catch (err) {
9026
- await this.store.dequeueUpload(shaHex);
9061
+ await this.store.dequeueUpload(sha256);
9027
9062
  this.emitUpdate();
9028
9063
  }
9029
9064
  try {
9030
- await this.pushQueuedOp(shaHex);
9065
+ await this.pushQueuedOp(sha256);
9031
9066
  } catch (err) {
9032
9067
  console.info("failed to push");
9033
9068
  }
@@ -10,16 +10,22 @@ declare class LocalStorageStore implements IClientStateStore {
10
10
  getLastFetchedAt(): Promise<Date | undefined>;
11
11
  setLastFetchedAt(ts: Date): Promise<void>;
12
12
  uploadQueue: Map<string, Uint8Array>;
13
- enqueueUpload: (sha256: string, cipherOp: Uint8Array) => Promise<void>;
14
- dequeueUpload: (sha256: string) => Promise<void>;
15
- peekUpload: (sha256: string) => Promise<Uint8Array | undefined>;
16
- listUploads: () => Promise<string[]>;
13
+ enqueueUpload: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
14
+ dequeueUpload: (sha256: Uint8Array) => Promise<void>;
15
+ peekUpload: (sha256: Uint8Array) => Promise<Uint8Array | undefined>;
16
+ listUploads: () => Promise<Uint8Array[]>;
17
17
  numUploads: () => Promise<number>;
18
- downloadQueue: Set<string>;
19
- enqueueDownload: (path: string) => Promise<void>;
20
- dequeueDownload: (path: string) => Promise<void>;
21
- listDownloads: () => Promise<string[]>;
18
+ downloadQueue: Map<string, Date>;
19
+ enqueueDownload: (sha256: Uint8Array, recordedAt: Date) => Promise<void>;
20
+ dequeueDownload: (sha256: Uint8Array) => Promise<void>;
21
+ listDownloads: () => Promise<{
22
+ sha256: Uint8Array;
23
+ recordedAt: Date;
24
+ }[]>;
22
25
  numDownloads: () => Promise<number>;
26
+ ops: Map<string, Uint8Array>;
27
+ storeOp: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
28
+ clearOp: (sha256: Uint8Array) => Promise<void>;
23
29
  }
24
30
  export declare const localStorageStore: LocalStorageStore;
25
31
  export {};
@@ -14,16 +14,22 @@ declare class MemoryStore implements IClientStateStore {
14
14
  getLastFetchedAt(): Promise<Date | undefined>;
15
15
  setLastFetchedAt(ts: Date): Promise<void>;
16
16
  uploadQueue: Map<string, Uint8Array>;
17
- enqueueUpload: (sha256: string, cipherOp: Uint8Array) => Promise<void>;
18
- dequeueUpload: (sha256: string) => Promise<void>;
19
- peekUpload: (sha256: string) => Promise<Uint8Array | undefined>;
20
- listUploads: () => Promise<string[]>;
17
+ enqueueUpload: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
18
+ dequeueUpload: (sha256: Uint8Array) => Promise<void>;
19
+ peekUpload: (sha256: Uint8Array) => Promise<Uint8Array | undefined>;
20
+ listUploads: () => Promise<Uint8Array[]>;
21
21
  numUploads: () => Promise<number>;
22
- downloadQueue: Set<string>;
23
- enqueueDownload: (path: string) => Promise<void>;
24
- dequeueDownload: (path: string) => Promise<void>;
25
- listDownloads: () => Promise<string[]>;
22
+ downloadQueue: Map<string, Date>;
23
+ enqueueDownload: (sha256: Uint8Array, recordedAt: Date) => Promise<void>;
24
+ dequeueDownload: (sha256: Uint8Array) => Promise<void>;
25
+ listDownloads: () => Promise<{
26
+ sha256: Uint8Array;
27
+ recordedAt: Date;
28
+ }[]>;
26
29
  numDownloads: () => Promise<number>;
30
+ ops: Map<string, Uint8Array>;
31
+ storeOp: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
32
+ clearOp: (sha256: Uint8Array) => Promise<void>;
27
33
  }
28
34
  export declare const memoryStore: MemoryStore;
29
35
  export {};
@@ -1,4 +1,4 @@
1
- import type { ICrypto, IGetDeltaPathsResponse, IMsgpackCodec, KeyPair } from "./types.ts";
1
+ import type { ICrypto, IListDeltasResponse, IMsgpackCodec, KeyPair } from "./types.ts";
2
2
  export default class DiplomaticClientAPI {
3
3
  codec: IMsgpackCodec;
4
4
  crypto: ICrypto;
@@ -6,6 +6,6 @@ export default class DiplomaticClientAPI {
6
6
  getHostID(hostURL: URL): Promise<string>;
7
7
  register(hostURL: URL, pubKey: Uint8Array, token: string): Promise<void>;
8
8
  putDelta(hostURL: URL, cipherOp: Uint8Array, keyPair: KeyPair): Promise<string>;
9
- getDelta(hostURL: URL, opPath: string, keyPair: KeyPair): Promise<Uint8Array>;
10
- getDeltaPaths(hostURL: URL, begin: Date, keyPair: KeyPair): Promise<IGetDeltaPathsResponse>;
9
+ getDelta(hostURL: URL, sha256: Uint8Array, keyPair: KeyPair): Promise<Uint8Array>;
10
+ listDeltas(hostURL: URL, begin: Date, keyPair: KeyPair): Promise<IListDeltasResponse>;
11
11
  }
@@ -29,16 +29,20 @@ export interface IRegistrationRequest {
29
29
  export interface IOperationRequest {
30
30
  cipher: Uint8Array;
31
31
  }
32
- export interface IGetDeltaPathsResponse {
33
- paths: string[];
32
+ export interface IDeltaListItem {
33
+ sha256: Uint8Array;
34
+ recordedAt: Date;
35
+ }
36
+ export interface IListDeltasResponse {
37
+ deltas: IDeltaListItem[];
34
38
  fetchedAt: string;
35
39
  }
36
40
  export interface IStorage {
37
41
  addUser: (pubKeyHex: string) => Promise<void>;
38
42
  hasUser: (pubKeyHex: string) => Promise<boolean>;
39
- setOp: (pubKeyHex: string, path: string, op: Uint8Array) => Promise<void>;
40
- getOp: (pubKeyHex: string, path: string) => Promise<Uint8Array | undefined>;
41
- listOps: (pubKeyHex: string, begin: string, end: string) => Promise<string[]>;
43
+ setOp: (pubKeyHex: string, recordedAt: Date, op: Uint8Array) => Promise<void>;
44
+ getOp: (pubKeyHex: string, sha256Hex: string) => Promise<Uint8Array | undefined>;
45
+ listOps: (pubKeyHex: string, begin: string, end: string) => Promise<IDeltaListItem[]>;
42
46
  }
43
47
  export interface KeyPair {
44
48
  keyType: "public" | "private" | "secret";
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { IOp } from "./shared/types";
1
+ import type { IDeltaListItem, IOp } from "./shared/types";
2
2
  export interface IClientStateStore {
3
3
  init?: () => Promise<void>;
4
4
  getSeed: () => Promise<Uint8Array | undefined>;
@@ -10,15 +10,17 @@ export interface IClientStateStore {
10
10
  setLastFetchedAt: (ts: Date) => Promise<void>;
11
11
  getLastFetchedAt: () => Promise<Date | undefined>;
12
12
  wipe: () => Promise<void>;
13
- enqueueUpload: (sha256: string, cipherOp: Uint8Array) => Promise<void>;
14
- dequeueUpload: (sha256: string) => Promise<void>;
15
- peekUpload: (sha256: string) => Promise<Uint8Array | undefined>;
16
- listUploads: () => Promise<string[]>;
13
+ enqueueUpload: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
14
+ dequeueUpload: (sha256: Uint8Array) => Promise<void>;
15
+ peekUpload: (sha256: Uint8Array) => Promise<Uint8Array | undefined>;
16
+ listUploads: () => Promise<Uint8Array[]>;
17
17
  numUploads: () => Promise<number>;
18
- enqueueDownload: (path: string) => Promise<void>;
19
- dequeueDownload: (path: string) => Promise<void>;
20
- listDownloads: () => Promise<string[]>;
18
+ enqueueDownload: (sha256: Uint8Array, recordedAt: Date) => Promise<void>;
19
+ dequeueDownload: (sha256: Uint8Array) => Promise<void>;
20
+ listDownloads: () => Promise<IDeltaListItem[]>;
21
21
  numDownloads: () => Promise<number>;
22
+ storeOp: (sha256: Uint8Array, cipherOp: Uint8Array) => Promise<void>;
23
+ clearOp: (sha256: Uint8Array) => Promise<void>;
22
24
  }
23
25
  export interface IDiplomaticClientState {
24
26
  hasSeed: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interncom/diplomatic",
3
- "version": "0.0.34",
3
+ "version": "0.0.36",
4
4
  "type": "module",
5
5
  "description": "Secure sync layer",
6
6
  "main": "dist/index.mjs",