@interncom/diplomatic 0.5.0 → 0.6.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/cli/index.mjs +2 -2
- package/dist/cli/shared/singleton.d.ts +2 -1
- package/dist/cli/shared/types.d.ts +30 -3
- package/dist/web/client.d.ts +40 -6
- package/dist/web/entdb/cached.d.ts +52 -0
- package/dist/web/entdb/entdb.d.ts +15 -7
- package/dist/web/entdb/idb.d.ts +2 -0
- package/dist/web/entdb/manager.d.ts +8 -0
- package/dist/web/entdb/memory.d.ts +1 -0
- package/dist/web/index.d.ts +6 -5
- package/dist/web/index.mjs +1 -1
- package/dist/web/shared/singleton.d.ts +2 -1
- package/dist/web/shared/types.d.ts +30 -3
- package/dist/web/state.d.ts +24 -5
- package/dist/web/types.d.ts +8 -4
- package/dist/web/worker/client.d.ts +25 -5
- package/dist/web/worker/protocol.d.ts +5 -38
- package/dist/web/worker.mjs +1 -1
- package/package.json +1 -1
|
@@ -39,11 +39,32 @@ export type IOp = IDeleteOp | IMutateOp;
|
|
|
39
39
|
export declare function isDeleteOp(op: IOp): op is IDeleteOp;
|
|
40
40
|
export declare function isMutateOp(op: IOp): op is IMutateOp;
|
|
41
41
|
export interface IInsertParams<T> extends IMsgEntBody<T> {
|
|
42
|
+
/** Optional 8-byte id material for the new eid; else random. */
|
|
42
43
|
id?: Uint8Array;
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Revision of an ent used as the base for update/delete.
|
|
47
|
+
* Apps almost always already hold this (the row being edited).
|
|
48
|
+
*/
|
|
49
|
+
export interface IEntRev {
|
|
50
|
+
eid: EntityID;
|
|
51
|
+
ctr: number;
|
|
52
|
+
/** Last-write time of this rev (eid.ts + off of the latest msg for this eid). */
|
|
53
|
+
updatedAt: Date;
|
|
54
|
+
}
|
|
55
|
+
export interface IUpdateParams<T> extends IMsgEntBody<T> {
|
|
56
|
+
prior: IEntRev;
|
|
57
|
+
/** Clock-skew recovery; default client-wide (usually true). */
|
|
58
|
+
force?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Prefer `{ prior }`; `{ eid }` loads prior from the message archive. */
|
|
61
|
+
export type IDeleteParams = {
|
|
62
|
+
prior: IEntRev;
|
|
63
|
+
force?: boolean;
|
|
64
|
+
} | {
|
|
65
|
+
eid: EntityID;
|
|
66
|
+
force?: boolean;
|
|
67
|
+
};
|
|
47
68
|
export interface IStorage {
|
|
48
69
|
addUser: (pubKey: PublicKey) => Promise<ValStat<void>>;
|
|
49
70
|
hasUser: (pubKey: PublicKey) => Promise<ValStat<boolean>>;
|
|
@@ -172,6 +193,12 @@ export interface IStateManager {
|
|
|
172
193
|
* updated shared application state in IndexedDB).
|
|
173
194
|
*/
|
|
174
195
|
notify: (types: Iterable<string>) => void;
|
|
196
|
+
/**
|
|
197
|
+
* Peer wrote durable application state for these eids (e.g. sync worker).
|
|
198
|
+
* With CachedEntDB: pull those eids from durable; type-level UI notifies
|
|
199
|
+
* fire only if mem changed.
|
|
200
|
+
*/
|
|
201
|
+
refresh: (eids: Iterable<EntityID>) => Promise<void>;
|
|
175
202
|
on: (type: string, listener: () => void) => void;
|
|
176
203
|
off: (type: string, listener: () => void) => void;
|
|
177
204
|
}
|
package/dist/web/state.d.ts
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
1
|
import { Status } from "./shared/consts";
|
|
2
|
-
import { IMessage, IMsgEntBody, IOp, IStateManager } from "./shared/types";
|
|
2
|
+
import { EntityID, IMessage, IMsgEntBody, IOp, IStateManager } from "./shared/types";
|
|
3
3
|
import { ValStat } from "./shared/valstat";
|
|
4
4
|
import type { Applier } from "./types";
|
|
5
5
|
export declare function isMsgEntBody(bodDec: unknown): bodDec is IMsgEntBody;
|
|
6
6
|
export declare function msgToOp(msg: IMessage): ValStat<IOp>;
|
|
7
|
+
type PeerIngestFn = (eids: Iterable<EntityID>) => Promise<void>;
|
|
7
8
|
export declare class StateManager implements IStateManager {
|
|
8
9
|
applier: Applier;
|
|
9
10
|
private emitter;
|
|
10
11
|
private clearer;
|
|
11
|
-
|
|
12
|
+
/** Worker / peer: eids successfully applied to durable EntDB. */
|
|
13
|
+
private onDirtyEids;
|
|
14
|
+
/**
|
|
15
|
+
* When set (CachedEntDB), type events are driven by the cache's subscribe
|
|
16
|
+
* path (immediate + durable ingest). apply() does not re-emit.
|
|
17
|
+
*/
|
|
18
|
+
private cacheDriven;
|
|
19
|
+
private peerIngest;
|
|
12
20
|
constructor(applier: Applier, clearer: () => Promise<Status>,
|
|
13
|
-
/**
|
|
14
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Called with eids that successfully applied (e.g. worker posts dirty).
|
|
23
|
+
*/
|
|
24
|
+
onDirtyEids?: (eids: EntityID[]) => void, opts?: {
|
|
25
|
+
cacheDriven?: boolean;
|
|
26
|
+
peerIngest?: PeerIngestFn;
|
|
27
|
+
});
|
|
15
28
|
apply: (msgs: IMessage[]) => Promise<Status[]>;
|
|
16
29
|
/** Clear application state and notify all type subscribers. */
|
|
17
30
|
clear: () => Promise<Status>;
|
|
18
|
-
/** Notify type subscribers without applying msgs
|
|
31
|
+
/** Notify type subscribers without applying msgs. */
|
|
19
32
|
notify: (types: Iterable<string>) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Peer (e.g. sync worker) updated durable EntDB for these eids.
|
|
35
|
+
* Cache pulls those rows; apps still hear type-level events via subscribe.
|
|
36
|
+
*/
|
|
37
|
+
refresh: (eids: Iterable<EntityID>) => Promise<void>;
|
|
20
38
|
on: (opType: string, listener: () => void) => void;
|
|
21
39
|
off: (opType: string, listener: () => void) => void;
|
|
22
40
|
}
|
|
23
41
|
export declare const nullStateManager: IStateManager;
|
|
42
|
+
export {};
|
package/dist/web/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { SyncProgressEvent } from "./progress";
|
|
|
2
2
|
import { Status } from "./shared/consts";
|
|
3
3
|
import type { Enclave } from "./shared/enclave";
|
|
4
4
|
import type { EncodedMessage } from "./shared/message";
|
|
5
|
-
import type { EntityID, Hash, HostHandle, IHostConnectionInfo, IHostMetadata, IInsertParams, IMessageHead, IOp,
|
|
5
|
+
import type { EntityID, Hash, HostHandle, IDeleteParams, IEntRev, IHostConnectionInfo, IHostMetadata, IInsertParams, IMessageHead, IOp, IUpdateParams, MasterSeed, SerializedContent } from "./shared/types";
|
|
6
6
|
import { ValStat } from "./shared/valstat";
|
|
7
7
|
import { ICrypto } from "./shared/types";
|
|
8
8
|
export interface IMsgParts {
|
|
@@ -27,6 +27,7 @@ export interface IDiplomaticClientXferState {
|
|
|
27
27
|
export type Applier = (ops: IOp[]) => Promise<{
|
|
28
28
|
stats: Status[];
|
|
29
29
|
types: Set<string>;
|
|
30
|
+
eids: EntityID[];
|
|
30
31
|
}>;
|
|
31
32
|
export interface ISeedStore {
|
|
32
33
|
save: (seed: MasterSeed) => Promise<Enclave>;
|
|
@@ -191,10 +192,13 @@ export interface IClient<Handle extends HostHandle> {
|
|
|
191
192
|
connect(): Promise<void>;
|
|
192
193
|
disconnect(): Promise<void>;
|
|
193
194
|
insertRaw(content: SerializedContent): Promise<ValStat<IMessageHead>>;
|
|
194
|
-
|
|
195
|
+
updateRaw(prior: IEntRev, content: SerializedContent | undefined, force?: boolean): Promise<ValStat<IMessageHead>>;
|
|
195
196
|
insert<T = unknown>(op: IInsertParams<T>): Promise<ValStat<IMessageHead>>;
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
update<T = unknown>(op: IUpdateParams<T>): Promise<ValStat<IMessageHead>>;
|
|
198
|
+
/**
|
|
199
|
+
* Delete by `{ prior }` (preferred) or `{ eid }` (archive lookup).
|
|
200
|
+
*/
|
|
201
|
+
delete(op: IDeleteParams): Promise<ValStat<IMessageHead>>;
|
|
198
202
|
/** Allocate an entity id (optional 8-byte id material; else random). */
|
|
199
203
|
genEID(id?: Uint8Array): Promise<ValStat<EntityID>>;
|
|
200
204
|
sync(): Promise<Status>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IClock } from "../shared/clock";
|
|
2
2
|
import { Status } from "../shared/consts";
|
|
3
|
-
import type { EntityID, IHostConnectionInfo, IInsertParams, IMessageHead, IStateManager,
|
|
3
|
+
import type { EntityID, IDeleteParams, IEntRev, IHostConnectionInfo, IInsertParams, IMessageHead, IStateManager, IUpdateParams, MasterSeed, SerializedContent } from "../shared/types";
|
|
4
4
|
import type { ValStat } from "../shared/valstat";
|
|
5
5
|
import type { IClient, IDiplomaticClientState, IDiplomaticClientXferState, IHostRow, IStateEmitter, IStore } from "../types";
|
|
6
6
|
/**
|
|
@@ -13,6 +13,11 @@ import type { IClient, IDiplomaticClientState, IDiplomaticClientXferState, IHost
|
|
|
13
13
|
* connect also probes with `ping`. Early construction (module scope) is fine even
|
|
14
14
|
* if `ready` fired before `onmessage` was set — the ping still succeeds once the
|
|
15
15
|
* worker has finished init (cmds are held until then on the worker side).
|
|
16
|
+
*
|
|
17
|
+
* After the ready barrier, connect hydrates `clientState` / `xferState` from the
|
|
18
|
+
* shared main-thread store (and recovers via getClientState/getXferState if the
|
|
19
|
+
* unsolicited events were dropped). Without that, the façade defaults to
|
|
20
|
+
* `hasSeed: false` and apps flash the unauthenticated UI until a later event.
|
|
16
21
|
*/
|
|
17
22
|
export type WorkerClientOptions = {
|
|
18
23
|
/** Already-constructed module Worker running `@interncom/diplomatic/worker`. */
|
|
@@ -60,8 +65,23 @@ export declare class WorkerClient implements IClient<URL> {
|
|
|
60
65
|
* Handshake: wait for unsolicited `ready` **or** a successful probe `ping`.
|
|
61
66
|
* The probe covers the common case where the app started the Worker early and
|
|
62
67
|
* `ready` was dropped before this thread set `onmessage`.
|
|
68
|
+
*
|
|
69
|
+
* Then hydrate client/xfer state from the shared store (and RPC) so
|
|
70
|
+
* `clientState.get()` is correct before connect returns — unsolicited
|
|
71
|
+
* `clientState` events are often lost when the Worker starts before
|
|
72
|
+
* `onmessage` is attached.
|
|
63
73
|
*/
|
|
64
74
|
static connect(state: IStateManager, store: IStore<URL>, opts: WorkerClientOptions): Promise<WorkerClient>;
|
|
75
|
+
/**
|
|
76
|
+
* Snapshot seed/host/queues from the shared main-thread store.
|
|
77
|
+
* `connected` stays false until the worker reports otherwise.
|
|
78
|
+
*/
|
|
79
|
+
private hydrateStateFromStore;
|
|
80
|
+
/**
|
|
81
|
+
* Request current client/xfer state from the worker. Recovers when unsolicited
|
|
82
|
+
* `clientState` / `xferState` events fired before `onmessage` was set.
|
|
83
|
+
*/
|
|
84
|
+
private pullRemoteState;
|
|
65
85
|
/** Resolve the ready barrier (idempotent). */
|
|
66
86
|
private markReady;
|
|
67
87
|
/**
|
|
@@ -85,12 +105,12 @@ export declare class WorkerClient implements IClient<URL> {
|
|
|
85
105
|
hosts(): Promise<IHostRow<URL>[]>;
|
|
86
106
|
connect(listen?: boolean, sync?: boolean): Promise<void>;
|
|
87
107
|
disconnect(): Promise<void>;
|
|
88
|
-
/** Local UI write: archive + apply on main (
|
|
108
|
+
/** Local UI write: archive + apply on main (cache notifies UI); sync via worker. */
|
|
89
109
|
insertRaw(content: SerializedContent): Promise<ValStat<IMessageHead>>;
|
|
90
|
-
|
|
110
|
+
updateRaw(prior: IEntRev, content: SerializedContent | undefined, force?: boolean): Promise<ValStat<IMessageHead>>;
|
|
91
111
|
insert<T = unknown>(op: IInsertParams<T>): Promise<ValStat<IMessageHead>>;
|
|
92
|
-
|
|
93
|
-
delete(
|
|
112
|
+
update<T = unknown>(op: IUpdateParams<T>): Promise<ValStat<IMessageHead>>;
|
|
113
|
+
delete(op: IDeleteParams): Promise<ValStat<IMessageHead>>;
|
|
94
114
|
genEID(id?: Uint8Array): Promise<ValStat<EntityID>>;
|
|
95
115
|
sync(): Promise<Status>;
|
|
96
116
|
wipe(): Promise<void>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Status } from "../shared/consts";
|
|
2
|
-
import type { IMessageHead } from "../shared/types";
|
|
3
2
|
import type { SyncProgressEvent } from "../progress";
|
|
4
3
|
import type { IDiplomaticClientState, IDiplomaticClientXferState } from "../types";
|
|
5
4
|
/** Host identity as plain data (URL → string for structured clone). */
|
|
@@ -38,40 +37,6 @@ export type WorkerCmd = {
|
|
|
38
37
|
} | {
|
|
39
38
|
id: number;
|
|
40
39
|
op: "wipe";
|
|
41
|
-
} | {
|
|
42
|
-
id: number;
|
|
43
|
-
op: "insertRaw";
|
|
44
|
-
body: Uint8Array;
|
|
45
|
-
} | {
|
|
46
|
-
id: number;
|
|
47
|
-
op: "upsertRaw";
|
|
48
|
-
eid: Uint8Array;
|
|
49
|
-
body?: Uint8Array;
|
|
50
|
-
force?: boolean;
|
|
51
|
-
} | {
|
|
52
|
-
id: number;
|
|
53
|
-
op: "insert";
|
|
54
|
-
params: {
|
|
55
|
-
type: string;
|
|
56
|
-
body: unknown;
|
|
57
|
-
gid?: string;
|
|
58
|
-
pid?: Uint8Array;
|
|
59
|
-
};
|
|
60
|
-
} | {
|
|
61
|
-
id: number;
|
|
62
|
-
op: "upsert";
|
|
63
|
-
params: {
|
|
64
|
-
type: string;
|
|
65
|
-
body: unknown;
|
|
66
|
-
eid?: Uint8Array;
|
|
67
|
-
gid?: string;
|
|
68
|
-
pid?: Uint8Array;
|
|
69
|
-
};
|
|
70
|
-
force?: boolean;
|
|
71
|
-
} | {
|
|
72
|
-
id: number;
|
|
73
|
-
op: "delete";
|
|
74
|
-
eid: Uint8Array;
|
|
75
40
|
} | {
|
|
76
41
|
id: number;
|
|
77
42
|
op: "import";
|
|
@@ -108,17 +73,19 @@ export type WorkerEvent = {
|
|
|
108
73
|
kind: "xferState";
|
|
109
74
|
state: IDiplomaticClientXferState;
|
|
110
75
|
}
|
|
111
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Application state (e.g. EntDB) changed for these eids.
|
|
78
|
+
* Main cache pulls only those rows from shared IDB, then notifies by type.
|
|
79
|
+
*/
|
|
112
80
|
| {
|
|
113
81
|
kind: "dirty";
|
|
114
|
-
|
|
82
|
+
eids: Uint8Array[];
|
|
115
83
|
} | {
|
|
116
84
|
kind: "wiped";
|
|
117
85
|
} | WorkerReply;
|
|
118
86
|
export declare function isWorkerEvent(data: unknown): data is WorkerEvent;
|
|
119
87
|
export declare function isWorkerCmd(data: unknown): data is WorkerCmd;
|
|
120
88
|
/** Narrow helpers for typed replies (avoid casts at call sites). */
|
|
121
|
-
export declare function headFromUnknown(v: unknown): IMessageHead | undefined;
|
|
122
89
|
export declare function statusFromUnknown(v: unknown): Status | undefined;
|
|
123
90
|
export declare function clientStateFromUnknown(v: unknown): IDiplomaticClientState | undefined;
|
|
124
91
|
export declare function progressFromUnknown(v: unknown): SyncProgressEvent | undefined;
|