@interncom/diplomatic 0.0.10 → 0.0.12
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/idbStore.d.ts +23 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +334 -37
- package/dist/localStorageStore.d.ts +9 -3
- package/dist/memoryStore.d.ts +23 -0
- package/dist/queue.d.ts +1 -1
- package/dist/types.d.ts +7 -32
- package/package.json +8 -5
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IClientStateStore } from "./types";
|
|
2
|
+
declare class IDBStore implements IClientStateStore {
|
|
3
|
+
seed?: Uint8Array;
|
|
4
|
+
hostURL?: string;
|
|
5
|
+
hostID?: string;
|
|
6
|
+
getSeed(): Promise<Uint8Array | undefined>;
|
|
7
|
+
setSeed(seed: Uint8Array): Promise<void>;
|
|
8
|
+
getHostURL(): Promise<string | undefined>;
|
|
9
|
+
setHostURL(url: string): Promise<void>;
|
|
10
|
+
getHostID(): Promise<string | undefined>;
|
|
11
|
+
setHostID(id: string): Promise<void>;
|
|
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[]>;
|
|
17
|
+
downloadQueue: Set<string>;
|
|
18
|
+
enqueueDownload: (path: string) => Promise<void>;
|
|
19
|
+
dequeueDownload: (path: string) => Promise<void>;
|
|
20
|
+
listDownloads: () => Promise<string[]>;
|
|
21
|
+
}
|
|
22
|
+
export declare const idbStore: IDBStore;
|
|
23
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useClientState } from "./useClient";
|
|
2
2
|
import { StateManager, useStateWatcher } from './state';
|
|
3
3
|
import { localStorageStore } from "./localStorageStore";
|
|
4
|
+
import { idbStore } from "./idbStore";
|
|
4
5
|
import DiplomaticClient from "./client";
|
|
5
6
|
import libsodiumCrypto from "./crypto";
|
|
6
7
|
import { btoh, htob } from "./shared/lib";
|
|
7
8
|
import { type IOp, Verb } from "./shared/types";
|
|
8
|
-
export { useClientState, StateManager, useStateWatcher, localStorageStore, DiplomaticClient, libsodiumCrypto, btoh, htob, Verb, };
|
|
9
|
+
export { useClientState, StateManager, useStateWatcher, localStorageStore, idbStore, DiplomaticClient, libsodiumCrypto, btoh, htob, Verb, };
|
|
9
10
|
export type { IOp, };
|
package/dist/index.mjs
CHANGED
|
@@ -80,31 +80,6 @@ function useStateWatcher(mgr, opType, callback) {
|
|
|
80
80
|
return val;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
// src/queue.ts
|
|
84
|
-
var Queue = class {
|
|
85
|
-
map;
|
|
86
|
-
constructor() {
|
|
87
|
-
this.map = /* @__PURE__ */ new Map();
|
|
88
|
-
}
|
|
89
|
-
async enqueue(key, value) {
|
|
90
|
-
this.map.set(key, value);
|
|
91
|
-
}
|
|
92
|
-
async peek(key) {
|
|
93
|
-
return this.map.get(key);
|
|
94
|
-
}
|
|
95
|
-
async entries() {
|
|
96
|
-
return this.map.entries();
|
|
97
|
-
}
|
|
98
|
-
async dequeue(key) {
|
|
99
|
-
const value = this.map.get(key);
|
|
100
|
-
this.map.delete(key);
|
|
101
|
-
return value;
|
|
102
|
-
}
|
|
103
|
-
async size() {
|
|
104
|
-
return this.map.size;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
83
|
// ../shared/lib.ts
|
|
109
84
|
function btoh(bytes) {
|
|
110
85
|
const hex = Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
@@ -149,11 +124,330 @@ var LocalStorageStore = class {
|
|
|
149
124
|
async setHostID(id) {
|
|
150
125
|
return localStorage.setItem(hostIDKey, id);
|
|
151
126
|
}
|
|
152
|
-
|
|
153
|
-
|
|
127
|
+
uploadQueue = /* @__PURE__ */ new Map();
|
|
128
|
+
enqueueUpload = async (sha256, cipherOp) => {
|
|
129
|
+
this.uploadQueue.set(sha256, cipherOp);
|
|
130
|
+
};
|
|
131
|
+
dequeueUpload = async (sha256) => {
|
|
132
|
+
this.uploadQueue.delete(sha256);
|
|
133
|
+
};
|
|
134
|
+
peekUpload = async (sha256) => {
|
|
135
|
+
return this.uploadQueue.get(sha256);
|
|
136
|
+
};
|
|
137
|
+
listUploads = async () => {
|
|
138
|
+
return Array.from(this.uploadQueue.keys());
|
|
139
|
+
};
|
|
140
|
+
downloadQueue = /* @__PURE__ */ new Set();
|
|
141
|
+
enqueueDownload = async (path) => {
|
|
142
|
+
this.downloadQueue.add(path);
|
|
143
|
+
};
|
|
144
|
+
dequeueDownload = async (path) => {
|
|
145
|
+
this.downloadQueue.delete(path);
|
|
146
|
+
};
|
|
147
|
+
listDownloads = async () => {
|
|
148
|
+
return Array.from(this.downloadQueue.keys());
|
|
149
|
+
};
|
|
154
150
|
};
|
|
155
151
|
var localStorageStore = new LocalStorageStore();
|
|
156
152
|
|
|
153
|
+
// node_modules/idb/build/index.js
|
|
154
|
+
var instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
|
|
155
|
+
var idbProxyableTypes;
|
|
156
|
+
var cursorAdvanceMethods;
|
|
157
|
+
function getIdbProxyableTypes() {
|
|
158
|
+
return idbProxyableTypes || (idbProxyableTypes = [
|
|
159
|
+
IDBDatabase,
|
|
160
|
+
IDBObjectStore,
|
|
161
|
+
IDBIndex,
|
|
162
|
+
IDBCursor,
|
|
163
|
+
IDBTransaction
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
function getCursorAdvanceMethods() {
|
|
167
|
+
return cursorAdvanceMethods || (cursorAdvanceMethods = [
|
|
168
|
+
IDBCursor.prototype.advance,
|
|
169
|
+
IDBCursor.prototype.continue,
|
|
170
|
+
IDBCursor.prototype.continuePrimaryKey
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
var transactionDoneMap = /* @__PURE__ */ new WeakMap();
|
|
174
|
+
var transformCache = /* @__PURE__ */ new WeakMap();
|
|
175
|
+
var reverseTransformCache = /* @__PURE__ */ new WeakMap();
|
|
176
|
+
function promisifyRequest(request) {
|
|
177
|
+
const promise = new Promise((resolve, reject) => {
|
|
178
|
+
const unlisten = () => {
|
|
179
|
+
request.removeEventListener("success", success);
|
|
180
|
+
request.removeEventListener("error", error);
|
|
181
|
+
};
|
|
182
|
+
const success = () => {
|
|
183
|
+
resolve(wrap(request.result));
|
|
184
|
+
unlisten();
|
|
185
|
+
};
|
|
186
|
+
const error = () => {
|
|
187
|
+
reject(request.error);
|
|
188
|
+
unlisten();
|
|
189
|
+
};
|
|
190
|
+
request.addEventListener("success", success);
|
|
191
|
+
request.addEventListener("error", error);
|
|
192
|
+
});
|
|
193
|
+
reverseTransformCache.set(promise, request);
|
|
194
|
+
return promise;
|
|
195
|
+
}
|
|
196
|
+
function cacheDonePromiseForTransaction(tx) {
|
|
197
|
+
if (transactionDoneMap.has(tx))
|
|
198
|
+
return;
|
|
199
|
+
const done = new Promise((resolve, reject) => {
|
|
200
|
+
const unlisten = () => {
|
|
201
|
+
tx.removeEventListener("complete", complete);
|
|
202
|
+
tx.removeEventListener("error", error);
|
|
203
|
+
tx.removeEventListener("abort", error);
|
|
204
|
+
};
|
|
205
|
+
const complete = () => {
|
|
206
|
+
resolve();
|
|
207
|
+
unlisten();
|
|
208
|
+
};
|
|
209
|
+
const error = () => {
|
|
210
|
+
reject(tx.error || new DOMException("AbortError", "AbortError"));
|
|
211
|
+
unlisten();
|
|
212
|
+
};
|
|
213
|
+
tx.addEventListener("complete", complete);
|
|
214
|
+
tx.addEventListener("error", error);
|
|
215
|
+
tx.addEventListener("abort", error);
|
|
216
|
+
});
|
|
217
|
+
transactionDoneMap.set(tx, done);
|
|
218
|
+
}
|
|
219
|
+
var idbProxyTraps = {
|
|
220
|
+
get(target, prop, receiver) {
|
|
221
|
+
if (target instanceof IDBTransaction) {
|
|
222
|
+
if (prop === "done")
|
|
223
|
+
return transactionDoneMap.get(target);
|
|
224
|
+
if (prop === "store") {
|
|
225
|
+
return receiver.objectStoreNames[1] ? void 0 : receiver.objectStore(receiver.objectStoreNames[0]);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return wrap(target[prop]);
|
|
229
|
+
},
|
|
230
|
+
set(target, prop, value) {
|
|
231
|
+
target[prop] = value;
|
|
232
|
+
return true;
|
|
233
|
+
},
|
|
234
|
+
has(target, prop) {
|
|
235
|
+
if (target instanceof IDBTransaction && (prop === "done" || prop === "store")) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
return prop in target;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
function replaceTraps(callback) {
|
|
242
|
+
idbProxyTraps = callback(idbProxyTraps);
|
|
243
|
+
}
|
|
244
|
+
function wrapFunction(func) {
|
|
245
|
+
if (getCursorAdvanceMethods().includes(func)) {
|
|
246
|
+
return function(...args) {
|
|
247
|
+
func.apply(unwrap(this), args);
|
|
248
|
+
return wrap(this.request);
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return function(...args) {
|
|
252
|
+
return wrap(func.apply(unwrap(this), args));
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function transformCachableValue(value) {
|
|
256
|
+
if (typeof value === "function")
|
|
257
|
+
return wrapFunction(value);
|
|
258
|
+
if (value instanceof IDBTransaction)
|
|
259
|
+
cacheDonePromiseForTransaction(value);
|
|
260
|
+
if (instanceOfAny(value, getIdbProxyableTypes()))
|
|
261
|
+
return new Proxy(value, idbProxyTraps);
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
function wrap(value) {
|
|
265
|
+
if (value instanceof IDBRequest)
|
|
266
|
+
return promisifyRequest(value);
|
|
267
|
+
if (transformCache.has(value))
|
|
268
|
+
return transformCache.get(value);
|
|
269
|
+
const newValue = transformCachableValue(value);
|
|
270
|
+
if (newValue !== value) {
|
|
271
|
+
transformCache.set(value, newValue);
|
|
272
|
+
reverseTransformCache.set(newValue, value);
|
|
273
|
+
}
|
|
274
|
+
return newValue;
|
|
275
|
+
}
|
|
276
|
+
var unwrap = (value) => reverseTransformCache.get(value);
|
|
277
|
+
function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
|
|
278
|
+
const request = indexedDB.open(name, version);
|
|
279
|
+
const openPromise = wrap(request);
|
|
280
|
+
if (upgrade) {
|
|
281
|
+
request.addEventListener("upgradeneeded", (event) => {
|
|
282
|
+
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
if (blocked) {
|
|
286
|
+
request.addEventListener("blocked", (event) => blocked(
|
|
287
|
+
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
288
|
+
event.oldVersion,
|
|
289
|
+
event.newVersion,
|
|
290
|
+
event
|
|
291
|
+
));
|
|
292
|
+
}
|
|
293
|
+
openPromise.then((db) => {
|
|
294
|
+
if (terminated)
|
|
295
|
+
db.addEventListener("close", () => terminated());
|
|
296
|
+
if (blocking) {
|
|
297
|
+
db.addEventListener("versionchange", (event) => blocking(event.oldVersion, event.newVersion, event));
|
|
298
|
+
}
|
|
299
|
+
}).catch(() => {
|
|
300
|
+
});
|
|
301
|
+
return openPromise;
|
|
302
|
+
}
|
|
303
|
+
var readMethods = ["get", "getKey", "getAll", "getAllKeys", "count"];
|
|
304
|
+
var writeMethods = ["put", "add", "delete", "clear"];
|
|
305
|
+
var cachedMethods = /* @__PURE__ */ new Map();
|
|
306
|
+
function getMethod(target, prop) {
|
|
307
|
+
if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === "string")) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (cachedMethods.get(prop))
|
|
311
|
+
return cachedMethods.get(prop);
|
|
312
|
+
const targetFuncName = prop.replace(/FromIndex$/, "");
|
|
313
|
+
const useIndex = prop !== targetFuncName;
|
|
314
|
+
const isWrite = writeMethods.includes(targetFuncName);
|
|
315
|
+
if (
|
|
316
|
+
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
|
|
317
|
+
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))
|
|
318
|
+
) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const method = async function(storeName, ...args) {
|
|
322
|
+
const tx = this.transaction(storeName, isWrite ? "readwrite" : "readonly");
|
|
323
|
+
let target2 = tx.store;
|
|
324
|
+
if (useIndex)
|
|
325
|
+
target2 = target2.index(args.shift());
|
|
326
|
+
return (await Promise.all([
|
|
327
|
+
target2[targetFuncName](...args),
|
|
328
|
+
isWrite && tx.done
|
|
329
|
+
]))[0];
|
|
330
|
+
};
|
|
331
|
+
cachedMethods.set(prop, method);
|
|
332
|
+
return method;
|
|
333
|
+
}
|
|
334
|
+
replaceTraps((oldTraps) => ({
|
|
335
|
+
...oldTraps,
|
|
336
|
+
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
|
337
|
+
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
|
|
338
|
+
}));
|
|
339
|
+
var advanceMethodProps = ["continue", "continuePrimaryKey", "advance"];
|
|
340
|
+
var methodMap = {};
|
|
341
|
+
var advanceResults = /* @__PURE__ */ new WeakMap();
|
|
342
|
+
var ittrProxiedCursorToOriginalProxy = /* @__PURE__ */ new WeakMap();
|
|
343
|
+
var cursorIteratorTraps = {
|
|
344
|
+
get(target, prop) {
|
|
345
|
+
if (!advanceMethodProps.includes(prop))
|
|
346
|
+
return target[prop];
|
|
347
|
+
let cachedFunc = methodMap[prop];
|
|
348
|
+
if (!cachedFunc) {
|
|
349
|
+
cachedFunc = methodMap[prop] = function(...args) {
|
|
350
|
+
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
return cachedFunc;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
async function* iterate(...args) {
|
|
357
|
+
let cursor = this;
|
|
358
|
+
if (!(cursor instanceof IDBCursor)) {
|
|
359
|
+
cursor = await cursor.openCursor(...args);
|
|
360
|
+
}
|
|
361
|
+
if (!cursor)
|
|
362
|
+
return;
|
|
363
|
+
cursor = cursor;
|
|
364
|
+
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
365
|
+
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
366
|
+
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
367
|
+
while (cursor) {
|
|
368
|
+
yield proxiedCursor;
|
|
369
|
+
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
370
|
+
advanceResults.delete(proxiedCursor);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function isIteratorProp(target, prop) {
|
|
374
|
+
return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === "iterate" && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
|
375
|
+
}
|
|
376
|
+
replaceTraps((oldTraps) => ({
|
|
377
|
+
...oldTraps,
|
|
378
|
+
get(target, prop, receiver) {
|
|
379
|
+
if (isIteratorProp(target, prop))
|
|
380
|
+
return iterate;
|
|
381
|
+
return oldTraps.get(target, prop, receiver);
|
|
382
|
+
},
|
|
383
|
+
has(target, prop) {
|
|
384
|
+
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
385
|
+
}
|
|
386
|
+
}));
|
|
387
|
+
|
|
388
|
+
// src/idbStore.ts
|
|
389
|
+
var dbPromise = openDB("client-store-db", 1, {
|
|
390
|
+
upgrade(db) {
|
|
391
|
+
db.createObjectStore("metaKV");
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
var IDBStore = class {
|
|
395
|
+
seed;
|
|
396
|
+
hostURL;
|
|
397
|
+
hostID;
|
|
398
|
+
async getSeed() {
|
|
399
|
+
const hex = await (await dbPromise).get("metaKV", "seed");
|
|
400
|
+
if (!hex) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const bytes = htob(hex);
|
|
404
|
+
return bytes;
|
|
405
|
+
}
|
|
406
|
+
async setSeed(seed) {
|
|
407
|
+
const hex = btoh(seed);
|
|
408
|
+
(await dbPromise).put("metaKV", hex, "seed");
|
|
409
|
+
this.seed = seed;
|
|
410
|
+
}
|
|
411
|
+
async getHostURL() {
|
|
412
|
+
const url = await (await dbPromise).get("metaKV", "hostURL");
|
|
413
|
+
return url;
|
|
414
|
+
}
|
|
415
|
+
async setHostURL(url) {
|
|
416
|
+
(await dbPromise).put("metaKV", url, "hostURL");
|
|
417
|
+
}
|
|
418
|
+
async getHostID() {
|
|
419
|
+
const id = await (await dbPromise).get("metaKV", "hostID");
|
|
420
|
+
return id;
|
|
421
|
+
}
|
|
422
|
+
async setHostID(id) {
|
|
423
|
+
(await dbPromise).put("metaKV", id, "hostID");
|
|
424
|
+
}
|
|
425
|
+
uploadQueue = /* @__PURE__ */ new Map();
|
|
426
|
+
enqueueUpload = async (sha256, cipherOp) => {
|
|
427
|
+
this.uploadQueue.set(sha256, cipherOp);
|
|
428
|
+
};
|
|
429
|
+
dequeueUpload = async (sha256) => {
|
|
430
|
+
this.uploadQueue.delete(sha256);
|
|
431
|
+
};
|
|
432
|
+
peekUpload = async (sha256) => {
|
|
433
|
+
return this.uploadQueue.get(sha256);
|
|
434
|
+
};
|
|
435
|
+
listUploads = async () => {
|
|
436
|
+
return Array.from(this.uploadQueue.keys());
|
|
437
|
+
};
|
|
438
|
+
downloadQueue = /* @__PURE__ */ new Set();
|
|
439
|
+
enqueueDownload = async (path) => {
|
|
440
|
+
this.downloadQueue.add(path);
|
|
441
|
+
};
|
|
442
|
+
dequeueDownload = async (path) => {
|
|
443
|
+
this.downloadQueue.delete(path);
|
|
444
|
+
};
|
|
445
|
+
listDownloads = async () => {
|
|
446
|
+
return Array.from(this.downloadQueue.keys());
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
var idbStore = new IDBStore();
|
|
450
|
+
|
|
157
451
|
// node_modules/@msgpack/msgpack/dist.es5+esm/utils/utf8.mjs
|
|
158
452
|
function utf8Count(str) {
|
|
159
453
|
var strLength = str.length;
|
|
@@ -8556,7 +8850,7 @@ var DiplomaticClient = class {
|
|
|
8556
8850
|
const pathResp = await api_default.getDeltaPaths(hostURL, begin, hostKeyPair);
|
|
8557
8851
|
const paths = pathResp.paths;
|
|
8558
8852
|
for (const path of paths) {
|
|
8559
|
-
await this.store.
|
|
8853
|
+
await this.store.enqueueDownload(path);
|
|
8560
8854
|
}
|
|
8561
8855
|
this.lastFetchedAt = pathResp.fetchedAt;
|
|
8562
8856
|
}
|
|
@@ -8565,17 +8859,19 @@ var DiplomaticClient = class {
|
|
|
8565
8859
|
return [];
|
|
8566
8860
|
}
|
|
8567
8861
|
const { hostURL, hostKeyPair, encKey } = this;
|
|
8568
|
-
|
|
8569
|
-
|
|
8862
|
+
const paths = await this.store.listDownloads();
|
|
8863
|
+
paths.sort((p1, p2) => p2.localeCompare(p1));
|
|
8864
|
+
for (const path of paths) {
|
|
8865
|
+
const cipher = await api_default.getDelta(hostURL, path, hostKeyPair);
|
|
8570
8866
|
const packed = await crypto_default.decryptXSalsa20Poly1305Combined(cipher, encKey);
|
|
8571
8867
|
const op = decode(packed);
|
|
8572
8868
|
try {
|
|
8573
8869
|
await this.applier(op);
|
|
8574
|
-
this.store.
|
|
8870
|
+
await this.store.dequeueDownload(path);
|
|
8575
8871
|
} catch {
|
|
8576
8872
|
const transient = true;
|
|
8577
8873
|
if (!transient) {
|
|
8578
|
-
this.store.
|
|
8874
|
+
await this.store.dequeueDownload(path);
|
|
8579
8875
|
}
|
|
8580
8876
|
}
|
|
8581
8877
|
}
|
|
@@ -8584,14 +8880,14 @@ var DiplomaticClient = class {
|
|
|
8584
8880
|
if (!this.hostURL || !this.hostKeyPair) {
|
|
8585
8881
|
return;
|
|
8586
8882
|
}
|
|
8587
|
-
const cipherOp = await this.store.
|
|
8883
|
+
const cipherOp = await this.store.peekUpload(sha256);
|
|
8588
8884
|
if (cipherOp) {
|
|
8589
8885
|
await api_default.putDelta(this.hostURL, cipherOp, this.hostKeyPair);
|
|
8590
8886
|
}
|
|
8591
|
-
await this.store.
|
|
8887
|
+
await this.store.dequeueUpload(sha256);
|
|
8592
8888
|
}
|
|
8593
8889
|
async pushQueuedOps() {
|
|
8594
|
-
for (const
|
|
8890
|
+
for (const sha256 of await this.store.listUploads()) {
|
|
8595
8891
|
await this.pushQueuedOp(sha256);
|
|
8596
8892
|
}
|
|
8597
8893
|
}
|
|
@@ -8607,11 +8903,11 @@ var DiplomaticClient = class {
|
|
|
8607
8903
|
const cipherOp = await crypto_default.encryptXSalsa20Poly1305Combined(packed, this.encKey);
|
|
8608
8904
|
const sha256 = await crypto_default.sha256Hash(cipherOp);
|
|
8609
8905
|
const shaHex = btoh(sha256);
|
|
8610
|
-
await this.store.
|
|
8906
|
+
await this.store.enqueueUpload(shaHex, cipherOp);
|
|
8611
8907
|
try {
|
|
8612
8908
|
await this.applier(op);
|
|
8613
8909
|
} catch {
|
|
8614
|
-
await this.store.
|
|
8910
|
+
await this.store.dequeueUpload(shaHex);
|
|
8615
8911
|
}
|
|
8616
8912
|
await this.pushQueuedOp(shaHex);
|
|
8617
8913
|
}
|
|
@@ -8626,6 +8922,7 @@ export {
|
|
|
8626
8922
|
Verb,
|
|
8627
8923
|
btoh,
|
|
8628
8924
|
htob,
|
|
8925
|
+
idbStore,
|
|
8629
8926
|
crypto_default as libsodiumCrypto,
|
|
8630
8927
|
localStorageStore,
|
|
8631
8928
|
useClientState,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Queue } from "./queue";
|
|
2
1
|
import type { IClientStateStore } from "./types";
|
|
3
2
|
declare class LocalStorageStore implements IClientStateStore {
|
|
4
3
|
getSeed(): Promise<Uint8Array | undefined>;
|
|
@@ -7,8 +6,15 @@ declare class LocalStorageStore implements IClientStateStore {
|
|
|
7
6
|
setHostURL(url: string): Promise<void>;
|
|
8
7
|
getHostID(): Promise<string | undefined>;
|
|
9
8
|
setHostID(id: string): Promise<void>;
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
uploadQueue: Map<string, Uint8Array>;
|
|
10
|
+
enqueueUpload: (sha256: string, cipherOp: Uint8Array) => Promise<void>;
|
|
11
|
+
dequeueUpload: (sha256: string) => Promise<void>;
|
|
12
|
+
peekUpload: (sha256: string) => Promise<Uint8Array | undefined>;
|
|
13
|
+
listUploads: () => Promise<string[]>;
|
|
14
|
+
downloadQueue: Set<string>;
|
|
15
|
+
enqueueDownload: (path: string) => Promise<void>;
|
|
16
|
+
dequeueDownload: (path: string) => Promise<void>;
|
|
17
|
+
listDownloads: () => Promise<string[]>;
|
|
12
18
|
}
|
|
13
19
|
export declare const localStorageStore: LocalStorageStore;
|
|
14
20
|
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IClientStateStore } from "./types";
|
|
2
|
+
declare class MemoryStore implements IClientStateStore {
|
|
3
|
+
seed?: Uint8Array;
|
|
4
|
+
hostURL?: string;
|
|
5
|
+
hostID?: string;
|
|
6
|
+
getSeed(): Promise<Uint8Array | undefined>;
|
|
7
|
+
setSeed(seed: Uint8Array): Promise<void>;
|
|
8
|
+
getHostURL(): Promise<string | undefined>;
|
|
9
|
+
setHostURL(url: string): Promise<void>;
|
|
10
|
+
getHostID(): Promise<string | undefined>;
|
|
11
|
+
setHostID(id: string): Promise<void>;
|
|
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[]>;
|
|
17
|
+
downloadQueue: Set<string>;
|
|
18
|
+
enqueueDownload: (path: string) => Promise<void>;
|
|
19
|
+
dequeueDownload: (path: string) => Promise<void>;
|
|
20
|
+
listDownloads: () => Promise<string[]>;
|
|
21
|
+
}
|
|
22
|
+
export declare const memoryStore: MemoryStore;
|
|
23
|
+
export {};
|
package/dist/queue.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare class Queue<K, V> implements IQueue<K, V> {
|
|
|
4
4
|
constructor();
|
|
5
5
|
enqueue(key: K, value: V): Promise<void>;
|
|
6
6
|
peek(key: K): Promise<V | undefined>;
|
|
7
|
-
entries(): Promise<
|
|
7
|
+
entries(): Promise<Array<[K, V]>>;
|
|
8
8
|
dequeue(key: K): Promise<V | undefined>;
|
|
9
9
|
size(): Promise<number>;
|
|
10
10
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,34 +1,4 @@
|
|
|
1
1
|
import type { IOp } from "./shared/types";
|
|
2
|
-
export interface IQueue<K, V> {
|
|
3
|
-
/**
|
|
4
|
-
* Adds an entry to the queue.
|
|
5
|
-
* @param key - The key of the entry.
|
|
6
|
-
* @param value - The value of the entry.
|
|
7
|
-
*/
|
|
8
|
-
enqueue(key: K, value: V): Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
* Returns the value of the entry with the specified key without removing it.
|
|
11
|
-
* @param key - The key of the entry.
|
|
12
|
-
* @returns The value of the entry if found, or undefined if the key does not exist.
|
|
13
|
-
*/
|
|
14
|
-
peek(key: K): Promise<V | undefined>;
|
|
15
|
-
/**
|
|
16
|
-
* Returns an iterator for the queue, allowing iteration over all entries.
|
|
17
|
-
* @returns An iterator of entries in the queue.
|
|
18
|
-
*/
|
|
19
|
-
entries(): Promise<Iterable<[K, V]>>;
|
|
20
|
-
/**
|
|
21
|
-
* Removes the entry with the specified key from the queue.
|
|
22
|
-
* @param key - The key of the entry.
|
|
23
|
-
* @returns The value of the removed entry if found, or undefined if the key does not exist.
|
|
24
|
-
*/
|
|
25
|
-
dequeue(key: K): Promise<V | undefined>;
|
|
26
|
-
/**
|
|
27
|
-
* Returns the number of entries in the queue.
|
|
28
|
-
* @returns The size of the queue.
|
|
29
|
-
*/
|
|
30
|
-
size(): Promise<number>;
|
|
31
|
-
}
|
|
32
2
|
export interface IClientStateStore {
|
|
33
3
|
init?: () => Promise<void>;
|
|
34
4
|
getSeed: () => Promise<Uint8Array | undefined>;
|
|
@@ -37,8 +7,13 @@ export interface IClientStateStore {
|
|
|
37
7
|
setHostURL: (url: string) => Promise<void>;
|
|
38
8
|
getHostID: () => Promise<string | undefined>;
|
|
39
9
|
setHostID: (id: string) => Promise<void>;
|
|
40
|
-
|
|
41
|
-
|
|
10
|
+
enqueueUpload: (sha256: string, cipherOp: Uint8Array) => Promise<void>;
|
|
11
|
+
dequeueUpload: (sha256: string) => Promise<void>;
|
|
12
|
+
peekUpload: (sha256: string) => Promise<Uint8Array | undefined>;
|
|
13
|
+
listUploads: () => Promise<string[]>;
|
|
14
|
+
enqueueDownload: (path: string) => Promise<void>;
|
|
15
|
+
dequeueDownload: (path: string) => Promise<void>;
|
|
16
|
+
listDownloads: () => Promise<string[]>;
|
|
42
17
|
}
|
|
43
18
|
export type DiplomaticClientState = "loading" | "seedless" | "hostless" | "ready";
|
|
44
19
|
export type Applier = (op: IOp) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interncom/diplomatic",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Secure sync layer",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
12
|
"tsc": "tsc",
|
|
13
|
-
"build": "node esbuild.mjs"
|
|
13
|
+
"build": "node esbuild.mjs",
|
|
14
|
+
"test": "vitest"
|
|
14
15
|
},
|
|
15
16
|
"author": "The Internet Committee",
|
|
16
17
|
"license": "ISC",
|
|
@@ -19,14 +20,16 @@
|
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"@types/react": "^18.3.3",
|
|
22
|
-
"react": "^18.3.1",
|
|
23
23
|
"esbuild": "0.21.5",
|
|
24
|
-
"
|
|
24
|
+
"react": "^18.3.1",
|
|
25
|
+
"typescript": "^5.5.2",
|
|
26
|
+
"vitest": "^1.6.0"
|
|
25
27
|
},
|
|
26
28
|
"peerDependencies": {
|
|
27
29
|
"react": "^18.3.1"
|
|
28
30
|
},
|
|
29
31
|
"dependencies": {
|
|
30
|
-
"@msgpack/msgpack": "^3.0.0-beta2"
|
|
32
|
+
"@msgpack/msgpack": "^3.0.0-beta2",
|
|
33
|
+
"idb": "^8.0.0"
|
|
31
34
|
}
|
|
32
35
|
}
|