@interncom/diplomatic 0.0.8 → 0.0.10
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 +4 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +76 -55
- package/dist/localStorageStore.d.ts +3 -8
- package/dist/queue.d.ts +10 -0
- package/dist/types.d.ts +32 -6
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -26,11 +26,12 @@ export default class DiplomaticClient {
|
|
|
26
26
|
loadHost(): Promise<void>;
|
|
27
27
|
register(hostURL: string): Promise<void>;
|
|
28
28
|
get state(): DiplomaticClientState;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
processOps(): Promise<void>;
|
|
30
|
+
pullOpPaths(): Promise<never[] | undefined>;
|
|
31
|
+
fetchAndExecQueuedOps(): Promise<never[] | undefined>;
|
|
32
32
|
private pushQueuedOp;
|
|
33
33
|
pushQueuedOps(): Promise<void>;
|
|
34
|
+
sync(): Promise<void>;
|
|
34
35
|
apply(op: IOp): Promise<void>;
|
|
35
36
|
upsert<T>(type: string, body: T, version?: number): Promise<void>;
|
|
36
37
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ import { localStorageStore } from "./localStorageStore";
|
|
|
4
4
|
import DiplomaticClient from "./client";
|
|
5
5
|
import libsodiumCrypto from "./crypto";
|
|
6
6
|
import { btoh, htob } from "./shared/lib";
|
|
7
|
-
import type
|
|
8
|
-
export { useClientState, StateManager, useStateWatcher, localStorageStore, DiplomaticClient, libsodiumCrypto, btoh, htob, };
|
|
9
|
-
export type { IOp,
|
|
7
|
+
import { type IOp, Verb } from "./shared/types";
|
|
8
|
+
export { useClientState, StateManager, useStateWatcher, localStorageStore, DiplomaticClient, libsodiumCrypto, btoh, htob, Verb, };
|
|
9
|
+
export type { IOp, };
|
package/dist/index.mjs
CHANGED
|
@@ -80,6 +80,31 @@ 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
|
+
|
|
83
108
|
// ../shared/lib.ts
|
|
84
109
|
function btoh(bytes) {
|
|
85
110
|
const hex = Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
@@ -124,29 +149,8 @@ var LocalStorageStore = class {
|
|
|
124
149
|
async setHostID(id) {
|
|
125
150
|
return localStorage.setItem(hostIDKey, id);
|
|
126
151
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const hex = btoh(sha256);
|
|
130
|
-
this.uploadQueue.set(hex, cipherOp);
|
|
131
|
-
};
|
|
132
|
-
dequeueUpload = async (sha256) => {
|
|
133
|
-
const hex = btoh(sha256);
|
|
134
|
-
this.uploadQueue.delete(hex);
|
|
135
|
-
};
|
|
136
|
-
peekUpload = async (sha256) => {
|
|
137
|
-
const hex = btoh(sha256);
|
|
138
|
-
return this.uploadQueue.get(hex);
|
|
139
|
-
};
|
|
140
|
-
async listUploadQueue() {
|
|
141
|
-
return Array.from(this.uploadQueue.keys());
|
|
142
|
-
}
|
|
143
|
-
downloadQueue = /* @__PURE__ */ new Set();
|
|
144
|
-
enqueueDownload = async (path) => {
|
|
145
|
-
this.downloadQueue.add(path);
|
|
146
|
-
};
|
|
147
|
-
dequeueDownload = async (path) => {
|
|
148
|
-
this.downloadQueue.delete(path);
|
|
149
|
-
};
|
|
152
|
+
pushQueue = new Queue();
|
|
153
|
+
pullQueue = new Queue();
|
|
150
154
|
};
|
|
151
155
|
var localStorageStore = new LocalStorageStore();
|
|
152
156
|
|
|
@@ -8409,6 +8413,13 @@ var msgpack = {
|
|
|
8409
8413
|
var webClientAPI = new DiplomaticClientAPI(msgpack, crypto_default);
|
|
8410
8414
|
var api_default = webClientAPI;
|
|
8411
8415
|
|
|
8416
|
+
// ../shared/types.ts
|
|
8417
|
+
var Verb = /* @__PURE__ */ ((Verb2) => {
|
|
8418
|
+
Verb2[Verb2["DELETE"] = 0] = "DELETE";
|
|
8419
|
+
Verb2[Verb2["UPSERT"] = 1] = "UPSERT";
|
|
8420
|
+
return Verb2;
|
|
8421
|
+
})(Verb || {});
|
|
8422
|
+
|
|
8412
8423
|
// ../shared/ops.ts
|
|
8413
8424
|
function genUpsertOp(type, body, version = 0) {
|
|
8414
8425
|
return {
|
|
@@ -8433,7 +8444,6 @@ var DiplomaticClient = class {
|
|
|
8433
8444
|
constructor(params) {
|
|
8434
8445
|
this.store = params.store;
|
|
8435
8446
|
this.applier = params.stateManager.apply;
|
|
8436
|
-
console.log("constructing");
|
|
8437
8447
|
this.init(params);
|
|
8438
8448
|
}
|
|
8439
8449
|
websocket;
|
|
@@ -8459,7 +8469,7 @@ var DiplomaticClient = class {
|
|
|
8459
8469
|
};
|
|
8460
8470
|
this.websocket.onmessage = (e) => {
|
|
8461
8471
|
console.log(`RECEIVED: ${e.data}`);
|
|
8462
|
-
this.
|
|
8472
|
+
this.processOps();
|
|
8463
8473
|
};
|
|
8464
8474
|
this.websocket.onerror = (e) => {
|
|
8465
8475
|
console.log(`ERROR: ${e}`);
|
|
@@ -8483,7 +8493,7 @@ var DiplomaticClient = class {
|
|
|
8483
8493
|
if (this.hostURL) {
|
|
8484
8494
|
await this.connect(this.hostURL);
|
|
8485
8495
|
}
|
|
8486
|
-
await this.
|
|
8496
|
+
await this.sync();
|
|
8487
8497
|
this.listener?.(this.state);
|
|
8488
8498
|
}
|
|
8489
8499
|
async loadSeed() {
|
|
@@ -8533,53 +8543,62 @@ var DiplomaticClient = class {
|
|
|
8533
8543
|
}
|
|
8534
8544
|
return "ready";
|
|
8535
8545
|
}
|
|
8536
|
-
async
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
}
|
|
8540
|
-
const packed = encode(delta);
|
|
8541
|
-
const cipherOp = await crypto_default.encryptXSalsa20Poly1305Combined(packed, this.encKey);
|
|
8542
|
-
await api_default.putDelta(this.hostURL, cipherOp, this.hostKeyPair);
|
|
8546
|
+
async processOps() {
|
|
8547
|
+
await this.pullOpPaths();
|
|
8548
|
+
await this.fetchAndExecQueuedOps();
|
|
8543
8549
|
}
|
|
8544
|
-
async
|
|
8550
|
+
async pullOpPaths() {
|
|
8545
8551
|
if (!this.hostURL || !this.hostKeyPair || !this.encKey) {
|
|
8546
8552
|
return [];
|
|
8547
8553
|
}
|
|
8548
8554
|
const begin = new Date(this.lastFetchedAt ?? 0);
|
|
8549
|
-
const { hostURL, hostKeyPair
|
|
8555
|
+
const { hostURL, hostKeyPair } = this;
|
|
8550
8556
|
const pathResp = await api_default.getDeltaPaths(hostURL, begin, hostKeyPair);
|
|
8551
8557
|
const paths = pathResp.paths;
|
|
8558
|
+
for (const path of paths) {
|
|
8559
|
+
await this.store.pullQueue.enqueue(path, null);
|
|
8560
|
+
}
|
|
8552
8561
|
this.lastFetchedAt = pathResp.fetchedAt;
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
}
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8562
|
+
}
|
|
8563
|
+
async fetchAndExecQueuedOps() {
|
|
8564
|
+
if (!this.hostURL || !this.hostKeyPair || !this.encKey) {
|
|
8565
|
+
return [];
|
|
8566
|
+
}
|
|
8567
|
+
const { hostURL, hostKeyPair, encKey } = this;
|
|
8568
|
+
for (const [path] of await this.store.pullQueue.entries()) {
|
|
8569
|
+
const cipher = await api_default.getDelta(this.hostURL, path, hostKeyPair);
|
|
8570
|
+
const packed = await crypto_default.decryptXSalsa20Poly1305Combined(cipher, encKey);
|
|
8571
|
+
const op = decode(packed);
|
|
8572
|
+
try {
|
|
8573
|
+
await this.applier(op);
|
|
8574
|
+
this.store.pullQueue.dequeue(path);
|
|
8575
|
+
} catch {
|
|
8576
|
+
const transient = true;
|
|
8577
|
+
if (!transient) {
|
|
8578
|
+
this.store.pullQueue.dequeue(path);
|
|
8579
|
+
}
|
|
8580
|
+
}
|
|
8565
8581
|
}
|
|
8566
8582
|
}
|
|
8567
8583
|
async pushQueuedOp(sha256) {
|
|
8568
8584
|
if (!this.hostURL || !this.hostKeyPair) {
|
|
8569
8585
|
return;
|
|
8570
8586
|
}
|
|
8571
|
-
const cipherOp = await this.store.
|
|
8587
|
+
const cipherOp = await this.store.pushQueue.peek(sha256);
|
|
8572
8588
|
if (cipherOp) {
|
|
8573
8589
|
await api_default.putDelta(this.hostURL, cipherOp, this.hostKeyPair);
|
|
8574
8590
|
}
|
|
8575
|
-
await this.store.
|
|
8591
|
+
await this.store.pushQueue.dequeue(sha256);
|
|
8576
8592
|
}
|
|
8577
8593
|
async pushQueuedOps() {
|
|
8578
|
-
for (const sha256 of await this.store.
|
|
8579
|
-
|
|
8580
|
-
await this.pushQueuedOp(bytes);
|
|
8594
|
+
for (const [sha256] of await this.store.pushQueue.entries()) {
|
|
8595
|
+
await this.pushQueuedOp(sha256);
|
|
8581
8596
|
}
|
|
8582
8597
|
}
|
|
8598
|
+
async sync() {
|
|
8599
|
+
await this.processOps();
|
|
8600
|
+
await this.pushQueuedOps();
|
|
8601
|
+
}
|
|
8583
8602
|
async apply(op) {
|
|
8584
8603
|
if (!this.encKey) {
|
|
8585
8604
|
throw "No encryption key";
|
|
@@ -8587,13 +8606,14 @@ var DiplomaticClient = class {
|
|
|
8587
8606
|
const packed = encode(op);
|
|
8588
8607
|
const cipherOp = await crypto_default.encryptXSalsa20Poly1305Combined(packed, this.encKey);
|
|
8589
8608
|
const sha256 = await crypto_default.sha256Hash(cipherOp);
|
|
8590
|
-
|
|
8609
|
+
const shaHex = btoh(sha256);
|
|
8610
|
+
await this.store.pushQueue.enqueue(shaHex, cipherOp);
|
|
8591
8611
|
try {
|
|
8592
8612
|
await this.applier(op);
|
|
8593
8613
|
} catch {
|
|
8594
|
-
await this.store.
|
|
8614
|
+
await this.store.pushQueue.dequeue(shaHex);
|
|
8595
8615
|
}
|
|
8596
|
-
await this.pushQueuedOp(
|
|
8616
|
+
await this.pushQueuedOp(shaHex);
|
|
8597
8617
|
}
|
|
8598
8618
|
async upsert(type, body, version = 0) {
|
|
8599
8619
|
const op = genUpsertOp(type, body, version);
|
|
@@ -8603,6 +8623,7 @@ var DiplomaticClient = class {
|
|
|
8603
8623
|
export {
|
|
8604
8624
|
DiplomaticClient,
|
|
8605
8625
|
StateManager,
|
|
8626
|
+
Verb,
|
|
8606
8627
|
btoh,
|
|
8607
8628
|
htob,
|
|
8608
8629
|
crypto_default as libsodiumCrypto,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Queue } from "./queue";
|
|
1
2
|
import type { IClientStateStore } from "./types";
|
|
2
3
|
declare class LocalStorageStore implements IClientStateStore {
|
|
3
4
|
getSeed(): Promise<Uint8Array | undefined>;
|
|
@@ -6,14 +7,8 @@ declare class LocalStorageStore implements IClientStateStore {
|
|
|
6
7
|
setHostURL(url: string): Promise<void>;
|
|
7
8
|
getHostID(): Promise<string | undefined>;
|
|
8
9
|
setHostID(id: string): Promise<void>;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
dequeueUpload: (sha256: Uint8Array) => Promise<void>;
|
|
12
|
-
peekUpload: (sha256: Uint8Array) => Promise<Uint8Array | undefined>;
|
|
13
|
-
listUploadQueue(): Promise<string[]>;
|
|
14
|
-
downloadQueue: Set<string>;
|
|
15
|
-
enqueueDownload: (path: string) => Promise<void>;
|
|
16
|
-
dequeueDownload: (path: string) => Promise<void>;
|
|
10
|
+
pushQueue: Queue<string, Uint8Array>;
|
|
11
|
+
pullQueue: Queue<string, null>;
|
|
17
12
|
}
|
|
18
13
|
export declare const localStorageStore: LocalStorageStore;
|
|
19
14
|
export {};
|
package/dist/queue.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IQueue } from "./types";
|
|
2
|
+
export declare class Queue<K, V> implements IQueue<K, V> {
|
|
3
|
+
private map;
|
|
4
|
+
constructor();
|
|
5
|
+
enqueue(key: K, value: V): Promise<void>;
|
|
6
|
+
peek(key: K): Promise<V | undefined>;
|
|
7
|
+
entries(): Promise<Iterable<[K, V]>>;
|
|
8
|
+
dequeue(key: K): Promise<V | undefined>;
|
|
9
|
+
size(): Promise<number>;
|
|
10
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
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
|
+
}
|
|
2
32
|
export interface IClientStateStore {
|
|
3
33
|
init?: () => Promise<void>;
|
|
4
34
|
getSeed: () => Promise<Uint8Array | undefined>;
|
|
@@ -7,12 +37,8 @@ export interface IClientStateStore {
|
|
|
7
37
|
setHostURL: (url: string) => Promise<void>;
|
|
8
38
|
getHostID: () => Promise<string | undefined>;
|
|
9
39
|
setHostID: (id: string) => Promise<void>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
peekUpload: (sha256: Uint8Array) => Promise<Uint8Array | undefined>;
|
|
13
|
-
listUploadQueue: () => Promise<string[]>;
|
|
14
|
-
enqueueDownload: (path: string) => Promise<void>;
|
|
15
|
-
dequeueDownload: (path: string) => Promise<void>;
|
|
40
|
+
pushQueue: IQueue<string, Uint8Array>;
|
|
41
|
+
pullQueue: IQueue<string, null>;
|
|
16
42
|
}
|
|
17
43
|
export type DiplomaticClientState = "loading" | "seedless" | "hostless" | "ready";
|
|
18
44
|
export type Applier = (op: IOp) => Promise<void>;
|