@synapse-sdk/client 0.3.4 → 0.3.7
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 +5 -5
- package/dist/calls.js +19 -21
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/keyserver.d.ts +37 -0
- package/dist/keyserver.js +146 -0
- package/dist/node.d.ts +24 -2
- package/dist/node.js +65 -5
- package/dist/scene.d.ts +22 -11
- package/dist/scene.js +297 -218
- package/dist/session.d.ts +12 -2
- package/dist/session.js +39 -14
- package/dist/store.d.ts +12 -4
- package/dist/store.js +99 -69
- package/dist/synapse.d.ts +29 -7
- package/dist/synapse.js +44 -11
- package/dist/target.d.ts +113 -0
- package/dist/target.js +377 -0
- package/dist/types.d.ts +84 -25
- package/package.json +4 -3
package/dist/types.d.ts
CHANGED
|
@@ -40,7 +40,19 @@ export interface ConnectOptions {
|
|
|
40
40
|
export interface ConnectTarget {
|
|
41
41
|
/**
|
|
42
42
|
* The runtime, `https://host:4470` (the path to dial is learned from the runtime at every attempt). Through a relay: the relay with
|
|
43
|
-
* the runtime's path, `https
|
|
43
|
+
* the runtime's path, `https://<relay>/cluster/<cluster>/runtimes/<runtime_id>`, and `token`. A `jwt=` in the URL is taken as the token.
|
|
44
|
+
*
|
|
45
|
+
* Or, in Bun/Node, a target as the CLI's `-t` names it (anything without `<scheme>://`): `"infra-1@devel"` (runtime `infra-1`
|
|
46
|
+
* of cluster `devel`), `"infra-1"` (in the default cluster), `"arm@medatech/devel"` (an org's cluster, by its slug). The relay
|
|
47
|
+
* URL and the token come from the CLI's files on this machine (`~/.synapse/cluster.toml` and the tokens beside it), read again
|
|
48
|
+
* at every attempt, so a token the CLI refreshed is used on the next reconnect (`token` given here wins). The SDK only reads
|
|
49
|
+
* those files: `synapse login` and `synapse cluster login <cluster>` first. A name this machine does not know is
|
|
50
|
+
* `invalid_input`, a missing or expired token `unauthorized`, each naming the CLI command that fixes it.
|
|
51
|
+
*
|
|
52
|
+
* With a person signed in (`node.setAuth`), in a browser or in Bun/Node, the same names are resolved through the key
|
|
53
|
+
* server instead, from your clusters: `"infra-1@devel"`, `"arm@medatech/devel"` (the cluster is always named). A name
|
|
54
|
+
* not in your clusters is `invalid_input`; nobody signed in, or a sign-in the key server does not take, `unauthorized`.
|
|
55
|
+
* In a browser with nobody signed in, a name is refused at once (`invalid_input`): sign in, or pass the relay URL and a token.
|
|
44
56
|
*/
|
|
45
57
|
url: string;
|
|
46
58
|
/** The type to declare there; left out keeps the node's current one. */
|
|
@@ -51,7 +63,7 @@ export interface ConnectTarget {
|
|
|
51
63
|
userId?: string;
|
|
52
64
|
/** The credential to present there; left out keeps the node's current one. Never printed. */
|
|
53
65
|
credential?: string;
|
|
54
|
-
/** Pin of *this*
|
|
66
|
+
/** Pin of *this* runtime's self-signed certificate (SHA-256 hex). Absent: `SYNAPSE_BROKER_CERT_SHA256`, then, for a runtime URL (no path), its helper; a URL naming a root (a relay) connects unpinned against the system's roots (per attempt). */
|
|
55
67
|
brokerCertSha256?: string;
|
|
56
68
|
/** The relay token for *this* target; left out = no token (a token for another runtime would be refused). Never printed. */
|
|
57
69
|
token?: string;
|
|
@@ -85,6 +97,42 @@ export type ConnectionState = {
|
|
|
85
97
|
status: "failed";
|
|
86
98
|
error: SynapseError;
|
|
87
99
|
};
|
|
100
|
+
/**
|
|
101
|
+
* Gives the signed-in person's credential for the key server, fetched each time the node asks it (`setAuth`);
|
|
102
|
+
* `null` or `undefined` means nobody is signed in.
|
|
103
|
+
*/
|
|
104
|
+
export type FetchToken = () => Promise<string | null | undefined>;
|
|
105
|
+
/** The key server's answer about the signed-in person (`node.discover()`): the relay to dial and your clusters with their runtimes. */
|
|
106
|
+
export interface Discovery {
|
|
107
|
+
/** The relay a runtime of these clusters is dialed through. */
|
|
108
|
+
relay: string;
|
|
109
|
+
/** The signed-in person. */
|
|
110
|
+
userId: string;
|
|
111
|
+
/** Your clusters: your own, and those of the organizations you belong to. */
|
|
112
|
+
clusters: {
|
|
113
|
+
id: string;
|
|
114
|
+
name: string;
|
|
115
|
+
/** Who owns it: `kind` `user` (yours) or `org`, its `id`, and the organization's `slug` when it has one. */
|
|
116
|
+
owner: {
|
|
117
|
+
kind: string;
|
|
118
|
+
id: string;
|
|
119
|
+
slug?: string;
|
|
120
|
+
};
|
|
121
|
+
/** How `connect()` names it: `name` for yours, `<slug>/<name>` (or `<org id>/<name>`) for an organization's: `"infra-1@" + label`. */
|
|
122
|
+
label: string;
|
|
123
|
+
/** Its runtimes, name → runtime id. */
|
|
124
|
+
runtimes: Record<string, string>;
|
|
125
|
+
}[];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* `node.discovery`: `idle` with nobody signed in (or just after `setAuth`), `pending` while the key server is asked,
|
|
129
|
+
* `success` with the answer, `error` with why it failed (`data` still holds the last answer, if there was one).
|
|
130
|
+
*/
|
|
131
|
+
export interface DiscoveryState {
|
|
132
|
+
status: "idle" | "pending" | "success" | "error";
|
|
133
|
+
data?: Discovery;
|
|
134
|
+
error?: SynapseError;
|
|
135
|
+
}
|
|
88
136
|
/** This node's identity and the current session's hello facts; empty strings between sessions. */
|
|
89
137
|
export interface Info {
|
|
90
138
|
name: string;
|
|
@@ -230,27 +278,32 @@ export interface CallOptions<U = unknown> {
|
|
|
230
278
|
/** Local: fail `idle_timeout` (and cancel) when no frame arrives for this long. */
|
|
231
279
|
idleTimeoutMs?: number;
|
|
232
280
|
signal?: AbortSignal;
|
|
281
|
+
/** The callback form: the SDK reads the updates and calls `onUpdate(u)` for each (the run's loop then has none); a throwing `onUpdate` is rethrown later and the reading goes on. */
|
|
233
282
|
onUpdate?: (u: U) => void;
|
|
234
283
|
}
|
|
235
|
-
/**
|
|
236
|
-
|
|
237
|
-
|
|
284
|
+
/**
|
|
285
|
+
* A started call (WP §8.3). Its progress is a stream, the run itself a promise:
|
|
286
|
+
* `for await (const u of run)` the updates until the run ended, `await run.next()` one update
|
|
287
|
+
* (`undefined` once the run ended), or `onUpdate` in the call options (the SDK reads them);
|
|
288
|
+
* `await run` (or `.then`/`.catch`) the result, rejecting with the `SynapseError` of a
|
|
289
|
+
* `failed` or `canceled` run; `cancel()`.
|
|
290
|
+
*/
|
|
291
|
+
export interface Run<U, R> extends AsyncDisposable, PromiseLike<R>, AsyncIterable<U> {
|
|
238
292
|
readonly id: string;
|
|
239
293
|
readonly status: RunStatus;
|
|
240
|
-
/** The next progress update; `undefined` once the
|
|
241
|
-
|
|
242
|
-
|
|
294
|
+
/** The next progress update; `undefined` once the run ended (then `await run` settles at once). */
|
|
295
|
+
next(): Promise<U | undefined>;
|
|
296
|
+
/** `await run` / `.then` as on a promise (returns a `Promise`, so `.then(...).catch(...)` chains). */
|
|
297
|
+
then<A = R, B = never>(onfulfilled?: ((value: R) => A | PromiseLike<A>) | null, onrejected?: ((reason: unknown) => B | PromiseLike<B>) | null): Promise<A | B>;
|
|
298
|
+
/** The result as a plain promise (what `await run` waits for). */
|
|
243
299
|
readonly result: Promise<R>;
|
|
300
|
+
/** `.catch` as on a promise: `onRejected` gets the run's `SynapseError` when it failed or was canceled. */
|
|
301
|
+
catch<B = never>(onRejected?: ((e: unknown) => B | PromiseLike<B>) | null): Promise<R | B>;
|
|
302
|
+
/** `.finally` as on a promise: `onFinally` runs once the run ended, whichever way. */
|
|
303
|
+
finally(onFinally?: (() => void) | null): Promise<R>;
|
|
244
304
|
/** Cooperative cancel: tells the broker, resolves on its `canceled` frame. */
|
|
245
305
|
cancel(reason?: string): Promise<void>;
|
|
246
306
|
}
|
|
247
|
-
export type CallEvent<U, R> = {
|
|
248
|
-
type: "update";
|
|
249
|
-
data: U;
|
|
250
|
-
} | {
|
|
251
|
-
type: "result";
|
|
252
|
-
data: R;
|
|
253
|
-
};
|
|
254
307
|
export interface ServeContext<U> {
|
|
255
308
|
readonly call: string;
|
|
256
309
|
readonly caller: string;
|
|
@@ -332,7 +385,7 @@ export interface StoreHandle extends AsyncDisposable {
|
|
|
332
385
|
readonly synced: boolean;
|
|
333
386
|
/** The handle's own state, a state value: `get()` now (the same object while unchanged), `onChange` for each change, `changed()` for the next. */
|
|
334
387
|
readonly status: StateValue<StoreStatus>;
|
|
335
|
-
/** Resolves once the
|
|
388
|
+
/** Resolves once the value is in: current as of the open (the version the runtime answered then applied), or the namespace absent. */
|
|
336
389
|
ready(): Promise<void>;
|
|
337
390
|
/** `set(key, value)`, or `set({ ... })` for several keys as one atomic write; resolves once `get()` shows it. */
|
|
338
391
|
set(key: string, value: unknown): Promise<void>;
|
|
@@ -343,8 +396,9 @@ export interface StoreHandle extends AsyncDisposable {
|
|
|
343
396
|
destroy(): Promise<void>;
|
|
344
397
|
/** The whole value after each change; with `key`, that key's value each time it changes (`undefined` after a delete). */
|
|
345
398
|
watch(key?: string): AsyncIterable<unknown>;
|
|
346
|
-
/** The whole value after its next change; `store_gone` once this handle is closed. */
|
|
399
|
+
/** The whole value after its next change; with `key`, that key's value after its next change (`undefined` after a delete). `store_gone` once this handle is closed. */
|
|
347
400
|
changed(): Promise<Record<string, unknown>>;
|
|
401
|
+
changed(key: string): Promise<unknown>;
|
|
348
402
|
/** `cb` with the whole value on every change of the value or the status (the framework bridge); returns the remover. */
|
|
349
403
|
onChange(cb: (value: Record<string, unknown>) => void): () => void;
|
|
350
404
|
close(): void;
|
|
@@ -441,7 +495,7 @@ export interface SceneEntity {
|
|
|
441
495
|
kind: SceneKind;
|
|
442
496
|
/**
|
|
443
497
|
* Unique across every plane (authored, calibration, live): a write that would give an entity a name another entity
|
|
444
|
-
* holds is refused `name_taken`, its `data.holder` the id holding the name.
|
|
498
|
+
* holds is refused `name_taken`, its `data.holder` the id holding the name (`data.kind`, `data.layer`: the holder's).
|
|
445
499
|
*/
|
|
446
500
|
name?: string;
|
|
447
501
|
/** The parent's id; `null` is the world root. */
|
|
@@ -550,6 +604,9 @@ export interface SceneEntityView extends SceneView<SceneEntity | undefined> {
|
|
|
550
604
|
*/
|
|
551
605
|
watch(): AsyncIterable<SceneEntity | undefined>;
|
|
552
606
|
watch<K extends keyof SceneEntity & string>(component: K): AsyncIterable<SceneEntity[K] | undefined>;
|
|
607
|
+
/** The entity after its next change; with `component`, that component after its next change (`undefined` once gone). The value now once the handle ends. */
|
|
608
|
+
changed(): Promise<SceneEntity | undefined>;
|
|
609
|
+
changed<K extends keyof SceneEntity & string>(component: K): Promise<SceneEntity[K] | undefined>;
|
|
553
610
|
}
|
|
554
611
|
/** An entity view's authored plane (`view.authored`). Reads as the view does: nothing once the handle is detached or closed. */
|
|
555
612
|
export interface EntityAuthored {
|
|
@@ -743,12 +800,14 @@ export interface SceneAuthored {
|
|
|
743
800
|
patch(entity: string | SceneEntityView, set: Partial<SceneEntity>): Promise<void>;
|
|
744
801
|
/**
|
|
745
802
|
* A builder's one verb, keyed by `name`; resolves with the entity's view (by id: that entity) once the entities show
|
|
746
|
-
* it.
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
751
|
-
*
|
|
803
|
+
* it. The id is the runtime's answer, never the copy's: `spawn(kind, { name, parent, ...components })` (a fresh id) is
|
|
804
|
+
* sent first; the runtime refusing it `name_taken` names the holder and its kind (`data.holder`, `data.kind`,
|
|
805
|
+
* `data.layer`). A holder of this kind in the authored or calibration layer is patched with the components that differ
|
|
806
|
+
* from what the copy shows of it (one-level merge; live overrides never count; all of them when the copy does not show
|
|
807
|
+
* it yet; equal, nothing more is sent): the copy only trims the patch, it never decides. A holder of another kind, a
|
|
808
|
+
* live one, or an answer without them: the `name_taken` as it came. `parent` is used by the spawn only: an existing
|
|
809
|
+
* entity is not reparented. Any other refusal as it came (`not_found` on the patch: the entity went meanwhile; upsert
|
|
810
|
+
* again). An `id` component: `invalid_input` (`data: { component: "id" }`), nothing sent.
|
|
752
811
|
*/
|
|
753
812
|
upsert(kind: SceneKind, opts: SceneSpawnOptions & {
|
|
754
813
|
id?: never;
|
|
@@ -817,7 +876,7 @@ export interface SceneHandle extends AsyncDisposable {
|
|
|
817
876
|
readonly status: StateValue<SceneStatus>;
|
|
818
877
|
/** The one boolean a node author checks: `status.get().synced`. */
|
|
819
878
|
readonly synced: boolean;
|
|
820
|
-
/** Resolves once the handle is attached (at once if it is); `not_connected` once the handle is closed. No timeout: pass an `AbortSignal` to what awaits it, or race it. */
|
|
879
|
+
/** Resolves once the handle is attached (at once if it is): the copy current as of the attach, at the version the runtime answered when the scene was opened, or past it; `not_connected` once the handle is closed. No timeout: pass an `AbortSignal` to what awaits it, or race it. */
|
|
821
880
|
ready(): Promise<void>;
|
|
822
881
|
/** The entities after their next change (state, not history); `not_connected` once the handle is closed. */
|
|
823
882
|
changed(): Promise<Readonly<Record<string, SceneEntity>>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapse-sdk/client",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Synapse SDK client: connect a node to the runtime; topics, services, calls, store, video.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
"dist"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@synapse-sdk/core": "0.3.
|
|
18
|
-
"@moq/net": "0.4.2"
|
|
17
|
+
"@synapse-sdk/core": "0.3.7",
|
|
18
|
+
"@moq/net": "0.4.2",
|
|
19
|
+
"smol-toml": "1.9.0"
|
|
19
20
|
},
|
|
20
21
|
"peerDependencies": {
|
|
21
22
|
"@moq/web-transport": "0.1.5"
|