@synapse-sdk/client 0.3.0 → 0.3.3

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/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Card, ClientType, Delivery, FecParams, MediaFrame, Role, ServiceRef, StoreMode, StoreOnDeath, StoreRow, TimeDomain, TopicRef, TrackDesc, Tlv, JsonSchema } from "@synapse-sdk/core";
2
- import type { SynapseError } from "@synapse-sdk/core";
1
+ import type { Card, ClientType, Delivery, FecParams, Role, ServiceRef, StoreMode, StoreOnDeath, StoreRow, TimeDomain, TopicRef, TrackDesc, Tlv, JsonSchema } from "@synapse-sdk/core";
2
+ import type { SynapseError, TasksRun } from "@synapse-sdk/core";
3
3
  export type { Card, ClientType, Delivery, FecParams, Role, ServiceRef, StoreMode, StoreOnDeath, StoreRow, TimeDomain, TopicRef, TrackDesc };
4
4
  /** What the reconnect policy is asked before every attempt. */
5
5
  export interface RetryContext {
@@ -13,8 +13,15 @@ export interface ReconnectPolicy {
13
13
  }
14
14
  export type Transport = "auto" | "webtransport" | "websocket";
15
15
  export interface ConnectOptions {
16
- /** `https://host:port/<root>`. */
17
- url: string;
16
+ /**
17
+ * The runtime, `https://host:4470` (the path to dial is learned from the runtime at every attempt). Through a relay: the relay with
18
+ * the runtime's path, `https://relay:4443/runtimes/<runtime_id>`, and `token`. A `jwt=` in the URL is taken as the token.
19
+ * Absent: `SYNAPSE_ENDPOINT` (Bun/Node; the runtime sets it for every task it starts); a browser has no environment,
20
+ * so there it is `invalid_input`.
21
+ */
22
+ url?: string;
23
+ /** The relay token that lets this node through a relay; none for a runtime dialed directly. Never printed. */
24
+ token?: string;
18
25
  /** This node's type (WP §3.1): bounds the role it may exercise; the runtime grants the role. */
19
26
  type: ClientType;
20
27
  /** This node's name `[a-z0-9_-]{1,64}`; minted (`<type>-<6 hex>`) when absent and kept across reconnects. */
@@ -27,7 +34,7 @@ export interface ConnectOptions {
27
34
  brokerCertSha256?: string;
28
35
  /** Time-domain id override (WP §7.3); default per runtime. */
29
36
  domId?: string;
30
- /** Standing project intent (`&project=`, WP §3.5). */
37
+ /** Standing project intent (WP §3.5), sent with the connect request. */
31
38
  project?: "operator";
32
39
  /** `null` = no reconnect: a dropped session ends the node `closed`. Default: 100 ms → 10 s, ×2, jitter, unlimited. */
33
40
  reconnect?: ReconnectPolicy | null;
@@ -46,6 +53,8 @@ export interface ConnectTarget {
46
53
  userId?: string;
47
54
  credential?: string;
48
55
  brokerCertSha256?: string;
56
+ /** The relay token for *this* target; left out = no token (a token for another runtime would be refused). */
57
+ token?: string;
49
58
  }
50
59
  export type ConnectionState = {
51
60
  status: "connecting";
@@ -79,7 +88,9 @@ export interface Info {
79
88
  dom: TimeDomain;
80
89
  brokerDom: string;
81
90
  brokerVersion: string; /** The robot the runtime serves (fixed for the runtime's life; empty between sessions). */
82
- robot: string;
91
+ robot: string; /** The runtime's name in its cluster, from the current session's hello (empty between sessions). */
92
+ runtimeName: string; /** The runtime's id, from the current session's hello (empty between sessions): kept across the runtime's restarts. */
93
+ runtimeId: string;
83
94
  url: string;
84
95
  }
85
96
  /** A `promoted`/`demoted` notice on the session (WP §3.5). */
@@ -93,7 +104,7 @@ export type Notice = {
93
104
  project: string | null;
94
105
  };
95
106
  export interface PublishOptions {
96
- /** The frame's `t_us` (this node's clock); default now. */
107
+ /** The frame's `t_us` (this node's clock): the capture time, if you have one; default now. */
97
108
  tUs?: number;
98
109
  flags?: number;
99
110
  }
@@ -121,12 +132,13 @@ export interface Publisher<TIn> extends AsyncDisposable {
121
132
  readonly verdict: Verdict;
122
133
  /** Resolves once admitted and announced on the current session; `not_connected` once the node ended. A refusal is asked again, paced and warned about. */
123
134
  ready(): Promise<void>;
124
- /** Synchronous: writes to the installed track, or drops and counts while unbound (SDK §12.4). */
135
+ /**
136
+ * Synchronous: writes to the installed track, or drops and counts while unbound (SDK §12.4). A
137
+ * msgpack topic takes a value; a raw topic takes bytes, sent as given; on a `video/*` topic the
138
+ * bytes are one access unit (Annex-B for `video/h264`), sent as a `MEDIA` frame whose
139
+ * `KEY`/`CONFIG`/`RECOVERY` flags are read off the bitstream.
140
+ */
125
141
  publish(value: TIn, opts?: PublishOptions): void;
126
- /** Raw topics: any frame type, flags and TLVs (WP §4.1); `MEDIA` frames via `publishMedia`. */
127
- publishFrame(type: number, flags: number, tUs: number, tlvs: Tlv[], body: Uint8Array): void;
128
- /** Raw topics: a media access unit (`MEDIA`, flags from the frame, `t_us` = capture time, `STAGES` when stamped; a `sentUs` of 0 is stamped at the write). */
129
- publishMedia(frame: MediaFrame): void;
130
142
  stats(): PublisherStats;
131
143
  close(): void;
132
144
  }
@@ -141,6 +153,12 @@ export interface Envelope<T> {
141
153
  flags: number;
142
154
  type: number;
143
155
  tlvs: Tlv[];
156
+ /** Flag `KEY`: an IDR, a decoder may start here (video). */
157
+ key: boolean;
158
+ /** Flag `CONFIG`: the access unit carries SPS/PPS (video). */
159
+ config: boolean;
160
+ /** Flag `RECOVERY`: a recovery point, a gradual start point (video). */
161
+ recovery: boolean;
144
162
  }
145
163
  export interface SubscribeOptions {
146
164
  /** Deliver at most one message per interval, newest wins (skipped counted `coalesced`). */
@@ -417,6 +435,9 @@ export interface SceneEntity {
417
435
  /** Presentation/status the live plane sets per entity. */
418
436
  state?: Record<string, unknown>;
419
437
  hardpoints?: Hardpoint[];
438
+ /** The entity's tasks (`instance` → declaration): what the runtime runs for it while the project's tasks run. */
439
+ tasks?: Record<string, TaskDeclaration>;
440
+ /** Passed through untouched; the runtime does not read it (`tasks` supersedes it). */
420
441
  behaviors?: Record<string, unknown>;
421
442
  possession?: Record<string, unknown>;
422
443
  labels?: string[];
@@ -653,6 +674,126 @@ export interface SceneHandle extends AsyncDisposable {
653
674
  /** Ends this handle: its verbs fail `not_connected`, its views and feeds end; the node's other scene handles go on. */
654
675
  close(): void;
655
676
  }
677
+ /**
678
+ * A declaration: what the runtime runs under an instance name (the robot's: a key of
679
+ * `tasks.declarations`; a project's: an entry of an entity's `tasks`). Whether it has a process to
680
+ * run is the catalog's: a task whose spec has nothing to run is passive (counted, never started).
681
+ */
682
+ export interface TaskDeclaration {
683
+ /** The task's address, as the task tool lists it (`<workspace>:<pkg>:<task>`); never split. */
684
+ ref: string;
685
+ /** `false`: left out of the next run. */
686
+ enabled?: boolean;
687
+ /** Passed to the task: as flags, positionals or environment variables per its spec, and whole as `SYNAPSE_CONFIG` (JSON). */
688
+ config?: Record<string, unknown>;
689
+ /** The catalog's `schemaHash` this declaration was written against; another one fails the run. */
690
+ schema?: string;
691
+ }
692
+ /** How a task's last process ended: its exit code, the signal that ended it, or neither. Times are Unix ms. */
693
+ export type TaskExit = {
694
+ code: number;
695
+ at: number;
696
+ } | {
697
+ signal: number;
698
+ at: number;
699
+ } | {
700
+ at: number;
701
+ };
702
+ /** One running task, as the runtime shows it. */
703
+ export interface TaskStatus {
704
+ scope: "robot" | "project";
705
+ /** The task's address (its declaration's `ref`). */
706
+ addr: string;
707
+ instance: string;
708
+ /** Project tasks: the entity's id. */
709
+ entity?: string;
710
+ /** `down`: its process exited and its restart is pending. */
711
+ state: "up" | "down";
712
+ /** Unix ms of the last change between `up` and `down`. */
713
+ since: number;
714
+ /** How many times its process was started again after an exit. */
715
+ restarts: number;
716
+ /** How its last process ended. */
717
+ exit?: TaskExit;
718
+ /** The file its stdout and stderr go to. */
719
+ log: string;
720
+ }
721
+ /** A scope's run and its tasks. */
722
+ export interface TasksRunStatus<T> {
723
+ /** `undefined`: the runtime has not said yet (not synced, or between sessions). */
724
+ state: "starting" | "running" | "stopping" | "stopped" | undefined;
725
+ /** Unix ms of the last change of `state`. */
726
+ since?: number;
727
+ /** Why it stopped or failed: `project_switch`, or an error code (`preflight_failed`, `launch_failed`, ...). */
728
+ reason?: string;
729
+ tasks: T;
730
+ }
731
+ /** What runs, both scopes: the robot's tasks by instance, the project's by entity id, then instance. */
732
+ export interface TasksStatus {
733
+ robot: TasksRunStatus<Readonly<Record<string, TaskStatus>>>;
734
+ project: TasksRunStatus<Readonly<Record<string, Readonly<Record<string, TaskStatus>>>>>;
735
+ }
736
+ /** One task the runtime knows (from the task tool's workspaces). Fields the task's manifest lacks are absent. */
737
+ export interface TaskCatalogEntry {
738
+ addr: string;
739
+ workspace: string;
740
+ pkg?: string;
741
+ name?: string;
742
+ kind?: string;
743
+ tags?: string[];
744
+ inputs?: JsonSchema;
745
+ schemaHash?: string;
746
+ definedBy?: string;
747
+ }
748
+ /** A value the runtime keeps current that this node only reads: it has no writes. */
749
+ export interface ReadonlyStoreHandle<V> {
750
+ /** The value now; the same object while nothing changed, and an unchanged part keeps its object when another part changes. */
751
+ readonly value: V;
752
+ /** `true` while the value is current. */
753
+ readonly synced: boolean;
754
+ /** Resolves once the value is current (the first time). */
755
+ ready(): Promise<void>;
756
+ /** The whole value after each change. It is state, not history: a reader slower than the changes sees the latest value. */
757
+ watch(): AsyncIterable<V>;
758
+ /** The framework bridge (React): called on every change of the value or of `synced`. */
759
+ subscribe(listener: () => void): () => void;
760
+ }
761
+ /** The robot's task declarations, `instance` → declaration (operators write them). The node owns this handle: it has no `close` or `destroy`. */
762
+ export interface TaskDeclarations extends Omit<StoreHandle, "name" | "value" | "get" | "set" | "watch" | "destroy" | "close" | typeof Symbol.asyncDispose> {
763
+ readonly value: Readonly<Record<string, TaskDeclaration>>;
764
+ get(instance: string): TaskDeclaration | undefined;
765
+ /** `set(instance, declaration)`, or `set({ ... })` for several as one atomic write; waits for the value to be current first, resolves once `value` shows the write. */
766
+ set(instance: string, declaration: TaskDeclaration): Promise<void>;
767
+ set(declarations: Record<string, TaskDeclaration>): Promise<void>;
768
+ /** The whole value after each change; with `instance`, that declaration each time it changes (`undefined` after a delete). */
769
+ watch(instance?: string): AsyncIterable<unknown>;
770
+ /** Resolves once the value is current (the first time). */
771
+ ready(): Promise<void>;
772
+ }
773
+ /**
774
+ * `node.tasks`: the robot's task declarations, what runs (`status`), what the runtime can run
775
+ * (`catalog`), and the verbs. Running and stopping need the operator role. A run's reply is the
776
+ * runtime's answer; what runs afterwards is `status`.
777
+ */
778
+ export interface Tasks {
779
+ readonly declarations: TaskDeclarations;
780
+ readonly status: ReadonlyStoreHandle<TasksStatus>;
781
+ /** By address. */
782
+ readonly catalog: ReadonlyStoreHandle<Readonly<Record<string, TaskCatalogEntry>>>;
783
+ /**
784
+ * Starts the robot's tasks (the enabled declarations). Every declaration is checked first and nothing starts unless all
785
+ * pass: a failed check rejects `preflight_failed`, a process that could not start `launch_failed` (what had started is
786
+ * stopped); both carry the report ({@link isTasksRefusal}). `already_running` while they run. Robot tasks keep running
787
+ * across project switches.
788
+ */
789
+ runRobotTasks(): Promise<TasksRun>;
790
+ /** Stops every robot task (also when none ran). Project tasks are not touched. */
791
+ stopRobotTasks(): Promise<void>;
792
+ /** Starts the active project's tasks (the enabled `tasks` of its scene's entities), as {@link runRobotTasks}; `project_inactive` with no active project. A project switch stops them. */
793
+ runProjectTasks(): Promise<TasksRun>;
794
+ /** Stops every project task (also when none ran). Robot tasks are not touched. */
795
+ stopProjectTasks(): Promise<void>;
796
+ }
656
797
  export interface Catalog {
657
798
  readonly topics: Readonly<Record<string, {
658
799
  desc?: TrackDesc;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapse-sdk/client",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
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,7 +14,7 @@
14
14
  "dist"
15
15
  ],
16
16
  "dependencies": {
17
- "@synapse-sdk/core": "0.3.0",
17
+ "@synapse-sdk/core": "0.3.3",
18
18
  "@moq/net": "0.4.2"
19
19
  },
20
20
  "peerDependencies": {