@synapse-sdk/client 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.
- package/dist/calls.d.ts +7 -1
- package/dist/calls.js +19 -0
- package/dist/node.d.ts +62 -24
- package/dist/node.js +205 -66
- package/dist/scene.d.ts +150 -56
- package/dist/scene.js +995 -163
- package/dist/scene_frames.d.ts +2 -2
- package/dist/scene_frames.js +1 -1
- package/dist/session.d.ts +3 -1
- package/dist/session.js +4 -2
- package/dist/store.d.ts +22 -11
- package/dist/store.js +112 -26
- package/dist/synapse.d.ts +72 -45
- package/dist/synapse.js +179 -112
- package/dist/tasks.d.ts +1 -1
- package/dist/tasks.js +24 -10
- package/dist/topics.d.ts +2 -0
- package/dist/topics.js +17 -1
- package/dist/types.d.ts +268 -97
- package/dist/util.d.ts +43 -0
- package/dist/util.js +97 -1
- package/dist/view.d.ts +5 -3
- package/dist/view.js +21 -10
- package/package.json +2 -2
package/dist/scene.d.ts
CHANGED
|
@@ -3,13 +3,15 @@ import { SynapseError, type ErrorBody, type ProjectSnapshot } from "@synapse-sdk
|
|
|
3
3
|
import type { Node } from "./node.ts";
|
|
4
4
|
import { StreamWriter, type Session } from "./session.ts";
|
|
5
5
|
import type { Warn } from "./topics.ts";
|
|
6
|
-
import type {
|
|
7
|
-
import { AsyncQueue, type Deferred } from "./util.ts";
|
|
6
|
+
import type { LiveJoints, LivePose, LiveRemoved, LiveState, Quat, SceneAuthored, SceneDiffOp, SceneEntity, SceneEntityLive, SceneEntityRef, SceneEntityView, SceneHandle, SceneKind, SceneLive, SceneOp, ScenePlace, SceneSpawnOptions, SceneState, SceneStatus, SceneTree, SceneTxn, SceneView, Vec3 } from "./types.ts";
|
|
7
|
+
import { AsyncQueue, type Deferred, type StateValue } from "./util.ts";
|
|
8
8
|
/** How many batches a feed may fall behind before it is ended (the store's `STORE_FEED_CAP`). */
|
|
9
9
|
export declare const SCENE_FEED_CAP = 256;
|
|
10
10
|
/** Keys a `patch` may not set (the runtime refuses them); a txn never folds such a patch into a spawn. */
|
|
11
11
|
export declare const PATCH_PROTECTED: readonly string[];
|
|
12
12
|
type Entities = Map<string, SceneEntity>;
|
|
13
|
+
/** An entity named by its id or by a view of it (the id the view names now). */
|
|
14
|
+
type EntityArg = string | SceneEntityView;
|
|
13
15
|
/**
|
|
14
16
|
* A fresh entity id: a ULID (26 Crockford base-32 characters) made from a UUIDv7 (48-bit ms, version,
|
|
15
17
|
* 74 random bits, variant), so ids sort by the time they were minted; within one millisecond the
|
|
@@ -37,19 +39,19 @@ export declare function treeOf(entities: Readonly<Record<string, SceneEntity>>):
|
|
|
37
39
|
export declare class Txn implements SceneTxn {
|
|
38
40
|
#private;
|
|
39
41
|
get ops(): readonly SceneOp[];
|
|
40
|
-
/** Spawns an entity of `kind` under `opts.parent` (default the world root) with the components given (`layer` `authored` when not given); its id is minted here (or `opts.id`, a known one) and returned. No `order` is sent: the runtime appends it after its siblings. */
|
|
41
|
-
spawn(kind:
|
|
42
|
-
/** Sets components of
|
|
43
|
-
patch(
|
|
44
|
-
rename(
|
|
45
|
-
/** Moves
|
|
46
|
-
reparent(
|
|
47
|
-
/** Despawns
|
|
48
|
-
despawn(
|
|
42
|
+
/** Spawns an entity of `kind` under `opts.parent` (default the world root) with the components given (`layer` `authored` when not given, else `calibration`; a live entity is not spawned here, it comes from `scene.live.upsert`); its id is minted here (or `opts.id`, a known one) and returned. No `order` is sent: the runtime appends it after its siblings. */
|
|
43
|
+
spawn(kind: SceneKind, opts: SceneSpawnOptions): string;
|
|
44
|
+
/** Sets components of the entity (one level deep: an object merges into an object). */
|
|
45
|
+
patch(entity: EntityArg, set: Partial<SceneEntity>): void;
|
|
46
|
+
rename(entity: EntityArg, name: string): void;
|
|
47
|
+
/** Moves the entity under `parent` (`null`: the world root), before or after a sibling (default: after the last). */
|
|
48
|
+
reparent(entity: EntityArg, parent: EntityArg | null, place?: ScenePlace): void;
|
|
49
|
+
/** Despawns the entity (`cascade`: with its subtree). One spawned in this batch is cancelled instead, unless it has children spawned in the batch and `cascade` is off (then the runtime decides). */
|
|
50
|
+
despawn(entity: EntityArg, opts?: {
|
|
49
51
|
cascade?: boolean;
|
|
50
52
|
}): void;
|
|
51
|
-
/** Locks or unlocks
|
|
52
|
-
setLocked(
|
|
53
|
+
/** Locks or unlocks the entity (a flags-only patch, which a lock lets through). */
|
|
54
|
+
setLocked(entity: EntityArg, locked: boolean): void;
|
|
53
55
|
}
|
|
54
56
|
/**
|
|
55
57
|
* Applies one diff op of a batch the runtime stamped `t` by `by` to the authored entities (the
|
|
@@ -57,8 +59,6 @@ export declare class Txn implements SceneTxn {
|
|
|
57
59
|
* `meta` is `{rev, t, by}`, as the runtime stamped it.
|
|
58
60
|
*/
|
|
59
61
|
export declare function foldAuthored(authored: Entities, op: SceneDiffOp, t: number, by: string | null): string[];
|
|
60
|
-
/** What changed from `old` to `next`, in the diff ops' shapes (a snapshot replacing the mirror, the mirror emptying): a spawn per new entity, a despawn per gone one, and per changed one a reparent (parent or order), a rename (name) and a patch of the other keys that differ. */
|
|
61
|
-
export declare function netDifference(old: Entities, next: Entities): SceneDiffOp[];
|
|
62
62
|
/** One live row as this node keeps it: the whole live entity of an upsert (absent: an override of an authored entity), the lanes, and the newest lane stamp (the runtime's clock). */
|
|
63
63
|
export interface LiveRow {
|
|
64
64
|
entity?: SceneEntity;
|
|
@@ -85,6 +85,10 @@ export interface LiveFrame {
|
|
|
85
85
|
}
|
|
86
86
|
/** A keyframe as a fresh live table. */
|
|
87
87
|
export declare function liveTableOf(k: LiveFrame): LiveTable;
|
|
88
|
+
/** The authored or calibration entity named `name` (live overrides never count). */
|
|
89
|
+
export declare function authoredNamed(authored: Entities, name: string): SceneEntity | undefined;
|
|
90
|
+
/** The id of the live entity named `name` (a lane-only row carries no name). */
|
|
91
|
+
export declare function liveNamed(live: LiveTable, name: string): string | undefined;
|
|
88
92
|
/** One tick folded into `table` with the runtime's rules (an upsert replaces the whole row, a lane replaces its lane, a remove drops the row); returns the ids it touched. */
|
|
89
93
|
export declare function foldLive(table: LiveTable, d: LiveFrame): string[];
|
|
90
94
|
/** The merged read of one entity: the pose lane replaces `xform.t`/`xform.q` (the rest of the xform stays), the joints lane replaces `joints`, the state lane replaces `state`; nothing merges deeper. */
|
|
@@ -93,9 +97,8 @@ export declare function overlay(entity: SceneEntity, row: LiveRow): SceneEntity;
|
|
|
93
97
|
export declare function liveValue(row: LiveRow): SceneEntityLive;
|
|
94
98
|
/** `id` as the entities show it: its live row over its authored entity, or a live entity's own row. */
|
|
95
99
|
export declare function mergedOf(authored: Entities, live: LiveTable, id: string): SceneEntity | undefined;
|
|
96
|
-
type FeedKind = "
|
|
100
|
+
type FeedKind = "removals" | "denied" | "states";
|
|
97
101
|
interface FeedItems {
|
|
98
|
-
changes: SceneDiffOp[];
|
|
99
102
|
removals: LiveRemoved[];
|
|
100
103
|
denied: string[];
|
|
101
104
|
states: SceneState;
|
|
@@ -143,11 +146,11 @@ export declare class Mirror {
|
|
|
143
146
|
dropHandle(id: number): void;
|
|
144
147
|
/** The hierarchy now (recomputed only after a change of the ids, a parent or an order; the same object while equal). */
|
|
145
148
|
tree(): SceneTree;
|
|
146
|
-
/** A snapshot of incarnation `epoch` replaces the authored copy
|
|
149
|
+
/** A snapshot of incarnation `epoch` replaces the authored copy. Not yet `attached`: the reader catches up first (`attach`). */
|
|
147
150
|
applySnapshot(epoch: string, s: Snapshot): void;
|
|
148
151
|
/** The reader has applied everything this node held when it bound the incarnation. */
|
|
149
152
|
attach(): void;
|
|
150
|
-
/** One applied batch: its ops folded into the authored copy
|
|
153
|
+
/** One applied batch: its ops folded into the authored copy. */
|
|
151
154
|
applyDiff(d: Diff, warn: Warn): void;
|
|
152
155
|
/** A keyframe replaces the live table. */
|
|
153
156
|
applyKeyframe(k: LiveFrame): void;
|
|
@@ -156,7 +159,7 @@ export declare class Mirror {
|
|
|
156
159
|
/** Ids of this node's live rows the runtime dropped. */
|
|
157
160
|
denied(ids: string[]): void;
|
|
158
161
|
setPending(n: number): void;
|
|
159
|
-
/** No incarnation: the copy empties
|
|
162
|
+
/** No incarnation: the copy empties, `detached`. */
|
|
160
163
|
detach(): void;
|
|
161
164
|
/** The end: emptied, `closed` (`reason` recorded), every feed ended. */
|
|
162
165
|
close(reason: string): void;
|
|
@@ -180,6 +183,13 @@ type Event = {
|
|
|
180
183
|
epoch: string;
|
|
181
184
|
version: number;
|
|
182
185
|
}
|
|
186
|
+
/** Reading `attempt` caught up with incarnation `epoch` at `version`: the task binds the claims, then attaches the handle. */
|
|
187
|
+
| {
|
|
188
|
+
kind: "attach";
|
|
189
|
+
attempt: number;
|
|
190
|
+
epoch: string;
|
|
191
|
+
version: number;
|
|
192
|
+
}
|
|
183
193
|
/** The reader of attempt `attempt` ended: the incarnation it bound and its final frame's reason (none: the tracks or the session went). */
|
|
184
194
|
| {
|
|
185
195
|
kind: "followEnded";
|
|
@@ -210,9 +220,47 @@ type Event = {
|
|
|
210
220
|
} | {
|
|
211
221
|
kind: "paced";
|
|
212
222
|
attempt: number;
|
|
223
|
+
}
|
|
224
|
+
/** `live.upsert`: a live entity's claim (its args, no id); answered with the id the runtime decided. */
|
|
225
|
+
| {
|
|
226
|
+
kind: "upsert";
|
|
227
|
+
args: Record<string, unknown>;
|
|
228
|
+
reply: Deferred<string>;
|
|
229
|
+
}
|
|
230
|
+
/** `live.remove`. */
|
|
231
|
+
| {
|
|
232
|
+
kind: "remove";
|
|
233
|
+
id: string;
|
|
234
|
+
reply: Deferred<void>;
|
|
235
|
+
}
|
|
236
|
+
/** A lane write asked the claim of `id` (marked asked by the handle). */
|
|
237
|
+
| {
|
|
238
|
+
kind: "claim";
|
|
239
|
+
id: string;
|
|
240
|
+
}
|
|
241
|
+
/** The runtime's answer to a claim asked in attach `bind`. */
|
|
242
|
+
| {
|
|
243
|
+
kind: "claimDone";
|
|
244
|
+
ask: Ask;
|
|
245
|
+
bind: number;
|
|
246
|
+
result: Result<unknown>;
|
|
247
|
+
}
|
|
248
|
+
/** A refused live entity may be due to be asked again. */
|
|
249
|
+
| {
|
|
250
|
+
kind: "reclaim";
|
|
213
251
|
} | {
|
|
214
252
|
kind: "close";
|
|
215
253
|
};
|
|
254
|
+
/** A claim being asked: a `live.upsert` (its args, its caller), or one of this node's claims asked again. */
|
|
255
|
+
type Ask = {
|
|
256
|
+
kind: "first";
|
|
257
|
+
args: Record<string, unknown>;
|
|
258
|
+
reply: Deferred<string>;
|
|
259
|
+
token: number;
|
|
260
|
+
} | {
|
|
261
|
+
kind: "again";
|
|
262
|
+
id: string;
|
|
263
|
+
};
|
|
216
264
|
/** This node's live writer: the session's `<prefix>/scene/live` broadcast and its track `live`. */
|
|
217
265
|
interface LiveWriter {
|
|
218
266
|
session: Session;
|
|
@@ -220,6 +268,51 @@ interface LiveWriter {
|
|
|
220
268
|
stream: StreamWriter;
|
|
221
269
|
seq: number;
|
|
222
270
|
}
|
|
271
|
+
/** Where one of this node's claims stands in the bound incarnation. */
|
|
272
|
+
type ClaimState =
|
|
273
|
+
/** Not claimed in the bound incarnation (none bound, or not asked yet). */
|
|
274
|
+
{
|
|
275
|
+
kind: "unclaimed";
|
|
276
|
+
}
|
|
277
|
+
/** Asked (or about to be, by the task): lane rows are parked until the answer. */
|
|
278
|
+
| {
|
|
279
|
+
kind: "asking";
|
|
280
|
+
}
|
|
281
|
+
/** The runtime granted it in the bound incarnation: lane rows go out. */
|
|
282
|
+
| {
|
|
283
|
+
kind: "claimed";
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Asked again from `at` (`performance.now()` ms) on. `refused`: the runtime refused it (rows are dropped until then; a
|
|
287
|
+
* live entity is asked by the task's timer, an override by its next lane write once due); not refused: a transient
|
|
288
|
+
* answer (rows keep parking; the task's timer asks it).
|
|
289
|
+
*/
|
|
290
|
+
| {
|
|
291
|
+
kind: "paced";
|
|
292
|
+
at: number;
|
|
293
|
+
refused: boolean;
|
|
294
|
+
};
|
|
295
|
+
/** The latest lane rows of one id written while its claim is not answered yet: one slot per lane, latest wins (state, not history), sent once the claim is granted, dropped on a refusal. */
|
|
296
|
+
interface Parked {
|
|
297
|
+
pose?: LivePose;
|
|
298
|
+
joints?: LiveJoints;
|
|
299
|
+
state?: LiveState;
|
|
300
|
+
lifetimeMs?: number;
|
|
301
|
+
}
|
|
302
|
+
/** One of this node's claims: its own intent, never world state. */
|
|
303
|
+
declare class Claim {
|
|
304
|
+
readonly args: Record<string, unknown>;
|
|
305
|
+
state: ClaimState;
|
|
306
|
+
/** Refusals of it in a row (the pace of the next ask). */
|
|
307
|
+
refusals: number;
|
|
308
|
+
parked: Parked;
|
|
309
|
+
/** `args`: the `upsert` call's args besides `id` (a live entity's `kind`, `name`, `parent`, `lifetime_ms` and components); empty for the override of an entity of the scene. */
|
|
310
|
+
constructor(args: Record<string, unknown>, state: ClaimState);
|
|
311
|
+
/** A live entity (claimed again on every attach), not an override (claimed by its lanes). */
|
|
312
|
+
get isEntity(): boolean;
|
|
313
|
+
}
|
|
314
|
+
/** What the lane gate does with a row: sent now (claimed), parked (the claim is not answered yet), dropped and counted (refused, not due again). */
|
|
315
|
+
type Gate = "send" | "park" | "drop";
|
|
223
316
|
/** The node's scene: what every handle shares with the task. */
|
|
224
317
|
export declare class Scene {
|
|
225
318
|
readonly node: Node;
|
|
@@ -230,11 +323,24 @@ export declare class Scene {
|
|
|
230
323
|
/** Handles neither closed nor dropped; the one that brings it to 0 tells the task `close`. */
|
|
231
324
|
handles: number;
|
|
232
325
|
nextHandle: number;
|
|
233
|
-
/** The live writer of the current session, made on the first
|
|
326
|
+
/** The live writer of the current session, made on the first live write. */
|
|
234
327
|
writer: LiveWriter | undefined;
|
|
328
|
+
/** This node's claims by id (what `live.upsert` made and what lane writes asked for); `live.remove` drops one. Nothing else is kept. */
|
|
329
|
+
readonly claims: Map<string, Claim>;
|
|
235
330
|
detachedDrops: number;
|
|
331
|
+
/** Lane rows dropped because their id's claim was refused (and not due again), or parked rows a refusal dropped. */
|
|
332
|
+
unclaimedDrops: number;
|
|
333
|
+
/** Told when a counter of the status changes (the listeners of the status state values). */
|
|
334
|
+
readonly counters: Set<() => void>;
|
|
236
335
|
constructor(node: Node, warn: Warn);
|
|
237
336
|
post(e: Event): boolean;
|
|
337
|
+
countersChanged(): void;
|
|
338
|
+
/**
|
|
339
|
+
* What happens to a lane row of `id` now. An id with no claim becomes the override's claim; an override that is
|
|
340
|
+
* unclaimed, or refused and due again, is marked asked and returned in `ask` (the task asks it: one ask per id at a
|
|
341
|
+
* time). A live entity's claim is asked by the task (on attach, paced after a refusal), never by a lane.
|
|
342
|
+
*/
|
|
343
|
+
gate(id: string, now: number, ask: string[]): Gate;
|
|
238
344
|
request<T>(make: (reply: Deferred<T>) => Event): Promise<T>;
|
|
239
345
|
}
|
|
240
346
|
/** The node's one scene task, if any (set with the task, cleared by the task when it exits). */
|
|
@@ -246,54 +352,42 @@ export declare function startScene(scene: Scene, registry: SceneRegistry): void;
|
|
|
246
352
|
export declare class SceneHandleImpl implements SceneHandle {
|
|
247
353
|
#private;
|
|
248
354
|
private readonly scene;
|
|
355
|
+
/** The authored plane's verbs. */
|
|
356
|
+
readonly authored: SceneAuthored;
|
|
357
|
+
/** This node's live writes. */
|
|
358
|
+
readonly live: SceneLive;
|
|
359
|
+
/** The handle's own state, a state value: `get()` (the same object while unchanged), `onChange`, `changed()`, `watch()`. */
|
|
360
|
+
readonly status: StateValue<SceneStatus>;
|
|
249
361
|
constructor(scene: Scene);
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
entity(id: string, opts: {
|
|
255
|
-
plane: "live";
|
|
256
|
-
}): SceneView<SceneEntityLive | undefined>;
|
|
257
|
-
entity(id: string, opts?: {
|
|
258
|
-
plane?: "authored" | "live";
|
|
259
|
-
}): SceneView<SceneEntity | SceneEntityLive | undefined>;
|
|
362
|
+
/** The merged entities now; a closed handle reads nothing (the mirror may live on for the node's other handles). */
|
|
363
|
+
get(): Readonly<Record<string, SceneEntity>>;
|
|
364
|
+
/** One entity as a view: the merged entity, with its authored value (`authored`) and its live row (`live`). */
|
|
365
|
+
entity(ref: SceneEntityRef): SceneEntityView;
|
|
260
366
|
tree(): SceneView<SceneTree>;
|
|
261
367
|
query(where: (e: SceneEntity) => boolean): SceneView<SceneEntity[]>;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
368
|
+
/** The one boolean a node author checks: `status.get().synced`. */
|
|
369
|
+
get synced(): boolean;
|
|
370
|
+
/** Resolves once the handle is attached (at once if it is); `not_connected` once it is closed (`close()`, or the node ending). */
|
|
371
|
+
ready(): Promise<void>;
|
|
372
|
+
/** The entities after their next change (state, not history); `not_connected` once this handle is closed. */
|
|
373
|
+
changed(): Promise<Readonly<Record<string, SceneEntity>>>;
|
|
374
|
+
/** The entities after each change; ends with the handle. */
|
|
375
|
+
watch(): AsyncIterable<Readonly<Record<string, SceneEntity>>>;
|
|
265
376
|
watchLiveRemovals(cb: (batch: LiveRemoved[]) => void): () => void;
|
|
266
377
|
watchLiveRemovals(): AsyncIterableIterator<LiveRemoved[]>;
|
|
267
378
|
watchLiveDenied(cb: (ids: string[]) => void): () => void;
|
|
268
379
|
watchLiveDenied(): AsyncIterableIterator<string[]>;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
txn(build: (t: SceneTxn) => void): Promise<void>;
|
|
273
|
-
spawn(kind: string, opts: SceneSpawnOptions): Promise<string>;
|
|
274
|
-
patch(id: string, set: Partial<SceneEntity>): Promise<void>;
|
|
275
|
-
rename(id: string, name: string): Promise<void>;
|
|
276
|
-
reparent(id: string, parent: string | null, place?: ScenePlace): Promise<void>;
|
|
277
|
-
despawn(id: string, opts?: {
|
|
278
|
-
cascade?: boolean;
|
|
279
|
-
}): Promise<void>;
|
|
280
|
-
setLocked(id: string, locked: boolean): Promise<void>;
|
|
281
|
-
/**
|
|
282
|
-
* Writes one live batch on this node's live track (made on the first call of each session); returns
|
|
283
|
-
* at once, like `publish`. The runtime stamps the rows and owns the outcome: an id another writer owns
|
|
284
|
-
* comes back on `watchLiveDenied`, a malformed batch as a node notice. Not attached: dropped and counted.
|
|
285
|
-
*/
|
|
286
|
-
live(batch: LiveBatch): void;
|
|
287
|
-
/** The framework bridge (React's hooks): called on every change of the entities or the status. */
|
|
288
|
-
subscribe(listener: () => void): () => void;
|
|
289
|
-
/** Closes the handle: its verbs fail, its views and feeds end, its status says `closed`; the node's other scene handles go on. The last one ends the task, which ends this node's live writer (the runtime retracts its lifetimed rows and live entities: `writer_gone`). Idempotent. */
|
|
380
|
+
/** `cb` with the entities on every change of the entities or the status (the framework bridge, React's hooks), and once more when this handle closes; returns the remover. */
|
|
381
|
+
onChange(cb: (entities: Readonly<Record<string, SceneEntity>>) => void): () => void;
|
|
382
|
+
/** Closes the handle: its verbs fail, its views and feeds end, its status says `closed`; the node's other scene handles go on. The last one ends the task, which releases this node's claims (one `synapse/scene/live/remove` call per claim, best effort, not awaited; the session's end releases what remains) and ends its live writer. Idempotent. */
|
|
290
383
|
close(): void;
|
|
291
384
|
[Symbol.asyncDispose](): Promise<void>;
|
|
292
385
|
}
|
|
293
386
|
/**
|
|
294
387
|
* The active project's scene (one per project; one task per node, shared by every handle). Resolves
|
|
295
388
|
* once the handle is attached, or at once `detached` when the runtime says no project is active; the
|
|
296
|
-
* handle then follows the incarnations as they come and go.
|
|
389
|
+
* handle then follows the incarnations as they come and go. Without a session (before the first, between
|
|
390
|
+
* two) the task waits for the next one, like after a drop.
|
|
297
391
|
*/
|
|
298
392
|
export declare function openScene(node: Node, registry: SceneRegistry, warn: Warn): Promise<SceneHandleImpl>;
|
|
299
393
|
export {};
|