@statelyai/sdk 0.14.2 → 0.16.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 +81 -11
- package/dist/auth.d.mts +1 -1
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +35 -0
- package/dist/embed.d.mts +1 -1
- package/dist/embed.mjs +1 -1
- package/dist/{graph-3oSqiY4N.d.mts → graph-DuOeLGvh.d.mts} +1 -1
- package/dist/graph.d.mts +1 -1
- package/dist/{index-CcgKzQ-C.d.mts → index-ag6K2iAS.d.mts} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +6 -6
- package/dist/{inspect-DWDTNMEc.mjs → inspect-BwVdM4R8.mjs} +109 -72
- package/dist/{inspect-DQ_7I7eH.d.mts → inspect-CduY_2Fa.d.mts} +54 -59
- package/dist/inspect.d.mts +1 -1
- package/dist/inspect.mjs +1 -1
- package/dist/node-relay.d.mts +22 -0
- package/dist/node-relay.mjs +84 -0
- package/dist/patchTypes.d.mts +1 -1
- package/dist/protocol.d.mts +102 -115
- package/dist/protocol.mjs +33 -2
- package/dist/relay.d.mts +10 -11
- package/dist/relay.mjs +83 -62
- package/dist/{dist-CO36Ks-i.mjs → statelyPragma-Th0gdXfx.mjs} +112 -4432
- package/dist/studio-Bk_u41gu.d.mts +303 -0
- package/dist/studio-txdyJHD7.mjs +4725 -0
- package/dist/studio.d.mts +2 -125
- package/dist/studio.mjs +2 -171
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +13 -24
- package/dist/{transport-D2Ud05yg.mjs → transport-B_ig9Znn.mjs} +56 -198
- package/package.json +15 -3
- package/dist/dist-Ci5I7Rjq.mjs +0 -9401
- /package/dist/{auth-D9-iLi-S.d.mts → auth-2Thaw42j.d.mts} +0 -0
|
@@ -157,9 +157,7 @@ function createPostMessageTransport(options) {
|
|
|
157
157
|
},
|
|
158
158
|
onMessage(handler) {
|
|
159
159
|
messageHandlers.add(handler);
|
|
160
|
-
return () =>
|
|
161
|
-
messageHandlers.delete(handler);
|
|
162
|
-
};
|
|
160
|
+
return () => messageHandlers.delete(handler);
|
|
163
161
|
},
|
|
164
162
|
destroy() {
|
|
165
163
|
if (destroyed) return;
|
|
@@ -177,31 +175,52 @@ function createPostMessageTransport(options) {
|
|
|
177
175
|
return () => {};
|
|
178
176
|
}
|
|
179
177
|
readyHandlers.add(handler);
|
|
180
|
-
return () =>
|
|
181
|
-
readyHandlers.delete(handler);
|
|
182
|
-
};
|
|
178
|
+
return () => readyHandlers.delete(handler);
|
|
183
179
|
}
|
|
184
180
|
};
|
|
185
181
|
}
|
|
186
182
|
function createWebSocketTransport(options) {
|
|
187
|
-
const { url, role,
|
|
183
|
+
const { url, role, producerId, metadata, reconnect = true, maxReconnectAttempts = 10 } = options;
|
|
184
|
+
if (role === "producer" && !producerId) throw new Error("A producerId is required for producer transports.");
|
|
188
185
|
let ws = null;
|
|
189
186
|
let destroyed = false;
|
|
187
|
+
let terminalFailure = false;
|
|
190
188
|
let isReady = false;
|
|
191
189
|
let reconnectAttempts = 0;
|
|
192
190
|
let reconnectTimer = null;
|
|
193
191
|
const readyHandlers = /* @__PURE__ */ new Set();
|
|
194
192
|
const messageHandlers = /* @__PURE__ */ new Set();
|
|
193
|
+
const errorHandlers = /* @__PURE__ */ new Set();
|
|
194
|
+
function fail(failure) {
|
|
195
|
+
errorHandlers.forEach((handler) => handler(failure));
|
|
196
|
+
}
|
|
197
|
+
function scheduleReconnect() {
|
|
198
|
+
if (!reconnect || reconnectAttempts >= maxReconnectAttempts) {
|
|
199
|
+
terminalFailure = true;
|
|
200
|
+
fail({
|
|
201
|
+
code: "connection_failed",
|
|
202
|
+
message: `Unable to connect to inspection relay ${url}`
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const delay = Math.min(1e3 * 2 ** reconnectAttempts, 3e4);
|
|
207
|
+
reconnectAttempts++;
|
|
208
|
+
reconnectTimer = setTimeout(connect, delay);
|
|
209
|
+
}
|
|
195
210
|
function connect() {
|
|
196
|
-
if (destroyed) return;
|
|
197
|
-
|
|
211
|
+
if (destroyed || terminalFailure) return;
|
|
212
|
+
try {
|
|
213
|
+
ws = new WebSocket(url);
|
|
214
|
+
} catch {
|
|
215
|
+
scheduleReconnect();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
198
218
|
ws.onopen = () => {
|
|
199
|
-
reconnectAttempts = 0;
|
|
200
219
|
ws.send(JSON.stringify({
|
|
201
220
|
type: "@statelyai.register",
|
|
202
221
|
protocolVersion: INSPECTION_PROTOCOL_VERSION,
|
|
203
222
|
role,
|
|
204
|
-
|
|
223
|
+
...producerId && { producerId },
|
|
205
224
|
...metadata && { metadata }
|
|
206
225
|
}));
|
|
207
226
|
};
|
|
@@ -217,20 +236,33 @@ function createWebSocketTransport(options) {
|
|
|
217
236
|
if (!raw.type.startsWith(PREFIX)) return;
|
|
218
237
|
const data = raw;
|
|
219
238
|
if (data.type === "@statelyai.registered") {
|
|
239
|
+
if (data.protocolVersion !== INSPECTION_PROTOCOL_VERSION) {
|
|
240
|
+
terminalFailure = true;
|
|
241
|
+
fail({
|
|
242
|
+
code: "unsupported_protocol",
|
|
243
|
+
message: `Relay selected protocol ${data.protocolVersion}; expected ${INSPECTION_PROTOCOL_VERSION}`
|
|
244
|
+
});
|
|
245
|
+
ws?.close(1002, "Unsupported inspection protocol");
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
reconnectAttempts = 0;
|
|
220
249
|
const wasReady = isReady;
|
|
221
250
|
isReady = true;
|
|
222
251
|
if (!wasReady) readyHandlers.forEach((fn) => fn());
|
|
252
|
+
} else if (data.type === "@statelyai.error" && !isReady) {
|
|
253
|
+
terminalFailure = true;
|
|
254
|
+
fail({
|
|
255
|
+
code: data.code,
|
|
256
|
+
message: data.message
|
|
257
|
+
});
|
|
258
|
+
ws?.close(1002, data.message.slice(0, 123));
|
|
223
259
|
}
|
|
224
260
|
messageHandlers.forEach((fn) => fn(data));
|
|
225
261
|
};
|
|
226
262
|
ws.onclose = () => {
|
|
227
|
-
if (destroyed) return;
|
|
263
|
+
if (destroyed || terminalFailure) return;
|
|
228
264
|
isReady = false;
|
|
229
|
-
|
|
230
|
-
const delay = Math.min(1e3 * 2 ** reconnectAttempts, 3e4);
|
|
231
|
-
reconnectAttempts++;
|
|
232
|
-
reconnectTimer = setTimeout(connect, delay);
|
|
233
|
-
}
|
|
265
|
+
scheduleReconnect();
|
|
234
266
|
};
|
|
235
267
|
ws.onerror = () => {};
|
|
236
268
|
}
|
|
@@ -242,9 +274,7 @@ function createWebSocketTransport(options) {
|
|
|
242
274
|
},
|
|
243
275
|
onMessage(handler) {
|
|
244
276
|
messageHandlers.add(handler);
|
|
245
|
-
return () =>
|
|
246
|
-
messageHandlers.delete(handler);
|
|
247
|
-
};
|
|
277
|
+
return () => messageHandlers.delete(handler);
|
|
248
278
|
},
|
|
249
279
|
destroy() {
|
|
250
280
|
if (destroyed) return;
|
|
@@ -254,6 +284,7 @@ function createWebSocketTransport(options) {
|
|
|
254
284
|
ws = null;
|
|
255
285
|
messageHandlers.clear();
|
|
256
286
|
readyHandlers.clear();
|
|
287
|
+
errorHandlers.clear();
|
|
257
288
|
},
|
|
258
289
|
get ready() {
|
|
259
290
|
return isReady && !!ws && ws.readyState === WebSocket.OPEN;
|
|
@@ -261,187 +292,14 @@ function createWebSocketTransport(options) {
|
|
|
261
292
|
onReady(handler) {
|
|
262
293
|
readyHandlers.add(handler);
|
|
263
294
|
if (isReady) handler();
|
|
264
|
-
return () =>
|
|
265
|
-
readyHandlers.delete(handler);
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
function createMultiplexedWebSocketConnection(options) {
|
|
271
|
-
const { url, role, sessionId: primarySessionId, metadata: primaryMetadata, reconnect = true, maxReconnectAttempts = 10 } = options;
|
|
272
|
-
let ws = null;
|
|
273
|
-
let destroyed = false;
|
|
274
|
-
let connectionReady = false;
|
|
275
|
-
let reconnectAttempts = 0;
|
|
276
|
-
let reconnectTimer = null;
|
|
277
|
-
const pendingOutbound = [];
|
|
278
|
-
const channels = /* @__PURE__ */ new Map();
|
|
279
|
-
function ensureChannel(opts) {
|
|
280
|
-
const existing = channels.get(opts.sessionId);
|
|
281
|
-
if (existing) return existing;
|
|
282
|
-
const state = {
|
|
283
|
-
sessionId: opts.sessionId,
|
|
284
|
-
metadata: opts.metadata,
|
|
285
|
-
ready: false,
|
|
286
|
-
readyHandlers: /* @__PURE__ */ new Set(),
|
|
287
|
-
messageHandlers: /* @__PURE__ */ new Set(),
|
|
288
|
-
registered: false,
|
|
289
|
-
transport: null
|
|
290
|
-
};
|
|
291
|
-
state.transport = {
|
|
292
|
-
send(msg) {
|
|
293
|
-
if (destroyed) return;
|
|
294
|
-
const stamped = {
|
|
295
|
-
...msg,
|
|
296
|
-
sessionId: state.sessionId
|
|
297
|
-
};
|
|
298
|
-
if (ws && ws.readyState === WebSocket.OPEN && state.registered) {
|
|
299
|
-
ws.send(JSON.stringify(stamped));
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
pendingOutbound.push(stamped);
|
|
303
|
-
},
|
|
304
|
-
onMessage(handler) {
|
|
305
|
-
state.messageHandlers.add(handler);
|
|
306
|
-
return () => {
|
|
307
|
-
state.messageHandlers.delete(handler);
|
|
308
|
-
};
|
|
309
|
-
},
|
|
310
|
-
destroy() {
|
|
311
|
-
state.messageHandlers.clear();
|
|
312
|
-
state.readyHandlers.clear();
|
|
313
|
-
channels.delete(state.sessionId);
|
|
314
|
-
},
|
|
315
|
-
get ready() {
|
|
316
|
-
return state.ready;
|
|
317
|
-
},
|
|
318
|
-
onReady(handler) {
|
|
319
|
-
state.readyHandlers.add(handler);
|
|
320
|
-
if (state.ready) handler();
|
|
321
|
-
return () => {
|
|
322
|
-
state.readyHandlers.delete(handler);
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
channels.set(state.sessionId, state);
|
|
327
|
-
if (connectionReady && ws && ws.readyState === WebSocket.OPEN) registerChannel(state);
|
|
328
|
-
return state;
|
|
329
|
-
}
|
|
330
|
-
function registerChannel(state) {
|
|
331
|
-
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
332
|
-
if (state.registered) return;
|
|
333
|
-
if (state.sessionId === primarySessionId) return;
|
|
334
|
-
ws.send(JSON.stringify({
|
|
335
|
-
type: "@statelyai.addSession",
|
|
336
|
-
sessionId: state.sessionId,
|
|
337
|
-
...state.metadata && { metadata: state.metadata }
|
|
338
|
-
}));
|
|
339
|
-
}
|
|
340
|
-
function markChannelReady(sessionId) {
|
|
341
|
-
const state = channels.get(sessionId);
|
|
342
|
-
if (!state || state.ready) return;
|
|
343
|
-
state.ready = true;
|
|
344
|
-
state.registered = true;
|
|
345
|
-
state.readyHandlers.forEach((fn) => fn());
|
|
346
|
-
flushPending();
|
|
347
|
-
}
|
|
348
|
-
function flushPending() {
|
|
349
|
-
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
350
|
-
const remaining = [];
|
|
351
|
-
for (const msg of pendingOutbound) {
|
|
352
|
-
const sessionId = msg.sessionId ?? primarySessionId;
|
|
353
|
-
const state = channels.get(sessionId);
|
|
354
|
-
if (state && state.registered) ws.send(JSON.stringify(msg));
|
|
355
|
-
else remaining.push(msg);
|
|
356
|
-
}
|
|
357
|
-
pendingOutbound.length = 0;
|
|
358
|
-
pendingOutbound.push(...remaining);
|
|
359
|
-
}
|
|
360
|
-
function connect() {
|
|
361
|
-
if (destroyed) return;
|
|
362
|
-
ws = new WebSocket(url);
|
|
363
|
-
ws.onopen = () => {
|
|
364
|
-
reconnectAttempts = 0;
|
|
365
|
-
ws.send(JSON.stringify({
|
|
366
|
-
type: "@statelyai.register",
|
|
367
|
-
protocolVersion: INSPECTION_PROTOCOL_VERSION,
|
|
368
|
-
role,
|
|
369
|
-
sessionId: primarySessionId,
|
|
370
|
-
...primaryMetadata && { metadata: primaryMetadata }
|
|
371
|
-
}));
|
|
372
|
-
};
|
|
373
|
-
ws.onmessage = (event) => {
|
|
374
|
-
if (destroyed) return;
|
|
375
|
-
let raw;
|
|
376
|
-
try {
|
|
377
|
-
raw = JSON.parse(event.data);
|
|
378
|
-
} catch {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
if (!raw?.type || typeof raw.type !== "string") return;
|
|
382
|
-
if (!raw.type.startsWith(PREFIX)) return;
|
|
383
|
-
const data = raw;
|
|
384
|
-
if (data.type === "@statelyai.registered") {
|
|
385
|
-
connectionReady = true;
|
|
386
|
-
markChannelReady(primarySessionId);
|
|
387
|
-
for (const state of channels.values()) if (!state.registered && state.sessionId !== primarySessionId) registerChannel(state);
|
|
388
|
-
flushPending();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
if (data.type === "@statelyai.sessionAdded") {
|
|
392
|
-
const added = data.sessionId;
|
|
393
|
-
if (added) markChannelReady(added);
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
const sessionId = raw.sessionId ?? primarySessionId;
|
|
397
|
-
const state = channels.get(sessionId);
|
|
398
|
-
if (state) state.messageHandlers.forEach((fn) => fn(data));
|
|
399
|
-
};
|
|
400
|
-
ws.onclose = () => {
|
|
401
|
-
if (destroyed) return;
|
|
402
|
-
connectionReady = false;
|
|
403
|
-
for (const state of channels.values()) {
|
|
404
|
-
state.ready = false;
|
|
405
|
-
state.registered = false;
|
|
406
|
-
}
|
|
407
|
-
if (reconnect && reconnectAttempts < maxReconnectAttempts) {
|
|
408
|
-
const delay = Math.min(1e3 * 2 ** reconnectAttempts, 3e4);
|
|
409
|
-
reconnectAttempts++;
|
|
410
|
-
reconnectTimer = setTimeout(connect, delay);
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
ws.onerror = () => {};
|
|
414
|
-
}
|
|
415
|
-
ensureChannel({
|
|
416
|
-
sessionId: primarySessionId,
|
|
417
|
-
metadata: primaryMetadata
|
|
418
|
-
});
|
|
419
|
-
connect();
|
|
420
|
-
return {
|
|
421
|
-
openChannel(opts) {
|
|
422
|
-
return ensureChannel(opts).transport;
|
|
423
|
-
},
|
|
424
|
-
destroy() {
|
|
425
|
-
if (destroyed) return;
|
|
426
|
-
destroyed = true;
|
|
427
|
-
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
428
|
-
ws?.close();
|
|
429
|
-
ws = null;
|
|
430
|
-
for (const state of channels.values()) {
|
|
431
|
-
state.messageHandlers.clear();
|
|
432
|
-
state.readyHandlers.clear();
|
|
433
|
-
}
|
|
434
|
-
channels.clear();
|
|
435
|
-
pendingOutbound.length = 0;
|
|
436
|
-
},
|
|
437
|
-
get ready() {
|
|
438
|
-
return connectionReady;
|
|
295
|
+
return () => readyHandlers.delete(handler);
|
|
439
296
|
},
|
|
440
|
-
|
|
441
|
-
|
|
297
|
+
onError(handler) {
|
|
298
|
+
errorHandlers.add(handler);
|
|
299
|
+
return () => errorHandlers.delete(handler);
|
|
442
300
|
}
|
|
443
301
|
};
|
|
444
302
|
}
|
|
445
303
|
|
|
446
304
|
//#endregion
|
|
447
|
-
export {
|
|
305
|
+
export { toInitMessage as a, createPendingExportManager as i, createWebSocketTransport as n, createEventRegistry as r, createPostMessageTransport as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"bin": {
|
|
6
|
+
"stately-sdk": "./dist/bin.mjs"
|
|
7
|
+
},
|
|
5
8
|
"files": [
|
|
6
9
|
"dist",
|
|
7
10
|
"schemas"
|
|
@@ -62,6 +65,10 @@
|
|
|
62
65
|
"types": "./dist/relay.d.mts",
|
|
63
66
|
"import": "./dist/relay.mjs"
|
|
64
67
|
},
|
|
68
|
+
"./node-relay": {
|
|
69
|
+
"types": "./dist/node-relay.d.mts",
|
|
70
|
+
"import": "./dist/node-relay.mjs"
|
|
71
|
+
},
|
|
65
72
|
"./statelyai.schema.json": "./schemas/statelyai.schema.json",
|
|
66
73
|
"./schemas/statelyai.schema.json": "./schemas/statelyai.schema.json",
|
|
67
74
|
"./xstate.schema.json": "./schemas/xstate.schema.json",
|
|
@@ -73,20 +80,25 @@
|
|
|
73
80
|
"@statelyai/graph": "^1.0.0",
|
|
74
81
|
"esbuild": "^0.27.0",
|
|
75
82
|
"typescript": "^5.9.3",
|
|
83
|
+
"ws": "^8.19.0",
|
|
76
84
|
"xstate": "^5.0.0"
|
|
77
85
|
},
|
|
78
86
|
"devDependencies": {
|
|
79
87
|
"@types/json-schema": "^7.0.15",
|
|
88
|
+
"@types/ws": "^8.18.1",
|
|
80
89
|
"jsdom": "^27.4.0",
|
|
81
90
|
"tsdown": "0.21.0-beta.2",
|
|
82
91
|
"vitest": "^3.2.4",
|
|
83
|
-
"
|
|
92
|
+
"@statelyai/api-contract": "0.0.1",
|
|
84
93
|
"@statelyai/graph-tools": "0.0.7"
|
|
85
94
|
},
|
|
95
|
+
"engines": {
|
|
96
|
+
"node": ">=22.4"
|
|
97
|
+
},
|
|
86
98
|
"scripts": {
|
|
87
99
|
"build": "tsdown",
|
|
88
100
|
"test": "vitest run",
|
|
89
|
-
"test:live": "vitest run
|
|
101
|
+
"test:live": "vitest run --config vitest.live.config.ts",
|
|
90
102
|
"test:watch": "vitest"
|
|
91
103
|
}
|
|
92
104
|
}
|