@synapse-sdk/client 0.3.4 → 0.3.6

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/calls.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { SynapseError, type CallId, type ServiceContract } from "@synapse-sdk/core";
2
2
  import type { Node } from "./node.ts";
3
3
  import { type RespFrame, type Session } from "./session.ts";
4
- import type { CallEvent, CallOptions, Run, RunStatus } from "./types.ts";
4
+ import type { CallOptions, Run, RunStatus } from "./types.ts";
5
5
  /** A fresh call id (WP §8.2): 16 random bytes. */
6
6
  export declare function newCallId(): CallId;
7
7
  export declare class RunImpl<U, R> implements Run<U, R> {
@@ -17,12 +17,14 @@ export declare class RunImpl<U, R> implements Run<U, R> {
17
17
  get status(): RunStatus;
18
18
  get result(): Promise<R>;
19
19
  then<A = R, B = never>(onFulfilled?: ((v: R) => A | PromiseLike<A>) | null, onRejected?: ((e: unknown) => B | PromiseLike<B>) | null): Promise<A | B>;
20
+ catch<B = never>(onRejected?: ((e: unknown) => B | PromiseLike<B>) | null): Promise<R | B>;
21
+ finally(onFinally?: (() => void) | null): Promise<R>;
20
22
  /** The session's demux hands frames here; `null` = the session ended with the call pending. */
21
23
  deliver(f: RespFrame | null): void;
22
24
  /** Starts the per-frame reader once the request is written (frames can arrive before `writeCall` returns). */
23
25
  start(): void;
24
- nextUpdate(): Promise<U | undefined>;
25
- updates(): AsyncIterable<U>;
26
+ next(): Promise<U | undefined>;
27
+ [Symbol.asyncIterator](): AsyncIterator<U>;
26
28
  /** Cooperative cancel (WP §8.4): tells the broker, then waits for its `canceled` terminal frame. `connection_lost` without sending once the session ended. */
27
29
  cancel(reason?: string): Promise<void>;
28
30
  /** Dropped with the call in flight: the runtime is told (best effort). */
@@ -39,5 +41,3 @@ export declare function startOn<U, R>(node: Node, session: Session, svc: string,
39
41
  * unhandled rejection.
40
42
  */
41
43
  export declare function failedRun<U, R>(error: SynapseError): Run<U, R>;
42
- /** `callStream`: the updates and the result as one ordered stream; `break` cancels. */
43
- export declare function callStream<U, R>(run: Run<U, R>): AsyncGenerator<CallEvent<U, R>, void, undefined>;
package/dist/calls.js CHANGED
@@ -4,7 +4,7 @@
4
4
  // a frame on a later session (WP §8.4: ownership is checked, never inferred).
5
5
  import { FLAGS, SynapseError, TYPES, decode as decodeBody, encode as encodeBody, nowUs, toHex, validateSync } from "@synapse-sdk/core";
6
6
  import { outcomeUnknown } from "./session.js";
7
- import { AsyncQueue, deferred } from "./util.js";
7
+ import { AsyncQueue, deferred, rethrowLater } from "./util.js";
8
8
  /** A fresh call id (WP §8.2): 16 random bytes. */
9
9
  export function newCallId() { const b = new Uint8Array(16); crypto.getRandomValues(b); return b; }
10
10
  export class RunImpl {
@@ -42,6 +42,8 @@ export class RunImpl {
42
42
  get status() { return this.#status; }
43
43
  get result() { return this.#result.promise; }
44
44
  then(onFulfilled, onRejected) { return this.#result.promise.then(onFulfilled, onRejected); }
45
+ catch(onRejected) { return this.then(undefined, onRejected); }
46
+ finally(onFinally) { return this.#result.promise.finally(onFinally); }
45
47
  /** The session's demux hands frames here; `null` = the session ended with the call pending. */
46
48
  deliver(f) { this.#frames.push(f); }
47
49
  /** Starts the per-frame reader once the request is written (frames can arrive before `writeCall` returns). */
@@ -93,11 +95,17 @@ export class RunImpl {
93
95
  continue;
94
96
  u = r.value;
95
97
  }
96
- this.#updates.push(u);
97
- try {
98
- this.opts.onUpdate?.(u);
98
+ // The callback form takes the stream (as `subscribe(topic, cb)`): a throwing `onUpdate` is rethrown later and the reading goes on.
99
+ if (this.opts.onUpdate) {
100
+ try {
101
+ this.opts.onUpdate(u);
102
+ }
103
+ catch (e) {
104
+ rethrowLater(e);
105
+ }
99
106
  }
100
- catch { /* the caller's */ }
107
+ else
108
+ this.#updates.push(u);
101
109
  }
102
110
  }
103
111
  #updates = new AsyncQueue(4096);
@@ -129,8 +137,8 @@ export class RunImpl {
129
137
  this.#result.resolve(r.value);
130
138
  }
131
139
  }
132
- async nextUpdate() { return this.#updates.next(); }
133
- updates() { return this.#updates; }
140
+ next() { return this.#updates.next(); }
141
+ [Symbol.asyncIterator]() { return this.#updates[Symbol.asyncIterator](); }
134
142
  #sendCancel(reason) {
135
143
  if (!this.session.isLive)
136
144
  return;
@@ -191,21 +199,11 @@ export function failedRun(error) {
191
199
  status: "failed",
192
200
  result,
193
201
  then: (onFulfilled, onRejected) => result.then(onFulfilled, onRejected),
194
- nextUpdate: async () => undefined,
195
- updates: async function* () { },
202
+ catch: onRejected => result.catch(onRejected),
203
+ finally: onFinally => result.finally(onFinally),
204
+ next: async () => undefined,
205
+ [Symbol.asyncIterator]: async function* () { },
196
206
  cancel: async () => { },
197
207
  [Symbol.asyncDispose]: async () => { },
198
208
  };
199
209
  }
200
- /** `callStream`: the updates and the result as one ordered stream; `break` cancels. */
201
- export async function* callStream(run) {
202
- try {
203
- for await (const u of run.updates())
204
- yield { type: "update", data: u };
205
- yield { type: "result", data: await run.result };
206
- }
207
- finally {
208
- if (run.status === "pending" || run.status === "running")
209
- run.cancel("caller").catch(() => { });
210
- }
211
- }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  export * from "@synapse-sdk/core";
2
2
  export { Synapse, FIRST_CONNECT_GIVE_UP_MS } from "./synapse.ts";
3
3
  export { defaultReconnectPolicy, exponentialPolicy, fixedPolicy, withMaxAttempts } from "./node.ts";
4
- export { callStream } from "./calls.ts";
5
4
  export { isTasksRefusal } from "./tasks.ts";
6
5
  export { setMoqDebug } from "./moq_log.ts";
7
6
  export type * from "./types.ts";
package/dist/index.js CHANGED
@@ -2,7 +2,6 @@
2
2
  export * from "@synapse-sdk/core";
3
3
  export { Synapse, FIRST_CONNECT_GIVE_UP_MS } from "./synapse.js";
4
4
  export { defaultReconnectPolicy, exponentialPolicy, fixedPolicy, withMaxAttempts } from "./node.js";
5
- export { callStream } from "./calls.js";
6
5
  export { isTasksRefusal } from "./tasks.js";
7
6
  export { setMoqDebug } from "./moq_log.js";
8
7
  export { brokerCertHelperUrl, discoverBrokerCertSha256, ensureWebTransport } from "./session.js";
package/dist/scene.d.ts CHANGED
@@ -132,8 +132,10 @@ export declare class Mirror {
132
132
  epoch: string | undefined;
133
133
  version: number;
134
134
  hash: string;
135
- /** An authored diff skipped a version; cleared by the next snapshot. */
136
- gap: boolean;
135
+ /** An authored diff skipped a version (not applied; the track is read again from its snapshot): the highest version seen then. Cleared once the copy is back at it (PLAN v0.34 §2.2). */
136
+ gap: number | undefined;
137
+ /** The live track's first keyframe of the incarnation is in the copy. */
138
+ liveKeyed: boolean;
137
139
  pending: number;
138
140
  authored: Entities;
139
141
  live: LiveTable;
@@ -146,12 +148,16 @@ export declare class Mirror {
146
148
  dropHandle(id: number): void;
147
149
  /** The hierarchy now (recomputed only after a change of the ids, a parent or an order; the same object while equal). */
148
150
  tree(): SceneTree;
149
- /** A snapshot of incarnation `epoch` replaces the authored copy. Not yet `attached`: the reader catches up first (`attach`). */
151
+ /** A snapshot of incarnation `epoch` replaces the authored copy. The first one is not yet `attached`: that is the task's, once the copy is at the version the open answered. */
150
152
  applySnapshot(epoch: string, s: Snapshot): void;
151
- /** The reader has applied everything this node held when it bound the incarnation. */
153
+ /** The copy is current as of the attach (the task checked it): `attached`. */
152
154
  attach(): void;
153
- /** One applied batch: its ops folded into the authored copy. */
154
- applyDiff(d: Diff, warn: Warn): void;
155
+ /**
156
+ * One applied batch: its ops folded into the authored copy, when it is the next version. Otherwise it is not applied
157
+ * (`false`): a gap, `synced` false until the copy is back at the version seen; the reader reads the track again from
158
+ * its snapshot (PLAN v0.34 §2.2).
159
+ */
160
+ applyDiff(d: Diff, warn: Warn): boolean;
155
161
  /** A keyframe replaces the live table. */
156
162
  applyKeyframe(k: LiveFrame): void;
157
163
  /** One tick folded into the live table; its removals go to the feeds. */
@@ -177,18 +183,22 @@ type Event = {
177
183
  } | {
178
184
  kind: "nodeEnded";
179
185
  }
186
+ /** The answer of `synapse/scene/open` of attempt `attempt`. */
187
+ | {
188
+ kind: "opened";
189
+ attempt: number;
190
+ result: Result<unknown>;
191
+ }
180
192
  /** The reader applied an authored frame of incarnation `epoch`: the mirror is at `version`. */
181
193
  | {
182
194
  kind: "applied";
183
195
  epoch: string;
184
196
  version: number;
185
197
  }
186
- /** Reading `attempt` caught up with incarnation `epoch` at `version`: the task binds the claims, then attaches the handle. */
198
+ /** The reader applied the live track's first keyframe of incarnation `epoch`. */
187
199
  | {
188
- kind: "attach";
189
- attempt: number;
200
+ kind: "liveKeyed";
190
201
  epoch: string;
191
- version: number;
192
202
  }
193
203
  /** The reader of attempt `attempt` ended: the incarnation it bound and its final frame's reason (none: the tracks or the session went). */
194
204
  | {
@@ -385,7 +395,8 @@ export declare class SceneHandleImpl implements SceneHandle {
385
395
  }
386
396
  /**
387
397
  * The active project's scene (one per project; one task per node, shared by every handle). Resolves
388
- * once the handle is attached, or at once `detached` when the runtime says no project is active; the
398
+ * once the handle is attached (the copy at the version `synapse/scene/open` answered, or past it), or at
399
+ * once `detached` when the runtime says no project is active; the
389
400
  * handle then follows the incarnations as they come and go. Without a session (before the first, between
390
401
  * two) the task waits for the next one, like after a drop.
391
402
  */