@interncom/diplomatic 0.3.3 → 0.3.4

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,6 +13,16 @@ import type { IClient, IStore } from "./types";
13
13
  * (built as `worker.mjs` in the published package). It must run as a
14
14
  * **module** worker (`type: "module"`).
15
15
  *
16
+ * ## Handshake (race-safe)
17
+ *
18
+ * The worker posts an unsolicited `{ kind: "ready" }` after init. Apps often
19
+ * construct the Worker at module load (or before `openDiplomaticClient` finishes
20
+ * opening IndexedDB), so that event can fire before the library sets
21
+ * `onmessage`. **That is fine:** connect also probes with a request/response
22
+ * `ping`. The worker holds commands until init completes, so the probe succeeds
23
+ * even if `ready` was dropped. Do **not** reimplement message buffering in the
24
+ * app unless you need it for other reasons.
25
+ *
16
26
  * ## Vite (recommended for SPA templates)
17
27
  *
18
28
  * ```ts
@@ -23,6 +33,7 @@ import type { IClient, IStore } from "./types";
23
33
  *
24
34
  * `?worker` makes Vite emit a real worker asset and a constructor. Create the
25
35
  * instance once (module scope or `useMemo`/`useRef`) — not on every render.
36
+ * Early construction is supported; the handshake recovers if `ready` is missed.
26
37
  *
27
38
  * ## webpack / Rollup / esbuild / Parcel (`new URL` + import.meta.url)
28
39
  *
@@ -19,11 +19,16 @@ type UseClientBase = {
19
19
  * import DiplomaticWorker from "@interncom/diplomatic/worker?worker";
20
20
  * const syncWorker = new DiplomaticWorker();
21
21
  * useClient({ worker: syncWorker, seed, host });
22
+ *
23
+ * Handshake is race-safe (ready event and/or probe ping). See
24
+ * `openDiplomaticClient` for bundler recipes and handshake notes.
22
25
  */
23
26
  export type UseClientWorkerOptions = UseClientBase & {
24
27
  /**
25
28
  * App-constructed sync Worker. Create once (module scope or useMemo/useRef),
26
- * not each render. See `openDiplomaticClient` for instantiation recipes.
29
+ * not each render. Early construction before `useClient` opens IDB is OK —
30
+ * the library does not require catching the unsolicited `ready` event.
31
+ * See `openDiplomaticClient` for instantiation recipes.
27
32
  */
28
33
  worker: Worker;
29
34
  store?: never;
@@ -8,11 +8,19 @@ import type { IClient, IDiplomaticClientState, IDiplomaticClientXferState, IHost
8
8
  *
9
9
  * Provide a live `Worker` — the library never constructs one. See
10
10
  * `openDiplomaticClient` for bundler/CDN instantiation recipes.
11
+ *
12
+ * Handshake is race-safe: the worker posts unsolicited `{ kind: "ready" }`, but
13
+ * connect also probes with `ping`. Early construction (module scope) is fine even
14
+ * if `ready` fired before `onmessage` was set — the ping still succeeds once the
15
+ * worker has finished init (cmds are held until then on the worker side).
11
16
  */
12
17
  export type WorkerClientOptions = {
13
18
  /** Already-constructed module Worker running `@interncom/diplomatic/worker`. */
14
19
  worker: Worker;
15
- /** Max wait for worker `ready` (default 15s). Failures throw; no fallback. */
20
+ /**
21
+ * Max wait for handshake (`ready` event or probe ping; default 15s).
22
+ * Failures throw; no fallback.
23
+ */
16
24
  readyTimeoutMs?: number;
17
25
  clock?: IClock;
18
26
  /**
@@ -48,8 +56,19 @@ export declare class WorkerClient implements IClient<URL> {
48
56
  * Attach to an app-provided Worker. `store` is the shared protocol IDB (main
49
57
  * connection) used for local msg writes; worker opens its own connection.
50
58
  * Throws if the worker never becomes ready — does not fall back to main thread.
59
+ *
60
+ * Handshake: wait for unsolicited `ready` **or** a successful probe `ping`.
61
+ * The probe covers the common case where the app started the Worker early and
62
+ * `ready` was dropped before this thread set `onmessage`.
51
63
  */
52
64
  static connect(state: IStateManager, store: IStore<URL>, opts: WorkerClientOptions): Promise<WorkerClient>;
65
+ /** Resolve the ready barrier (idempotent). */
66
+ private markReady;
67
+ /**
68
+ * Active handshake: post ping without waiting for the ready event.
69
+ * On pong, mark ready so connect can proceed even if `ready` was missed.
70
+ */
71
+ private probeReady;
53
72
  /** Lightweight RPC check after connect. */
54
73
  ping(): Promise<void>;
55
74
  /** Terminate the worker (drops protocol DB connection in that thread). */
@@ -4,8 +4,14 @@ export type PostFn = (msg: WorkerEvent, transfer?: Transferable[]) => void;
4
4
  export declare class WorkerRuntime {
5
5
  private client;
6
6
  private post;
7
+ /** Resolves when init finishes (success or failure). Cmds wait on this. */
8
+ private whenReady;
9
+ private resolveReady;
10
+ private rejectReady;
7
11
  constructor(post: PostFn);
8
12
  init(): Promise<void>;
13
+ private markReady;
14
+ private failReady;
9
15
  private requireClient;
10
16
  private emitClientState;
11
17
  private emitXferState;