@synapse-sdk/client 0.3.0 → 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.
package/dist/calls.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type CallId, type ServiceContract } from "@synapse-sdk/core";
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
4
  import type { CallEvent, CallOptions, Run, RunStatus } from "./types.ts";
@@ -33,5 +33,11 @@ export declare class RunImpl<U, R> implements Run<U, R> {
33
33
  * go on the session the attempt is for (`channel.ts`). `connection_lost` once it ended.
34
34
  */
35
35
  export declare function startOn<U, R>(node: Node, session: Session, svc: string, args: unknown, opts: CallOptions<U>, contract?: ServiceContract<unknown, unknown, U, R>): RunImpl<U, R>;
36
+ /**
37
+ * A call that was never sent (no session): a `Run` already `failed` with `error`. Its result is the
38
+ * error; it has no updates; `cancel()` has nothing to do. Like every Run, an unread result is no
39
+ * unhandled rejection.
40
+ */
41
+ export declare function failedRun<U, R>(error: SynapseError): Run<U, R>;
36
42
  /** `callStream`: the updates and the result as one ordered stream; `break` cancels. */
37
43
  export declare function callStream<U, R>(run: Run<U, R>): AsyncGenerator<CallEvent<U, R>, void, undefined>;
package/dist/calls.js CHANGED
@@ -178,6 +178,25 @@ export function startOn(node, session, svc, args, opts, contract) {
178
178
  run.start();
179
179
  return run;
180
180
  }
181
+ /**
182
+ * A call that was never sent (no session): a `Run` already `failed` with `error`. Its result is the
183
+ * error; it has no updates; `cancel()` has nothing to do. Like every Run, an unread result is no
184
+ * unhandled rejection.
185
+ */
186
+ export function failedRun(error) {
187
+ const result = Promise.reject(error);
188
+ result.catch(() => { });
189
+ return {
190
+ id: "",
191
+ status: "failed",
192
+ result,
193
+ then: (onFulfilled, onRejected) => result.then(onFulfilled, onRejected),
194
+ nextUpdate: async () => undefined,
195
+ updates: async function* () { },
196
+ cancel: async () => { },
197
+ [Symbol.asyncDispose]: async () => { },
198
+ };
199
+ }
181
200
  /** `callStream`: the updates and the result as one ordered stream; `break` cancels. */
182
201
  export async function* callStream(run) {
183
202
  try {
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ 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
4
  export { callStream } from "./calls.ts";
5
+ export { isTasksRefusal } from "./tasks.ts";
5
6
  export { setMoqDebug } from "./moq_log.ts";
6
7
  export type * from "./types.ts";
7
8
  export { brokerCertHelperUrl, discoverBrokerCertSha256, ensureWebTransport } from "./session.ts";
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ 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
5
  export { callStream } from "./calls.js";
6
+ export { isTasksRefusal } from "./tasks.js";
6
7
  export { setMoqDebug } from "./moq_log.js";
7
8
  export { brokerCertHelperUrl, discoverBrokerCertSha256, ensureWebTransport } from "./session.js";
8
9
  export { replaceEqualDeep, shallowEqual } from "./util.js";
package/dist/node.d.ts CHANGED
@@ -9,14 +9,16 @@ export declare function fixedPolicy(ms: number): ReconnectPolicy;
9
9
  /** Stops after `maxAttempts` attempts in one phase. */
10
10
  export declare function withMaxAttempts(p: ReconnectPolicy, maxAttempts: number): ReconnectPolicy;
11
11
  export declare const defaultReconnectPolicy: ReconnectPolicy;
12
- /** The node's declared target: bumped `generation` per change; `dial` undefined = deliberately disconnected. */
12
+ /** The node's declared target: bumped `generation` per change; `dial` undefined = no target (the node is `idle`). */
13
13
  export interface Target {
14
14
  generation: number;
15
15
  dial: Dial | undefined;
16
16
  identity: Identity;
17
17
  }
18
- /** The one lifecycle cell: `ConnectionState` with the session on `connected`. State, not history. */
18
+ /** The one lifecycle value (held in a `Cell`): `ConnectionState` with the session on `connected`. State, not history. */
19
19
  export type Link = {
20
+ status: "idle";
21
+ } | {
20
22
  status: "connecting";
21
23
  attempt: number;
22
24
  } | {
@@ -36,6 +38,7 @@ export type Link = {
36
38
  } | {
37
39
  status: "failed";
38
40
  error: SynapseError;
41
+ generation: number;
39
42
  };
40
43
  export declare function stateOf(l: Link): ConnectionState;
41
44
  /** What a handle task is told about the node's session, in its own mailbox, in order with its other events. */
@@ -47,16 +50,20 @@ export type SessionEvent = {
47
50
  } | {
48
51
  kind: "nodeEnded";
49
52
  };
50
- /** Where the loop replies to a `connect`/`setTarget` call waiting for a target generation. */
53
+ /** How long the first pursuit of a declared target (`connect()`) keeps trying a retryable failure before `failed` (SDK §2: a hard bound; the same value in every SDK). */
54
+ export declare const FIRST_CONNECT_GIVE_UP_MS = 30000;
55
+ /** Where the loop replies to a `connect`/`disconnect` call waiting for a target generation. */
51
56
  type Reply = Deferred<void>;
52
- /** Why the loop is dialing. */
57
+ /**
58
+ * Why the loop is dialing: the first pursuit of a declared target (`connect()`), every attempt (its pause included) cut
59
+ * at `deadlineMs` (`boundMs` after the first attempt), or a dropped session (paced by the policy).
60
+ */
53
61
  type Pursuit = {
54
62
  kind: "first";
55
63
  deadlineMs: number;
64
+ boundMs: number;
56
65
  } | {
57
66
  kind: "reconnect";
58
- } | {
59
- kind: "target";
60
67
  };
61
68
  type Stand = {
62
69
  kind: "live";
@@ -76,30 +83,44 @@ type Next = {
76
83
  delayMs: number;
77
84
  } | {
78
85
  kind: "failed";
79
- } | {
80
- kind: "closed";
81
86
  };
82
- /** The rules (SDK §2, WP §10.4) for the delay before attempt `attempt`. */
87
+ /**
88
+ * The rules (SDK §2, WP §10.4) for the delay before attempt `attempt`. `unauthorized` gives up in every pursuit. The first
89
+ * connect retries only retryable errors and only until its deadline (the loop cuts the pause and the attempt at it; the
90
+ * delay is not cut here); with no policy it uses the default. Giving up is `failed` in every pursuit: the node rests
91
+ * until a new target.
92
+ */
83
93
  export declare function decide(pursuit: Pursuit, policy: ReconnectPolicy | null, err: SynapseError, attempt: number, nowMs: number): Next;
84
94
  export declare class Node {
85
95
  #private;
86
96
  readonly link: Cell<Link>;
87
97
  readonly target: Cell<Target>;
88
- readonly dom: TimeDomain;
98
+ /** The node's time domain; final once `prepared` resolved (the loop dials, and publishers describe themselves, only after). */
99
+ dom: TimeDomain;
100
+ /** Resolves once the time domain is final (the host's monotonic clock read, its domain id derived). */
101
+ readonly prepared: Promise<void>;
89
102
  readonly knobs: SessionKnobs;
90
103
  readonly policy: ReconnectPolicy | null;
104
+ /** Bun/Node: close on SIGINT/SIGTERM once a target is declared (not at construction: constructing opens nothing). */
105
+ readonly signals: boolean;
91
106
  /** Broker notices addressed to this node, across its sessions (fed by the loop from the current session's). */
92
107
  readonly notices: Set<(n: ErrorBody) => void>;
93
108
  readonly projectNotices: Set<(n: Notice) => void>;
94
- /** Resolves once the node has ended for good (`close()`, the first connect failing, the policy giving up). */
109
+ /** Resolves once the node has ended for good: `close()`, and nothing else. */
95
110
  readonly ended: Deferred<void>;
96
111
  epochs: number;
97
112
  reconnects: number;
98
113
  callsSent: number;
99
114
  callsAnswered: number;
100
- constructor(target: Target, dom: TimeDomain, knobs: SessionKnobs, policy: ReconnectPolicy | null);
115
+ /** `finalDom`: the time domain once known, when `dom` is only provisional (see `createNode`). */
116
+ constructor(target: Target, dom: TimeDomain, knobs: SessionKnobs, policy: ReconnectPolicy | null, opts?: {
117
+ signals?: boolean;
118
+ finalDom?: Promise<TimeDomain>;
119
+ });
101
120
  get isEnded(): boolean;
102
121
  get isConnected(): boolean;
122
+ /** Whether the node rests `failed` on target `generation` (a `failed` of an older target, not yet replaced by the loop, is not this target's). */
123
+ failedOn(generation: number): boolean;
103
124
  currentSession(): Session | undefined;
104
125
  state(): ConnectionState;
105
126
  /** The loop's one write. A write that names a session or withdraws one tells every monitoring handle, in the same step. */
@@ -115,13 +136,29 @@ export declare class Node {
115
136
  };
116
137
  /** The node ends for good in `link`: handles are told, feeds end. */
117
138
  end(link: Link): void;
118
- /** Builds the freshly opened session completely (its epoch, its tasks running), then names it. */
119
- attach(session: Session): Session;
139
+ /** Builds the freshly opened session completely (its epoch, the target generation it was opened for, its tasks running), then names it. */
140
+ attach(session: Session, generation: number): Session;
120
141
  /** `close()`: posts the command; resolves once the node has ended. */
121
142
  close(): Promise<void>;
122
- /** `setTarget()`: declares the target under the cell's write, posts the command with its reply, and awaits it. */
123
- setTarget(dial: Dial | undefined): Promise<void>;
124
- /** Starts the loop. `first` is the `connect()` call's reply. `signals`: close on SIGINT/SIGTERM (Bun/Node). */
143
+ /**
144
+ * The one path of every target change (`connect()`, `disconnect()`): declares `dial` (`undefined`: no target) under the
145
+ * `target` `Cell`'s write, posts the command with its reply, and awaits it (the loop answers once the target is reached, given up
146
+ * on, applied as none, or superseded by a newer one: quietly). The target already declared declares nothing (except
147
+ * from `failed` on it, where it is dialed again) and settles with the node's state (`settled`); no target again is done at
148
+ * once. `giveUpAfterMs`: the bound of the dial's first pursuit.
149
+ */
150
+ declare(dial: Dial | undefined, giveUpAfterMs?: number): Promise<void>;
151
+ /**
152
+ * Settles with target `generation` by reading the node's state: resolves once connected on a session opened for it (a
153
+ * session of an earlier target still connected does not count) or once a newer target superseded it (quietly, as the
154
+ * loop answers a superseded call); rejects once `failed` on it (its error; a `failed` of an older target keeps it waiting) or ended (`not_connected`).
155
+ */
156
+ settled(generation: number): Promise<void>;
157
+ /** `disconnect()` again while the first is still being acted on: resolves once the node rests `idle` (or a newer target superseded it); `not_connected` once it ended. */
158
+ idle(generation: number): Promise<void>;
159
+ /** Resolves once a session other than `asked` is connected; rejects with the error once the node rests `failed`, `not_connected` once it ended or rests `idle` (disconnected meanwhile: no session will follow). */
160
+ switchedFrom(asked: Session): Promise<void>;
161
+ /** Starts the loop (once the time domain is final). `first` is a `connect()` call's reply. `signals`: close on SIGINT/SIGTERM (Bun/Node). */
125
162
  run(stand: Stand, first: Reply | undefined, signals: boolean): void;
126
163
  }
127
164
  /** Resolves the identity a node declares (`resolve_identity`): a missing name is minted, a `web`/`hmi` node without a `user_id` mints one. */
@@ -133,13 +170,14 @@ export declare function resolveIdentity(o: {
133
170
  }): Identity;
134
171
  /** Resolves a `ConnectTarget` against the node's current identity (fields left out are kept). */
135
172
  export declare function resolveTarget(node: Node, t: ConnectTarget): Dial;
173
+ /** A given broker url that is not a URL is the caller's mistake: `invalid_input`. */
174
+ export declare function checkUrl(url: string): void;
136
175
  /**
137
- * Builds the node and starts its loop in the first pursuit. Resolves as soon as the loop runs, with
138
- * the node (so a `close()` can reach it during the first dial) and `connected`: the loop's reply to
139
- * the first connect, a session established or why there is none (`not_connected` after a `close()`).
176
+ * Builds the node, synchronously, with no target (`idle`), and starts its loop resting; nothing is
177
+ * dialed until `connect()` declares a target. Throws `invalid_input` for options that can never work
178
+ * (a bad name). The time domain is read in the background; the loop starts once it is final.
140
179
  */
141
- export declare function startNode(opts: ConnectOptions, giveUpAfterMs: number): Promise<{
142
- node: Node;
143
- connected: Promise<void>;
144
- }>;
180
+ export declare function createNode(opts: ConnectOptions): Node;
181
+ /** The dial `connect()` with no target declares when none is declared: `SYNAPSE_ENDPOINT` (Bun/Node; unset, or a browser: `invalid_input`) with the node's current identity. */
182
+ export declare function endpointDial(node: Node): Dial;
145
183
  export {};