@synapse-sdk/client 0.1.0 → 0.3.0
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/README.md +1 -111
- package/dist/calls.d.ts +37 -0
- package/dist/calls.js +192 -0
- package/dist/channel.d.ts +84 -0
- package/dist/channel.js +215 -0
- package/dist/fec.d.ts +85 -0
- package/dist/fec.js +281 -0
- package/dist/index.d.ts +10 -74
- package/dist/index.js +10 -15
- package/dist/moq_log.d.ts +23 -0
- package/dist/moq_log.js +176 -0
- package/dist/node.d.ts +145 -0
- package/dist/node.js +407 -0
- package/dist/scene.d.ts +299 -0
- package/dist/scene.js +1531 -0
- package/dist/scene_frames.d.ts +51 -0
- package/dist/scene_frames.js +215 -0
- package/dist/serve.d.ts +46 -0
- package/dist/serve.js +281 -0
- package/dist/session.d.ts +189 -0
- package/dist/session.js +745 -0
- package/dist/signals.d.ts +10 -0
- package/dist/signals.js +63 -0
- package/dist/store.d.ts +145 -0
- package/dist/store.js +898 -0
- package/dist/synapse.d.ts +89 -0
- package/dist/synapse.js +256 -0
- package/dist/topics.d.ts +136 -0
- package/dist/topics.js +938 -0
- package/dist/types.d.ts +679 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +67 -0
- package/dist/util.js +227 -0
- package/dist/view.d.ts +19 -0
- package/dist/view.js +145 -0
- package/package.json +18 -39
- package/dist/node-CSSIXG4k.js +0 -1501
- package/dist/node-DbD7G0Nx.d.ts +0 -466
- package/dist/react.d.ts +0 -63
- package/dist/react.js +0 -141
package/dist/fec.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as Moq from "@moq/net";
|
|
2
|
+
import { type FecParams, type FecReport, type FecWasm, type Header } from "@synapse-sdk/core";
|
|
3
|
+
import { type Session } from "./session.ts";
|
|
4
|
+
/** The most symbols one write puts on the track at once (the relay's datagram ring). */
|
|
5
|
+
export declare const RING_BURST = 64;
|
|
6
|
+
/** The pause between two bursts of one frame's remainder. */
|
|
7
|
+
export declare const BURST_GAP_MS = 1;
|
|
8
|
+
/** How long a `fec` follower waits before following its publisher again (shared with `channel.ts`'s re-ask pace). */
|
|
9
|
+
export declare const REFOLLOW_PACE_MS = 100;
|
|
10
|
+
/** The wasm codec, or `not_supported` with the reason it is not there. */
|
|
11
|
+
export declare function requireFec(what: string): Promise<FecWasm>;
|
|
12
|
+
export interface FecPubStats {
|
|
13
|
+
blocks: number;
|
|
14
|
+
plain: number;
|
|
15
|
+
superseded: number;
|
|
16
|
+
symbols: number;
|
|
17
|
+
reports: number;
|
|
18
|
+
repairPct: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class FecWriter {
|
|
21
|
+
#private;
|
|
22
|
+
readonly topic: string;
|
|
23
|
+
readonly track: Moq.Track.Producer;
|
|
24
|
+
readonly params: FecParams;
|
|
25
|
+
readonly stats: FecPubStats;
|
|
26
|
+
private readonly onError;
|
|
27
|
+
/** `stats` is the publisher's (cumulative across sessions); `params.repair_pct` is the ratio to start from. */
|
|
28
|
+
constructor(topic: string, track: Moq.Track.Producer, wasm: FecWasm, params: FecParams, stats: FecPubStats, onError: (e: unknown) => void);
|
|
29
|
+
/** WP §6.4: the repair ratio for the next blocks (clamped 0..100). */
|
|
30
|
+
setRepairPct(pct: number): void;
|
|
31
|
+
/** Would this frame go as one plain datagram? */
|
|
32
|
+
isPlain(header: Header, bodyLen: number): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Encodes one frame and writes its first [`RING_BURST`] symbols; a larger frame's remainder is
|
|
35
|
+
* written from the timer. A `STAGES.sent_us` of 0 is stamped here, before the encode (the symbols
|
|
36
|
+
* are derived from those bytes). Throws when the frame cannot be encoded (nothing written) or the
|
|
37
|
+
* track refuses (the session is going).
|
|
38
|
+
*/
|
|
39
|
+
publish(header: Header, body: Uint8Array): void;
|
|
40
|
+
close(): void;
|
|
41
|
+
}
|
|
42
|
+
/** `<sub prefix>/feedback/<pub name>/<pub sid>/<topic>`: where subscriber session `sub` reports to publisher session `publisher` (both `client/<name>/<sid>`). */
|
|
43
|
+
export declare function feedbackPath(sub: string, publisher: string, topic: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Publisher side of WP §6.4: follows every subscriber session's reports on `topic` for the
|
|
46
|
+
* publisher session `s` and adapts `setRepairPct` through a `RepairAdapter`. Ends when `signal` aborts.
|
|
47
|
+
*/
|
|
48
|
+
export declare function feedbackListener(s: Session, topic: string, basePct: number, setRepairPct: (pct: number) => void, onReport: () => void, signal: AbortSignal, warn: (msg: string) => void): Promise<void>;
|
|
49
|
+
/** A frame the receiver put together: `frame` is header ++ body. */
|
|
50
|
+
export interface ReceivedFrame {
|
|
51
|
+
seq: number;
|
|
52
|
+
frame: Uint8Array;
|
|
53
|
+
repaired: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface ReceiverStats {
|
|
56
|
+
symbols: number;
|
|
57
|
+
late: number;
|
|
58
|
+
surplus: number;
|
|
59
|
+
bad: number;
|
|
60
|
+
frames: number;
|
|
61
|
+
repaired: number;
|
|
62
|
+
lost: number;
|
|
63
|
+
expired: number;
|
|
64
|
+
}
|
|
65
|
+
/** The receiver for one publisher: `push` every datagram, `poll` for frames (after each push and on the 10 ms tick). */
|
|
66
|
+
export declare class FecReader {
|
|
67
|
+
#private;
|
|
68
|
+
constructor(wasm: FecWasm, params: FecParams | undefined, deadlineOverrideMs: number | undefined);
|
|
69
|
+
/** `false` when the datagram was undecodable or inconsistent (counted `bad`). */
|
|
70
|
+
push(payload: Uint8Array, nowUs: number): boolean;
|
|
71
|
+
poll(nowUs: number): ReceivedFrame[];
|
|
72
|
+
pending(): number;
|
|
73
|
+
stats(): ReceiverStats;
|
|
74
|
+
takeReport(): FecReport;
|
|
75
|
+
close(): void;
|
|
76
|
+
}
|
|
77
|
+
/** Subscriber side of WP §6.4: the report track, created on the first report; bound to one session like the follower that owns it. */
|
|
78
|
+
export declare class ReportWriter {
|
|
79
|
+
#private;
|
|
80
|
+
private readonly s;
|
|
81
|
+
readonly path: string;
|
|
82
|
+
constructor(s: Session, pubPrefix: string, topic: string);
|
|
83
|
+
write(report: FecReport): void;
|
|
84
|
+
close(): void;
|
|
85
|
+
}
|
package/dist/fec.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// The datagram path of `fec` topics (WP §6.2–§6.4), the JS spelling of the Rust client's `fec.rs`.
|
|
2
|
+
// The codec is synapse-core's RaptorQ sender/receiver compiled to wasm (`loadFec`); a `fec` topic
|
|
3
|
+
// without it is refused (`not_supported`) — there is no second encoder in TypeScript.
|
|
4
|
+
//
|
|
5
|
+
// Publisher ([`FecWriter`], the send rule, WP §6.3): `publish` encodes the frame and writes its
|
|
6
|
+
// first [`RING_BURST`] symbols to the track in the call; a larger frame's remainder follows in
|
|
7
|
+
// bursts of at most [`RING_BURST`], [`BURST_GAP_MS`] apart, from a timer; a newer frame published
|
|
8
|
+
// while a remainder is still due replaces it (newest wins, counted `superseded`). Subscriber
|
|
9
|
+
// ([`FecReader`]): every datagram goes through the receiver (symbols and plain frames alike), which
|
|
10
|
+
// delivers frames in `seq` order, repair applied; polled after each datagram and every 10 ms so a
|
|
11
|
+
// lost block gives up on its own. Feedback (WP §6.4): a subscriber session writes one `REPORT` a
|
|
12
|
+
// second on `<own prefix>/feedback/<pub name>/<pub sid>/<topic>` track `report`; the publisher
|
|
13
|
+
// follows `client/*/*/feedback/<own name>/<own sid>/<topic>` and adapts its repair ratio
|
|
14
|
+
// (`RepairAdapter`, worst subscriber wins).
|
|
15
|
+
import * as Moq from "@moq/net";
|
|
16
|
+
import { RepairAdapter, SynapseError, TYPES, decode as decodeBody, encode as encodeBody, encodeHeader, hasPendingSentUs, headerLength, loadFec, moqPriority, nowUs, splitFrame, stampSentUs, } from "@synapse-sdk/core";
|
|
17
|
+
import { CallWriter, moqTimestamp, streamSubscription, waitActive } from "./session.js";
|
|
18
|
+
/** The most symbols one write puts on the track at once (the relay's datagram ring). */
|
|
19
|
+
export const RING_BURST = 64;
|
|
20
|
+
/** The pause between two bursts of one frame's remainder. */
|
|
21
|
+
export const BURST_GAP_MS = 1;
|
|
22
|
+
/** How long a `fec` follower waits before following its publisher again (shared with `channel.ts`'s re-ask pace). */
|
|
23
|
+
export const REFOLLOW_PACE_MS = 100;
|
|
24
|
+
/** The wasm codec, or `not_supported` with the reason it is not there. */
|
|
25
|
+
export async function requireFec(what) {
|
|
26
|
+
try {
|
|
27
|
+
return await loadFec();
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
throw new SynapseError("not_supported", { message: `${what}: fec needs the synapse-wasm codec, which could not be loaded: ${e instanceof Error ? e.message : String(e)}`, cause: e });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class FecWriter {
|
|
34
|
+
topic;
|
|
35
|
+
track;
|
|
36
|
+
params;
|
|
37
|
+
stats;
|
|
38
|
+
onError;
|
|
39
|
+
#sender;
|
|
40
|
+
#rest;
|
|
41
|
+
#timer;
|
|
42
|
+
#closed = false;
|
|
43
|
+
/** `stats` is the publisher's (cumulative across sessions); `params.repair_pct` is the ratio to start from. */
|
|
44
|
+
constructor(topic, track, wasm, params, stats, onError) {
|
|
45
|
+
this.topic = topic;
|
|
46
|
+
this.track = track;
|
|
47
|
+
this.params = params;
|
|
48
|
+
this.stats = stats;
|
|
49
|
+
this.onError = onError;
|
|
50
|
+
this.#sender = new wasm.FecSender(params.symbol_size, params.repair_pct, params.deadline_ms);
|
|
51
|
+
this.#sender.setRepairPct(stats.repairPct);
|
|
52
|
+
}
|
|
53
|
+
/** WP §6.4: the repair ratio for the next blocks (clamped 0..100). */
|
|
54
|
+
setRepairPct(pct) { this.stats.repairPct = Math.max(0, Math.min(100, Math.trunc(pct))); this.#sender.setRepairPct(this.stats.repairPct); }
|
|
55
|
+
/** Would this frame go as one plain datagram? */
|
|
56
|
+
isPlain(header, bodyLen) { return this.#sender.isPlain(encodeHeader(header), bodyLen); }
|
|
57
|
+
/**
|
|
58
|
+
* Encodes one frame and writes its first [`RING_BURST`] symbols; a larger frame's remainder is
|
|
59
|
+
* written from the timer. A `STAGES.sent_us` of 0 is stamped here, before the encode (the symbols
|
|
60
|
+
* are derived from those bytes). Throws when the frame cannot be encoded (nothing written) or the
|
|
61
|
+
* track refuses (the session is going).
|
|
62
|
+
*/
|
|
63
|
+
publish(header, body) {
|
|
64
|
+
if (this.#closed)
|
|
65
|
+
throw new SynapseError("connection_lost", "fec writer closed");
|
|
66
|
+
if (hasPendingSentUs(header))
|
|
67
|
+
stampSentUs(header, nowUs());
|
|
68
|
+
let block;
|
|
69
|
+
try {
|
|
70
|
+
block = this.#sender.encode(encodeHeader(header), body);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
throw new SynapseError("invalid_input", { message: `fec topic ${this.topic}: ${e instanceof Error ? e.message : String(e)} (${headerLength(header) + body.length} bytes)`, cause: e });
|
|
74
|
+
}
|
|
75
|
+
if (block.plain)
|
|
76
|
+
this.stats.plain++;
|
|
77
|
+
else
|
|
78
|
+
this.stats.blocks++;
|
|
79
|
+
this.stats.symbols += block.symbols.length;
|
|
80
|
+
// A remainder still due is replaced: the newer frame is what the subscriber wants.
|
|
81
|
+
if (this.#rest) {
|
|
82
|
+
this.stats.superseded++;
|
|
83
|
+
this.#rest = undefined;
|
|
84
|
+
}
|
|
85
|
+
const ts = moqTimestamp(block.tUs);
|
|
86
|
+
const first = Math.min(block.symbols.length, RING_BURST);
|
|
87
|
+
for (let i = 0; i < first; i++)
|
|
88
|
+
this.track.appendDatagram(ts, block.symbols[i]);
|
|
89
|
+
if (block.symbols.length > first) {
|
|
90
|
+
this.#rest = { tUs: block.tUs, symbols: block.symbols, next: first, dueMs: performance.now() + BURST_GAP_MS };
|
|
91
|
+
this.#arm();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
#arm() {
|
|
95
|
+
if (this.#timer !== undefined || !this.#rest || this.#closed)
|
|
96
|
+
return;
|
|
97
|
+
this.#timer = setTimeout(() => { this.#timer = undefined; this.#burst(); }, Math.max(0, this.#rest.dueMs - performance.now()));
|
|
98
|
+
}
|
|
99
|
+
/** Writes the next burst of the remainder; re-arms while symbols are left. */
|
|
100
|
+
#burst() {
|
|
101
|
+
const r = this.#rest;
|
|
102
|
+
if (!r || this.#closed)
|
|
103
|
+
return;
|
|
104
|
+
const ts = moqTimestamp(r.tUs);
|
|
105
|
+
const end = Math.min(r.symbols.length, r.next + RING_BURST);
|
|
106
|
+
try {
|
|
107
|
+
for (; r.next < end; r.next++)
|
|
108
|
+
this.track.appendDatagram(ts, r.symbols[r.next]);
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
this.close();
|
|
112
|
+
this.onError(e);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (r.next >= r.symbols.length)
|
|
116
|
+
this.#rest = undefined;
|
|
117
|
+
else {
|
|
118
|
+
r.dueMs = performance.now() + BURST_GAP_MS;
|
|
119
|
+
this.#arm();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
close() {
|
|
123
|
+
this.#closed = true;
|
|
124
|
+
if (this.#timer !== undefined) {
|
|
125
|
+
clearTimeout(this.#timer);
|
|
126
|
+
this.#timer = undefined;
|
|
127
|
+
}
|
|
128
|
+
this.#rest = undefined;
|
|
129
|
+
try {
|
|
130
|
+
this.#sender.free();
|
|
131
|
+
}
|
|
132
|
+
catch { /* freed */ }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** `<sub prefix>/feedback/<pub name>/<pub sid>/<topic>`: where subscriber session `sub` reports to publisher session `publisher` (both `client/<name>/<sid>`). */
|
|
136
|
+
export function feedbackPath(sub, publisher, topic) { return `${sub}/feedback/${publisher.startsWith("client/") ? publisher.slice("client/".length) : publisher}/${topic}`; }
|
|
137
|
+
/**
|
|
138
|
+
* Publisher side of WP §6.4: follows every subscriber session's reports on `topic` for the
|
|
139
|
+
* publisher session `s` and adapts `setRepairPct` through a `RepairAdapter`. Ends when `signal` aborts.
|
|
140
|
+
*/
|
|
141
|
+
export async function feedbackListener(s, topic, basePct, setRepairPct, onReport, signal, warn) {
|
|
142
|
+
let pattern, announced;
|
|
143
|
+
try {
|
|
144
|
+
pattern = Moq.Path.Pattern.parse(feedbackPath("client/*/*", s.prefix, topic));
|
|
145
|
+
announced = s.sub.announced(pattern);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
warn(`topic ${topic}: feedback pattern refused: ${e instanceof Error ? e.message : String(e)}`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const adapter = new RepairAdapter(basePct);
|
|
152
|
+
const onAbort = () => announced.close();
|
|
153
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
154
|
+
try {
|
|
155
|
+
for (;;) {
|
|
156
|
+
const u = await announced.next();
|
|
157
|
+
if (!u)
|
|
158
|
+
return;
|
|
159
|
+
if (u.kind !== "announced")
|
|
160
|
+
continue;
|
|
161
|
+
// The cursor delivers every announcement whose subtree overlaps the pattern (a client's `hello` among them): only an exact match is a report broadcast.
|
|
162
|
+
if (!pattern.matches(String(u.prefix)))
|
|
163
|
+
continue;
|
|
164
|
+
void (async () => {
|
|
165
|
+
const req = s.request(String(u.prefix));
|
|
166
|
+
try {
|
|
167
|
+
const bc = await waitActive(req, 5000, signal);
|
|
168
|
+
const sub = bc.track("report").subscribe(streamSubscription(moqPriority(3)));
|
|
169
|
+
// Reports are read as they arrive (as in Rust): only the newest matters to the adapter, so a missing older one is never waited for.
|
|
170
|
+
let g;
|
|
171
|
+
const onStop = () => { sub.close(); g?.close(); };
|
|
172
|
+
signal.addEventListener("abort", onStop, { once: true });
|
|
173
|
+
try {
|
|
174
|
+
for (;;) {
|
|
175
|
+
g = await sub.recvGroup();
|
|
176
|
+
if (!g)
|
|
177
|
+
break;
|
|
178
|
+
for (;;) {
|
|
179
|
+
const f = await g.readFrame();
|
|
180
|
+
if (!f)
|
|
181
|
+
break;
|
|
182
|
+
let header, body;
|
|
183
|
+
try {
|
|
184
|
+
({ header, body } = splitFrame(f.payload));
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (header.type !== TYPES.REPORT)
|
|
190
|
+
continue;
|
|
191
|
+
let report;
|
|
192
|
+
try {
|
|
193
|
+
report = decodeBody(body);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (!report || typeof report.lost !== "number" || typeof report.frames !== "number")
|
|
199
|
+
continue;
|
|
200
|
+
onReport();
|
|
201
|
+
const pct = adapter.observe(report);
|
|
202
|
+
if (pct !== undefined)
|
|
203
|
+
setRepairPct(pct);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
signal.removeEventListener("abort", onStop);
|
|
209
|
+
onStop();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch { /* the subscriber left */ }
|
|
213
|
+
finally {
|
|
214
|
+
req.close();
|
|
215
|
+
}
|
|
216
|
+
})();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
if (!signal.aborted)
|
|
221
|
+
warn(`topic ${topic}: feedback listener ended: ${e instanceof Error ? e.message : String(e)}`);
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
signal.removeEventListener("abort", onAbort);
|
|
225
|
+
announced.close();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/** The receiver for one publisher: `push` every datagram, `poll` for frames (after each push and on the 10 ms tick). */
|
|
229
|
+
export class FecReader {
|
|
230
|
+
#rx;
|
|
231
|
+
constructor(wasm, params, deadlineOverrideMs) {
|
|
232
|
+
this.#rx = new wasm.FecReceiver(params?.deadline_ms ?? 0, 0, deadlineOverrideMs ?? 0);
|
|
233
|
+
}
|
|
234
|
+
/** `false` when the datagram was undecodable or inconsistent (counted `bad`). */
|
|
235
|
+
push(payload, nowUs) { return this.#rx.push(payload, nowUs) !== 2 /* Pushed.Bad */; }
|
|
236
|
+
poll(nowUs) { return this.#rx.poll(nowUs); }
|
|
237
|
+
pending() { return this.#rx.pending(); }
|
|
238
|
+
stats() { return this.#rx.stats(); }
|
|
239
|
+
takeReport() { return this.#rx.takeReport(); }
|
|
240
|
+
close() { try {
|
|
241
|
+
this.#rx.free();
|
|
242
|
+
}
|
|
243
|
+
catch { /* freed */ } }
|
|
244
|
+
}
|
|
245
|
+
/** Subscriber side of WP §6.4: the report track, created on the first report; bound to one session like the follower that owns it. */
|
|
246
|
+
export class ReportWriter {
|
|
247
|
+
s;
|
|
248
|
+
path;
|
|
249
|
+
#bc;
|
|
250
|
+
#writer;
|
|
251
|
+
#seq = 0;
|
|
252
|
+
constructor(s, pubPrefix, topic) {
|
|
253
|
+
this.s = s;
|
|
254
|
+
this.path = feedbackPath(s.prefix, pubPrefix, topic);
|
|
255
|
+
}
|
|
256
|
+
write(report) {
|
|
257
|
+
if (!this.#writer) {
|
|
258
|
+
const bc = this.s.createBroadcast(this.path);
|
|
259
|
+
this.#writer = new CallWriter(bc.createTrack("report", { priority: moqPriority(3) }));
|
|
260
|
+
bc.announce();
|
|
261
|
+
this.#bc = bc;
|
|
262
|
+
}
|
|
263
|
+
const rtt = this.s.clock.get().rttUs;
|
|
264
|
+
if (rtt !== undefined)
|
|
265
|
+
report.rtt_us = rtt;
|
|
266
|
+
this.#seq = (this.#seq + 1) >>> 0;
|
|
267
|
+
this.#writer.write({ flags: 0, type: TYPES.REPORT, seq: this.#seq, tUs: nowUs(), tlvs: [] }, encodeBody(report));
|
|
268
|
+
}
|
|
269
|
+
close() {
|
|
270
|
+
try {
|
|
271
|
+
this.#writer?.close();
|
|
272
|
+
}
|
|
273
|
+
catch { /* closed */ }
|
|
274
|
+
try {
|
|
275
|
+
this.#bc?.close();
|
|
276
|
+
}
|
|
277
|
+
catch { /* closed */ }
|
|
278
|
+
this.#writer = undefined;
|
|
279
|
+
this.#bc = undefined;
|
|
280
|
+
}
|
|
281
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,74 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
//#region src/address.d.ts
|
|
12
|
-
interface Address {
|
|
13
|
-
realm: string;
|
|
14
|
-
name: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Split a `[realm:]name` address into `{ realm, name }`; default realm `synapse`.
|
|
18
|
-
* Only a bare-identifier prefix counts as a realm, so a synapse name with `/` and no realm
|
|
19
|
-
* passes through unchanged. Mirrors the Python client.
|
|
20
|
-
*
|
|
21
|
-
* "camera/capture" -> { realm: "synapse", name: "camera/capture" }
|
|
22
|
-
* "rosbridge:/add_two_ints" -> { realm: "rosbridge", name: "/add_two_ints" }
|
|
23
|
-
*/
|
|
24
|
-
declare function address(addr: string): Address;
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/errors.d.ts
|
|
27
|
-
declare class ConnectionError extends Error {
|
|
28
|
-
constructor(message: string, options?: {
|
|
29
|
-
cause?: unknown;
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
declare class TimeoutError extends ConnectionError {
|
|
33
|
-
constructor(message: string);
|
|
34
|
-
}
|
|
35
|
-
/** A newer `connect(...)` (or `disconnect()`) replaced the target this promise was awaiting. */
|
|
36
|
-
declare class SupersededError extends ConnectionError {
|
|
37
|
-
constructor();
|
|
38
|
-
}
|
|
39
|
-
declare class ChannelError extends Error {
|
|
40
|
-
topic: string;
|
|
41
|
-
response: unknown;
|
|
42
|
-
constructor(topic: string, message: string, response?: unknown);
|
|
43
|
-
}
|
|
44
|
-
interface BusErrorPayload {
|
|
45
|
-
code?: string;
|
|
46
|
-
message?: string;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Known bus error codes — server-emitted (`unauthorized`, `service_unavailable`,
|
|
50
|
-
* `provider_error`, `invalid_input`, `unknown_event`, `ros_error`) plus client-side
|
|
51
|
-
* (`bad_ack`, `not_connected`, `timeout`, `cancelled`). Match on these to avoid magic
|
|
52
|
-
* strings; treat the set as **non-exhaustive** (the server may add codes).
|
|
53
|
-
*/
|
|
54
|
-
declare const BusErrorCode: {
|
|
55
|
-
readonly Unauthorized: "unauthorized";
|
|
56
|
-
readonly ServiceUnavailable: "service_unavailable";
|
|
57
|
-
readonly ProviderError: "provider_error";
|
|
58
|
-
readonly InvalidInput: "invalid_input";
|
|
59
|
-
readonly UnknownEvent: "unknown_event";
|
|
60
|
-
readonly RosError: "ros_error";
|
|
61
|
-
readonly BadAck: "bad_ack";
|
|
62
|
-
readonly NotConnected: "not_connected";
|
|
63
|
-
readonly Timeout: "timeout";
|
|
64
|
-
readonly Cancelled: "cancelled";
|
|
65
|
-
};
|
|
66
|
-
type BusErrorCode = (typeof BusErrorCode)[keyof typeof BusErrorCode];
|
|
67
|
-
/** Raised when a service call fails — at accept time or mid-flight (see the bus error model). */
|
|
68
|
-
declare class BusError extends Error {
|
|
69
|
-
code: string;
|
|
70
|
-
detail: unknown;
|
|
71
|
-
constructor(error: BusErrorPayload | unknown);
|
|
72
|
-
}
|
|
73
|
-
//#endregion
|
|
74
|
-
export { type Address, BusError, BusErrorCode, type BusErrorPayload, type CallContext, type CallOptions, type CatalogChange, Channel, ChannelError, type ChannelHandler, type ChannelHost, type ConnectTarget, Connection, ConnectionError, type ConnectionOptions, type ConnectionState, type ConnectionStatus, type Frame, LatestValue, type Logger, type Message, type Params, type ParamsInput, type Reply, type ResourceInfo, type Serializer, type ServiceCard, type ServiceHandler, type ServiceRegistration, type StateDiff, StateHandle, type StreamEvent, type SubscribeOptions, type Subscription, SupersededError, Synapse, type SynapseOptions, SystemRole, type SystemState, type Target, TimeoutError, type TokenInput, type VerifyFn, type VerifyHandle, type WebSocketCtor, type WebSocketLike, address, serializer };
|
|
1
|
+
export * from "@synapse-sdk/core";
|
|
2
|
+
export { Synapse, FIRST_CONNECT_GIVE_UP_MS } from "./synapse.ts";
|
|
3
|
+
export { defaultReconnectPolicy, exponentialPolicy, fixedPolicy, withMaxAttempts } from "./node.ts";
|
|
4
|
+
export { callStream } from "./calls.ts";
|
|
5
|
+
export { setMoqDebug } from "./moq_log.ts";
|
|
6
|
+
export type * from "./types.ts";
|
|
7
|
+
export { brokerCertHelperUrl, discoverBrokerCertSha256, ensureWebTransport } from "./session.ts";
|
|
8
|
+
export { replaceEqualDeep, shallowEqual } from "./util.ts";
|
|
9
|
+
export { orderAfter, orderBefore, orderBetween, ulid } from "./scene.ts";
|
|
10
|
+
export { derivedFrameKey, derivedFrameName, materializeFrames, materializeHardpoints, validateDerivedFrame, type MaterializeReport } from "./scene_frames.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Controller: "controller",
|
|
12
|
-
Agent: "agent"
|
|
13
|
-
};
|
|
14
|
-
//#endregion
|
|
15
|
-
export { BusError, BusErrorCode, Channel, ChannelError, Connection, ConnectionError, LatestValue, StateHandle, SupersededError, Synapse, SystemRole, TimeoutError, address, serializer };
|
|
1
|
+
// @synapse-sdk/client: the Synapse node over @moq/net. Re-exports the core so one import suffices.
|
|
2
|
+
export * from "@synapse-sdk/core";
|
|
3
|
+
export { Synapse, FIRST_CONNECT_GIVE_UP_MS } from "./synapse.js";
|
|
4
|
+
export { defaultReconnectPolicy, exponentialPolicy, fixedPolicy, withMaxAttempts } from "./node.js";
|
|
5
|
+
export { callStream } from "./calls.js";
|
|
6
|
+
export { setMoqDebug } from "./moq_log.js";
|
|
7
|
+
export { brokerCertHelperUrl, discoverBrokerCertSha256, ensureWebTransport } from "./session.js";
|
|
8
|
+
export { replaceEqualDeep, shallowEqual } from "./util.js";
|
|
9
|
+
export { orderAfter, orderBefore, orderBetween, ulid } from "./scene.js";
|
|
10
|
+
export { derivedFrameKey, derivedFrameName, materializeFrames, materializeHardpoints, validateDerivedFrame } from "./scene_frames.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Show @moq/net's debug narration (and the demoted routine-end lines) on `console.debug`; default off, or `SYNAPSE_MOQ_DEBUG=1`. */
|
|
2
|
+
export declare function setMoqDebug(on: boolean): void;
|
|
3
|
+
/** Exported for tests: whether a `console.debug` call is @moq/net's narration. */
|
|
4
|
+
export declare function isMoqDebug(args: readonly unknown[]): boolean;
|
|
5
|
+
/** One session's share of the registry: the paths it announced and whether we are closing it. */
|
|
6
|
+
export interface MoqLogScope {
|
|
7
|
+
/** Records a broadcast path this session announces (`client/<name>/<sid>/...`). */
|
|
8
|
+
announced(path: string): void;
|
|
9
|
+
/** Records a broadcast path this session requests (subscribes to). */
|
|
10
|
+
requested(path: string): void;
|
|
11
|
+
/** Marks the session as closed by us: its tracks now end on purpose. */
|
|
12
|
+
closing(): void;
|
|
13
|
+
/** Drops the scope once @moq/net's late lines have had time to arrive. */
|
|
14
|
+
release(): void;
|
|
15
|
+
}
|
|
16
|
+
/** Registers a session with the filter; installs the `console.warn` wrapper on first use. */
|
|
17
|
+
export declare function moqLogScope(): MoqLogScope;
|
|
18
|
+
/** Forgets every scope; for tests, whose earlier nodes would otherwise still count as closing. */
|
|
19
|
+
export declare function resetMoqLogScopes(): void;
|
|
20
|
+
/** Restores the original `console.warn`/`console.debug`; for tests. */
|
|
21
|
+
export declare function uninstallMoqLogFilter(): void;
|
|
22
|
+
/** Exported for tests: whether a `console.warn` call from @moq/net describes the normal end of one of our tracks. */
|
|
23
|
+
export declare function isRoutineEnd(args: readonly unknown[]): boolean;
|