iii-sdk 0.21.7-next.1 → 0.21.8-next.2

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.
Files changed (53) hide show
  1. package/dist/channel.cjs +1 -1
  2. package/dist/channel.d.cts +1 -1
  3. package/dist/channel.d.mts +1 -1
  4. package/dist/channel.mjs +1 -1
  5. package/dist/{channels-DfBRsGN1.cjs → channels-C2ezAJ_g.cjs} +4 -3
  6. package/dist/channels-C2ezAJ_g.cjs.map +1 -0
  7. package/dist/{channels-D3WzAo7Z.mjs → channels-C4f7nfQr.mjs} +4 -3
  8. package/dist/channels-C4f7nfQr.mjs.map +1 -0
  9. package/dist/engine.cjs +1 -1
  10. package/dist/engine.d.cts +1 -1
  11. package/dist/engine.d.mts +1 -1
  12. package/dist/engine.mjs +1 -1
  13. package/dist/helpers.cjs +1 -1
  14. package/dist/helpers.d.cts +1 -1
  15. package/dist/helpers.d.mts +1 -1
  16. package/dist/helpers.mjs +1 -1
  17. package/dist/{iii-constants-Br94RUNi.cjs → iii-constants-M_BGfxGD.cjs} +25 -1
  18. package/dist/{iii-constants-_k3SoHry.mjs.map → iii-constants-M_BGfxGD.cjs.map} +1 -1
  19. package/dist/{iii-constants-_k3SoHry.mjs → iii-constants-TIcoyiOl.mjs} +8 -2
  20. package/dist/{iii-constants-Br94RUNi.cjs.map → iii-constants-TIcoyiOl.mjs.map} +1 -1
  21. package/dist/{iii-types-6aHBgy7l.cjs → iii-types-BvaIabiX.cjs} +2 -1
  22. package/dist/iii-types-BvaIabiX.cjs.map +1 -0
  23. package/dist/{iii-types-CRx2qAjB.mjs → iii-types-wPYrg7hX.mjs} +2 -1
  24. package/dist/iii-types-wPYrg7hX.mjs.map +1 -0
  25. package/dist/index.cjs +43 -5
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +1 -1
  28. package/dist/index.d.cts.map +1 -1
  29. package/dist/index.d.mts +1 -1
  30. package/dist/index.d.mts.map +1 -1
  31. package/dist/index.mjs +43 -5
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/internal.d.cts +1 -1
  34. package/dist/internal.d.mts +1 -1
  35. package/dist/protocol.cjs +1 -1
  36. package/dist/protocol.d.cts +1 -1
  37. package/dist/protocol.d.mts +1 -1
  38. package/dist/protocol.mjs +1 -1
  39. package/dist/runtime.d.cts +1 -1
  40. package/dist/runtime.d.mts +1 -1
  41. package/dist/trigger.d.cts +1 -1
  42. package/dist/trigger.d.mts +1 -1
  43. package/dist/{types-Bl-ha_EI.d.mts → types-BQJauFOT.d.cts} +4 -3
  44. package/dist/types-BQJauFOT.d.cts.map +1 -0
  45. package/dist/{types-CoEglURT.d.cts → types-CZ6tnyUT.d.mts} +4 -3
  46. package/dist/types-CZ6tnyUT.d.mts.map +1 -0
  47. package/package.json +2 -2
  48. package/dist/channels-D3WzAo7Z.mjs.map +0 -1
  49. package/dist/channels-DfBRsGN1.cjs.map +0 -1
  50. package/dist/iii-types-6aHBgy7l.cjs.map +0 -1
  51. package/dist/iii-types-CRx2qAjB.mjs.map +0 -1
  52. package/dist/types-Bl-ha_EI.d.mts.map +0 -1
  53. package/dist/types-CoEglURT.d.cts.map +0 -1
package/dist/channel.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_channels = require('./channels-DfBRsGN1.cjs');
2
+ const require_channels = require('./channels-C2ezAJ_g.cjs');
3
3
 
4
4
  exports.ChannelReader = require_channels.ChannelReader;
5
5
  exports.ChannelWriter = require_channels.ChannelWriter;
@@ -1,2 +1,2 @@
1
- import { O as StreamChannelRef, t as Channel, v as ChannelReader, y as ChannelWriter } from "./types-CoEglURT.cjs";
1
+ import { O as StreamChannelRef, t as Channel, v as ChannelReader, y as ChannelWriter } from "./types-BQJauFOT.cjs";
2
2
  export { type Channel, ChannelReader, ChannelWriter, type StreamChannelRef };
@@ -1,2 +1,2 @@
1
- import { O as StreamChannelRef, t as Channel, v as ChannelReader, y as ChannelWriter } from "./types-Bl-ha_EI.mjs";
1
+ import { O as StreamChannelRef, t as Channel, v as ChannelReader, y as ChannelWriter } from "./types-CZ6tnyUT.mjs";
2
2
  export { type Channel, ChannelReader, ChannelWriter, type StreamChannelRef };
package/dist/channel.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { i as ChannelWriter, r as ChannelReader } from "./channels-D3WzAo7Z.mjs";
1
+ import { i as ChannelWriter, r as ChannelReader } from "./channels-C4f7nfQr.mjs";
2
2
 
3
3
  export { ChannelReader, ChannelWriter };
@@ -1,4 +1,5 @@
1
1
  const require_utils = require('./utils-63wxBJg-.cjs');
2
+ const require_iii_constants = require('./iii-constants-M_BGfxGD.cjs');
2
3
  let ws = require("ws");
3
4
  let node_stream = require("node:stream");
4
5
 
@@ -79,7 +80,7 @@ var ChannelWriter = class ChannelWriter {
79
80
  ensureConnected() {
80
81
  if (this.ws && this.ws.readyState !== ws.WebSocket.CLOSING && this.ws.readyState !== ws.WebSocket.CLOSED) return;
81
82
  this.wsReady = false;
82
- this.ws = new ws.WebSocket(this.url);
83
+ this.ws = new ws.WebSocket(this.url, { handshakeTimeout: require_iii_constants.WS_HANDSHAKE_TIMEOUT_MS });
83
84
  this.ws.on("open", () => {
84
85
  this.wsReady = true;
85
86
  for (const { data, callback } of this.pendingMessages) this.ws?.send(data, callback);
@@ -182,7 +183,7 @@ var ChannelReader = class {
182
183
  ensureConnected() {
183
184
  if (this.connected) return;
184
185
  this.connected = true;
185
- this.ws = new ws.WebSocket(this.url);
186
+ this.ws = new ws.WebSocket(this.url, { handshakeTimeout: require_iii_constants.WS_HANDSHAKE_TIMEOUT_MS });
186
187
  this.ws.on("open", () => {
187
188
  this.ws.binaryType = "nodebuffer";
188
189
  });
@@ -245,4 +246,4 @@ Object.defineProperty(exports, 'ChannelWriter', {
245
246
  return ChannelWriter;
246
247
  }
247
248
  });
248
- //# sourceMappingURL=channels-DfBRsGN1.cjs.map
249
+ //# sourceMappingURL=channels-C2ezAJ_g.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels-C2ezAJ_g.cjs","names":["Writable","WebSocket","WS_HANDSHAKE_TIMEOUT_MS","Readable"],"sources":["../src/channels.ts"],"sourcesContent":["import { Readable, Writable } from 'node:stream'\nimport { WebSocket } from 'ws'\nimport { WS_HANDSHAKE_TIMEOUT_MS } from './iii-constants'\nimport type { StreamChannelRef } from './iii-types'\n\n/**\n * Direction of a streaming channel endpoint. Mirrors the Rust SDK's\n * `ChannelDirection` enum and matches the literal values used by\n * {@link StreamChannelRef.direction}.\n */\nexport const ChannelDirection = {\n Read: 'read',\n Write: 'write',\n} as const\nexport type ChannelDirection = (typeof ChannelDirection)[keyof typeof ChannelDirection]\n\n/**\n * Discriminated runtime tag for an item observed on a streaming channel.\n * Mirrors the Rust SDK's `ChannelItem` enum (`Text` / `Binary`). Carrier for\n * factory + type-guard helpers so callers can construct and discriminate\n * channel items without depending on Rust-specific shape.\n */\nexport type ChannelItem =\n | { type: 'text'; value: string }\n | { type: 'binary'; value: Uint8Array }\n\nexport const ChannelItem = {\n /** Construct a text channel item. */\n Text(value: string): ChannelItem {\n return { type: 'text', value }\n },\n /** Construct a binary channel item. */\n Binary(value: Uint8Array): ChannelItem {\n return { type: 'binary', value }\n },\n} as const\n\n/**\n * Write end of a streaming channel. Provides both a Node.js `Writable` stream\n * and a `sendMessage` method for sending structured text messages.\n *\n * @example\n * ```typescript\n * import { createChannel } from 'iii-sdk/helpers'\n * const channel = await createChannel(iii)\n *\n * // Stream binary data\n * channel.writer.stream.write(Buffer.from('hello'))\n * channel.writer.stream.end()\n *\n * // Or send text messages\n * channel.writer.sendMessage(JSON.stringify({ type: 'event', data: 'test' }))\n * channel.writer.close()\n * ```\n */\nexport class ChannelWriter {\n private static readonly FRAME_SIZE = 64 * 1024\n private ws: WebSocket | null = null\n private wsReady = false\n private readonly pendingMessages: {\n data: Buffer | string\n callback: (err?: Error | null) => void\n }[] = []\n /** Node.js Writable stream for binary data. */\n public readonly stream: Writable\n private readonly url: string\n\n constructor(engineWsBase: string, ref: StreamChannelRef) {\n this.url = buildChannelUrl(engineWsBase, ref.channel_id, ref.access_key, 'write')\n\n this.stream = new Writable({\n write: (chunk: Buffer, _encoding, callback) => {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n this.sendChunked(buf, callback)\n },\n final: (callback) => {\n if (!this.ws) {\n callback()\n return\n }\n // Delay the close frame slightly to allow the TCP stack to flush\n // all buffered send() data. Without this, the close frame can arrive\n // at the engine before all data frames, causing data truncation.\n const doClose = () => {\n if (this.ws) {\n this.ws.close(1000, 'stream_complete')\n }\n callback()\n }\n if (this.wsReady) {\n setTimeout(doClose, 10)\n } else {\n this.ws.on('open', () => setTimeout(doClose, 10))\n }\n },\n destroy: (err, callback) => {\n if (this.ws) this.ws.terminate()\n callback(err)\n },\n })\n }\n\n private ensureConnected(): void {\n // A non-null socket is only reusable while it is still connecting or open.\n // A CLOSING/CLOSED socket is dead and must be replaced — guarding solely on\n // `this.ws` being non-null would pin a terminated socket forever, so every\n // subsequent send would target a connection that can never deliver it.\n if (\n this.ws &&\n this.ws.readyState !== WebSocket.CLOSING &&\n this.ws.readyState !== WebSocket.CLOSED\n ) {\n return\n }\n this.wsReady = false\n this.ws = new WebSocket(this.url, { handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS })\n\n this.ws.on('open', () => {\n this.wsReady = true\n for (const { data, callback } of this.pendingMessages) {\n this.ws?.send(data, callback)\n }\n this.pendingMessages.length = 0\n })\n\n this.ws.on('error', (err) => {\n this.wsReady = false\n this.stream.destroy(err)\n })\n\n this.ws.on('close', () => {\n this.wsReady = false\n if (!this.stream.destroyed) {\n this.stream.destroy()\n }\n })\n }\n\n /** Send a text message through the channel. */\n sendMessage(msg: string): void {\n this.ensureConnected()\n this.sendRaw(msg, (err) => {\n if (err) this.stream.destroy(err)\n })\n }\n\n /** Close the channel writer. */\n close(): void {\n if (!this.ws) return\n const doClose = () => {\n if (this.ws) {\n this.ws.close(1000, 'channel_close')\n }\n }\n if (this.wsReady) {\n doClose()\n } else {\n this.ws.on('open', () => doClose())\n }\n }\n\n private sendChunked(data: Buffer, callback: (err?: Error | null) => void): void {\n let offset = 0\n const sendNext = (err?: Error | null): void => {\n if (err) {\n callback(err)\n return\n }\n\n if (offset >= data.length) {\n callback(null)\n return\n }\n\n const end = Math.min(offset + ChannelWriter.FRAME_SIZE, data.length)\n const part = data.subarray(offset, end)\n offset = end\n this.sendRaw(part, sendNext)\n }\n sendNext(null)\n }\n\n private sendRaw(data: Buffer | string, callback: (err?: Error | null) => void): void {\n this.ensureConnected()\n // Trust the socket's live readyState over the tracked `wsReady` flag, which\n // can stay true after a drop. Queue anything we cannot send right now — and\n // requeue a send() that throws because the socket died underneath us — so it\n // flushes on the next open instead of being lost or throwing to the caller.\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.send(data, (err) => callback(err ?? null))\n } catch {\n this.pendingMessages.push({ data, callback })\n }\n } else {\n this.pendingMessages.push({ data, callback })\n }\n }\n}\n\n/**\n * Read end of a streaming channel. Provides both a Node.js `Readable` stream\n * for binary data and an `onMessage` callback for structured text messages.\n *\n * @example\n * ```typescript\n * import { createChannel } from 'iii-sdk/helpers'\n * const channel = await createChannel(iii)\n *\n * // Stream binary data\n * channel.reader.stream.on('data', (chunk) => console.log(chunk))\n *\n * // Or receive text messages\n * channel.reader.onMessage((msg) => console.log('Got:', msg))\n * ```\n */\nexport class ChannelReader {\n private ws: WebSocket | null = null\n private connected = false\n private readonly messageCallbacks: Array<(msg: string) => void> = []\n /** Node.js Readable stream for binary data. */\n public readonly stream: Readable\n private readonly url: string\n\n constructor(engineWsBase: string, ref: StreamChannelRef) {\n this.url = buildChannelUrl(engineWsBase, ref.channel_id, ref.access_key, 'read')\n\n const self = this\n this.stream = new Readable({\n read() {\n self.ensureConnected()\n if (self.ws) self.ws.resume()\n },\n destroy(err, callback) {\n if (self.ws && self.ws.readyState !== WebSocket.CLOSED) {\n self.ws.terminate()\n }\n self.ws = null\n callback(err)\n },\n })\n }\n\n private ensureConnected(): void {\n if (this.connected) return\n this.connected = true\n this.ws = new WebSocket(this.url, { handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS })\n\n this.ws.on('open', () => {\n ;(this.ws as unknown as { binaryType: string }).binaryType = 'nodebuffer'\n })\n\n this.ws.on('message', (data: Buffer, isBinary: boolean) => {\n if (isBinary) {\n if (!this.stream.push(data)) {\n this.ws?.pause()\n }\n } else {\n const msg = data.toString('utf-8')\n for (const cb of this.messageCallbacks) {\n cb(msg)\n }\n }\n })\n\n this.ws.on('close', () => {\n this.ws = null\n if (!this.stream.destroyed) this.stream.push(null)\n })\n\n this.ws.on('error', (err) => {\n this.stream.destroy(err)\n })\n }\n\n /** Register a callback to receive text messages from the channel. */\n onMessage(callback: (msg: string) => void): void {\n this.messageCallbacks.push(callback)\n }\n\n async readAll(): Promise<Buffer> {\n this.ensureConnected()\n const chunks: Buffer[] = []\n\n for await (const chunk of this.stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n\n return Buffer.concat(chunks)\n }\n\n close(): void {\n if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {\n this.ws.close(1000, 'channel_close')\n }\n }\n}\n\nfunction buildChannelUrl(\n engineWsBase: string,\n channelId: string,\n accessKey: string,\n direction: 'read' | 'write',\n): string {\n const base = engineWsBase.replace(/\\/$/, '')\n return `${base}/ws/channels/${channelId}?key=${encodeURIComponent(accessKey)}&dir=${direction}`\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { a as WS_HANDSHAKE_TIMEOUT_MS } from "./iii-constants-TIcoyiOl.mjs";
1
2
  import { WebSocket } from "ws";
2
3
  import { Readable, Writable } from "node:stream";
3
4
 
@@ -78,7 +79,7 @@ var ChannelWriter = class ChannelWriter {
78
79
  ensureConnected() {
79
80
  if (this.ws && this.ws.readyState !== WebSocket.CLOSING && this.ws.readyState !== WebSocket.CLOSED) return;
80
81
  this.wsReady = false;
81
- this.ws = new WebSocket(this.url);
82
+ this.ws = new WebSocket(this.url, { handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS });
82
83
  this.ws.on("open", () => {
83
84
  this.wsReady = true;
84
85
  for (const { data, callback } of this.pendingMessages) this.ws?.send(data, callback);
@@ -181,7 +182,7 @@ var ChannelReader = class {
181
182
  ensureConnected() {
182
183
  if (this.connected) return;
183
184
  this.connected = true;
184
- this.ws = new WebSocket(this.url);
185
+ this.ws = new WebSocket(this.url, { handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS });
185
186
  this.ws.on("open", () => {
186
187
  this.ws.binaryType = "nodebuffer";
187
188
  });
@@ -221,4 +222,4 @@ function buildChannelUrl(engineWsBase, channelId, accessKey, direction) {
221
222
 
222
223
  //#endregion
223
224
  export { ChannelWriter as i, ChannelItem as n, ChannelReader as r, ChannelDirection as t };
224
- //# sourceMappingURL=channels-D3WzAo7Z.mjs.map
225
+ //# sourceMappingURL=channels-C4f7nfQr.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels-C4f7nfQr.mjs","names":[],"sources":["../src/channels.ts"],"sourcesContent":["import { Readable, Writable } from 'node:stream'\nimport { WebSocket } from 'ws'\nimport { WS_HANDSHAKE_TIMEOUT_MS } from './iii-constants'\nimport type { StreamChannelRef } from './iii-types'\n\n/**\n * Direction of a streaming channel endpoint. Mirrors the Rust SDK's\n * `ChannelDirection` enum and matches the literal values used by\n * {@link StreamChannelRef.direction}.\n */\nexport const ChannelDirection = {\n Read: 'read',\n Write: 'write',\n} as const\nexport type ChannelDirection = (typeof ChannelDirection)[keyof typeof ChannelDirection]\n\n/**\n * Discriminated runtime tag for an item observed on a streaming channel.\n * Mirrors the Rust SDK's `ChannelItem` enum (`Text` / `Binary`). Carrier for\n * factory + type-guard helpers so callers can construct and discriminate\n * channel items without depending on Rust-specific shape.\n */\nexport type ChannelItem =\n | { type: 'text'; value: string }\n | { type: 'binary'; value: Uint8Array }\n\nexport const ChannelItem = {\n /** Construct a text channel item. */\n Text(value: string): ChannelItem {\n return { type: 'text', value }\n },\n /** Construct a binary channel item. */\n Binary(value: Uint8Array): ChannelItem {\n return { type: 'binary', value }\n },\n} as const\n\n/**\n * Write end of a streaming channel. Provides both a Node.js `Writable` stream\n * and a `sendMessage` method for sending structured text messages.\n *\n * @example\n * ```typescript\n * import { createChannel } from 'iii-sdk/helpers'\n * const channel = await createChannel(iii)\n *\n * // Stream binary data\n * channel.writer.stream.write(Buffer.from('hello'))\n * channel.writer.stream.end()\n *\n * // Or send text messages\n * channel.writer.sendMessage(JSON.stringify({ type: 'event', data: 'test' }))\n * channel.writer.close()\n * ```\n */\nexport class ChannelWriter {\n private static readonly FRAME_SIZE = 64 * 1024\n private ws: WebSocket | null = null\n private wsReady = false\n private readonly pendingMessages: {\n data: Buffer | string\n callback: (err?: Error | null) => void\n }[] = []\n /** Node.js Writable stream for binary data. */\n public readonly stream: Writable\n private readonly url: string\n\n constructor(engineWsBase: string, ref: StreamChannelRef) {\n this.url = buildChannelUrl(engineWsBase, ref.channel_id, ref.access_key, 'write')\n\n this.stream = new Writable({\n write: (chunk: Buffer, _encoding, callback) => {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n this.sendChunked(buf, callback)\n },\n final: (callback) => {\n if (!this.ws) {\n callback()\n return\n }\n // Delay the close frame slightly to allow the TCP stack to flush\n // all buffered send() data. Without this, the close frame can arrive\n // at the engine before all data frames, causing data truncation.\n const doClose = () => {\n if (this.ws) {\n this.ws.close(1000, 'stream_complete')\n }\n callback()\n }\n if (this.wsReady) {\n setTimeout(doClose, 10)\n } else {\n this.ws.on('open', () => setTimeout(doClose, 10))\n }\n },\n destroy: (err, callback) => {\n if (this.ws) this.ws.terminate()\n callback(err)\n },\n })\n }\n\n private ensureConnected(): void {\n // A non-null socket is only reusable while it is still connecting or open.\n // A CLOSING/CLOSED socket is dead and must be replaced — guarding solely on\n // `this.ws` being non-null would pin a terminated socket forever, so every\n // subsequent send would target a connection that can never deliver it.\n if (\n this.ws &&\n this.ws.readyState !== WebSocket.CLOSING &&\n this.ws.readyState !== WebSocket.CLOSED\n ) {\n return\n }\n this.wsReady = false\n this.ws = new WebSocket(this.url, { handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS })\n\n this.ws.on('open', () => {\n this.wsReady = true\n for (const { data, callback } of this.pendingMessages) {\n this.ws?.send(data, callback)\n }\n this.pendingMessages.length = 0\n })\n\n this.ws.on('error', (err) => {\n this.wsReady = false\n this.stream.destroy(err)\n })\n\n this.ws.on('close', () => {\n this.wsReady = false\n if (!this.stream.destroyed) {\n this.stream.destroy()\n }\n })\n }\n\n /** Send a text message through the channel. */\n sendMessage(msg: string): void {\n this.ensureConnected()\n this.sendRaw(msg, (err) => {\n if (err) this.stream.destroy(err)\n })\n }\n\n /** Close the channel writer. */\n close(): void {\n if (!this.ws) return\n const doClose = () => {\n if (this.ws) {\n this.ws.close(1000, 'channel_close')\n }\n }\n if (this.wsReady) {\n doClose()\n } else {\n this.ws.on('open', () => doClose())\n }\n }\n\n private sendChunked(data: Buffer, callback: (err?: Error | null) => void): void {\n let offset = 0\n const sendNext = (err?: Error | null): void => {\n if (err) {\n callback(err)\n return\n }\n\n if (offset >= data.length) {\n callback(null)\n return\n }\n\n const end = Math.min(offset + ChannelWriter.FRAME_SIZE, data.length)\n const part = data.subarray(offset, end)\n offset = end\n this.sendRaw(part, sendNext)\n }\n sendNext(null)\n }\n\n private sendRaw(data: Buffer | string, callback: (err?: Error | null) => void): void {\n this.ensureConnected()\n // Trust the socket's live readyState over the tracked `wsReady` flag, which\n // can stay true after a drop. Queue anything we cannot send right now — and\n // requeue a send() that throws because the socket died underneath us — so it\n // flushes on the next open instead of being lost or throwing to the caller.\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.send(data, (err) => callback(err ?? null))\n } catch {\n this.pendingMessages.push({ data, callback })\n }\n } else {\n this.pendingMessages.push({ data, callback })\n }\n }\n}\n\n/**\n * Read end of a streaming channel. Provides both a Node.js `Readable` stream\n * for binary data and an `onMessage` callback for structured text messages.\n *\n * @example\n * ```typescript\n * import { createChannel } from 'iii-sdk/helpers'\n * const channel = await createChannel(iii)\n *\n * // Stream binary data\n * channel.reader.stream.on('data', (chunk) => console.log(chunk))\n *\n * // Or receive text messages\n * channel.reader.onMessage((msg) => console.log('Got:', msg))\n * ```\n */\nexport class ChannelReader {\n private ws: WebSocket | null = null\n private connected = false\n private readonly messageCallbacks: Array<(msg: string) => void> = []\n /** Node.js Readable stream for binary data. */\n public readonly stream: Readable\n private readonly url: string\n\n constructor(engineWsBase: string, ref: StreamChannelRef) {\n this.url = buildChannelUrl(engineWsBase, ref.channel_id, ref.access_key, 'read')\n\n const self = this\n this.stream = new Readable({\n read() {\n self.ensureConnected()\n if (self.ws) self.ws.resume()\n },\n destroy(err, callback) {\n if (self.ws && self.ws.readyState !== WebSocket.CLOSED) {\n self.ws.terminate()\n }\n self.ws = null\n callback(err)\n },\n })\n }\n\n private ensureConnected(): void {\n if (this.connected) return\n this.connected = true\n this.ws = new WebSocket(this.url, { handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS })\n\n this.ws.on('open', () => {\n ;(this.ws as unknown as { binaryType: string }).binaryType = 'nodebuffer'\n })\n\n this.ws.on('message', (data: Buffer, isBinary: boolean) => {\n if (isBinary) {\n if (!this.stream.push(data)) {\n this.ws?.pause()\n }\n } else {\n const msg = data.toString('utf-8')\n for (const cb of this.messageCallbacks) {\n cb(msg)\n }\n }\n })\n\n this.ws.on('close', () => {\n this.ws = null\n if (!this.stream.destroyed) this.stream.push(null)\n })\n\n this.ws.on('error', (err) => {\n this.stream.destroy(err)\n })\n }\n\n /** Register a callback to receive text messages from the channel. */\n onMessage(callback: (msg: string) => void): void {\n this.messageCallbacks.push(callback)\n }\n\n async readAll(): Promise<Buffer> {\n this.ensureConnected()\n const chunks: Buffer[] = []\n\n for await (const chunk of this.stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n\n return Buffer.concat(chunks)\n }\n\n close(): void {\n if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {\n this.ws.close(1000, 'channel_close')\n }\n }\n}\n\nfunction buildChannelUrl(\n engineWsBase: string,\n channelId: string,\n accessKey: string,\n direction: 'read' | 'write',\n): string {\n const base = engineWsBase.replace(/\\/$/, '')\n return `${base}/ws/channels/${channelId}?key=${encodeURIComponent(accessKey)}&dir=${direction}`\n}\n"],"mappings":"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"}
package/dist/engine.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_iii_constants = require('./iii-constants-Br94RUNi.cjs');
2
+ const require_iii_constants = require('./iii-constants-M_BGfxGD.cjs');
3
3
 
4
4
  exports.EngineFunctions = require_iii_constants.EngineFunctions;
5
5
  exports.EngineTriggers = require_iii_constants.EngineTriggers;
package/dist/engine.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- import { l as RemoteFunctionHandler } from "./types-CoEglURT.cjs";
1
+ import { l as RemoteFunctionHandler } from "./types-BQJauFOT.cjs";
2
2
  import { n as EngineTriggers, t as EngineFunctions } from "./iii-constants-BqXp8xSN.cjs";
3
3
  export { EngineFunctions, EngineTriggers, type RemoteFunctionHandler };
package/dist/engine.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { l as RemoteFunctionHandler } from "./types-Bl-ha_EI.mjs";
1
+ import { l as RemoteFunctionHandler } from "./types-CZ6tnyUT.mjs";
2
2
  import { n as EngineTriggers, t as EngineFunctions } from "./iii-constants-Baptl8nm.mjs";
3
3
  export { EngineFunctions, EngineTriggers, type RemoteFunctionHandler };
package/dist/engine.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { i as EngineTriggers, r as EngineFunctions } from "./iii-constants-_k3SoHry.mjs";
1
+ import { i as EngineTriggers, r as EngineFunctions } from "./iii-constants-TIcoyiOl.mjs";
2
2
 
3
3
  export { EngineFunctions, EngineTriggers };
package/dist/helpers.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_utils = require('./utils-63wxBJg-.cjs');
3
- const require_channels = require('./channels-DfBRsGN1.cjs');
3
+ const require_channels = require('./channels-C2ezAJ_g.cjs');
4
4
 
5
5
  //#region src/helpers.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { O as StreamChannelRef, _ as ChannelItem, g as ChannelDirection, r as IIIClient, t as Channel } from "./types-CoEglURT.cjs";
1
+ import { O as StreamChannelRef, _ as ChannelItem, g as ChannelDirection, r as IIIClient, t as Channel } from "./types-BQJauFOT.cjs";
2
2
  import { IStream } from "./stream.cjs";
3
3
 
4
4
  //#region src/utils.d.ts
@@ -1,4 +1,4 @@
1
- import { O as StreamChannelRef, _ as ChannelItem, g as ChannelDirection, r as IIIClient, t as Channel } from "./types-Bl-ha_EI.mjs";
1
+ import { O as StreamChannelRef, _ as ChannelItem, g as ChannelDirection, r as IIIClient, t as Channel } from "./types-CZ6tnyUT.mjs";
2
2
  import { IStream } from "./stream.mjs";
3
3
 
4
4
  //#region src/utils.d.ts
package/dist/helpers.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as ChannelItem, t as ChannelDirection } from "./channels-D3WzAo7Z.mjs";
1
+ import { n as ChannelItem, t as ChannelDirection } from "./channels-C4f7nfQr.mjs";
2
2
  import { n as extractChannelRefs, r as isChannelRef } from "./utils-8G4hHqvZ.mjs";
3
3
 
4
4
  //#region src/helpers.ts
@@ -38,6 +38,12 @@ const DEFAULT_BRIDGE_RECONNECTION_CONFIG = {
38
38
  };
39
39
  /** Default invocation timeout in milliseconds */
40
40
  const DEFAULT_INVOCATION_TIMEOUT_MS = 3e4;
41
+ /** WebSocket opening-handshake timeout in ms (parity with Rust SDK connect_timeout, MOT-3857) */
42
+ const WS_HANDSHAKE_TIMEOUT_MS = 1e4;
43
+ /** Client keepalive ping cadence in ms (parity with Rust SDK ping_interval) */
44
+ const WS_PING_INTERVAL_MS = 2e4;
45
+ /** Force reconnect after this long with no inbound frame (parity with Rust SDK idle_timeout) */
46
+ const WS_IDLE_TIMEOUT_MS = 6e4;
41
47
 
42
48
  //#endregion
43
49
  Object.defineProperty(exports, 'DEFAULT_BRIDGE_RECONNECTION_CONFIG', {
@@ -64,4 +70,22 @@ Object.defineProperty(exports, 'EngineTriggers', {
64
70
  return EngineTriggers;
65
71
  }
66
72
  });
67
- //# sourceMappingURL=iii-constants-Br94RUNi.cjs.map
73
+ Object.defineProperty(exports, 'WS_HANDSHAKE_TIMEOUT_MS', {
74
+ enumerable: true,
75
+ get: function () {
76
+ return WS_HANDSHAKE_TIMEOUT_MS;
77
+ }
78
+ });
79
+ Object.defineProperty(exports, 'WS_IDLE_TIMEOUT_MS', {
80
+ enumerable: true,
81
+ get: function () {
82
+ return WS_IDLE_TIMEOUT_MS;
83
+ }
84
+ });
85
+ Object.defineProperty(exports, 'WS_PING_INTERVAL_MS', {
86
+ enumerable: true,
87
+ get: function () {
88
+ return WS_PING_INTERVAL_MS;
89
+ }
90
+ });
91
+ //# sourceMappingURL=iii-constants-M_BGfxGD.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"iii-constants-_k3SoHry.mjs","names":[],"sources":["../src/iii-constants.ts"],"sourcesContent":["/**\n * Constants for the III module.\n */\n\n/**\n * Engine function paths for internal operations.\n *\n * Naming note: `LIST_TRIGGERS` / `INFO_TRIGGERS` cover trigger TYPES\n * (templates). `LIST_REGISTERED_TRIGGERS` / `INFO_REGISTERED_TRIGGERS`\n * cover trigger INSTANCES (subscriber rows). The old\n * `engine::trigger-types::list` builtin has been removed and is now\n * served by `engine::triggers::list`.\n */\nexport const EngineFunctions = {\n LIST_FUNCTIONS: 'engine::functions::list',\n INFO_FUNCTIONS: 'engine::functions::info',\n LIST_WORKERS: 'engine::workers::list',\n INFO_WORKERS: 'engine::workers::info',\n LIST_TRIGGERS: 'engine::triggers::list',\n INFO_TRIGGERS: 'engine::triggers::info',\n LIST_REGISTERED_TRIGGERS: 'engine::registered-triggers::list',\n INFO_REGISTERED_TRIGGERS: 'engine::registered-triggers::info',\n REGISTER_WORKER: 'engine::workers::register',\n} as const\n\n/** Engine trigger types */\nexport const EngineTriggers = {\n FUNCTIONS_AVAILABLE: 'engine::functions-available',\n LOG: 'log',\n} as const\n\n/** Log function paths */\nexport const LogFunctions = {\n INFO: 'engine::log::info',\n WARN: 'engine::log::warn',\n ERROR: 'engine::log::error',\n DEBUG: 'engine::log::debug',\n} as const\n\n/** Connection state for the III WebSocket */\nexport type IIIConnectionState =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface IIIReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_BRIDGE_RECONNECTION_CONFIG: IIIReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Default invocation timeout in milliseconds */\nexport const DEFAULT_INVOCATION_TIMEOUT_MS = 30000\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,kBAAkB;CAC7B,gBAAgB;CAChB,gBAAgB;CAChB,cAAc;CACd,cAAc;CACd,eAAe;CACf,eAAe;CACf,0BAA0B;CAC1B,0BAA0B;CAC1B,iBAAiB;CAClB;;AAGD,MAAa,iBAAiB;CAC5B,qBAAqB;CACrB,KAAK;CACN;;AAiCD,MAAa,qCAA4D;CACvE,gBAAgB;CAChB,YAAY;CACZ,mBAAmB;CACnB,cAAc;CACd,YAAY;CACb;;AAGD,MAAa,gCAAgC"}
1
+ {"version":3,"file":"iii-constants-M_BGfxGD.cjs","names":[],"sources":["../src/iii-constants.ts"],"sourcesContent":["/**\n * Constants for the III module.\n */\n\n/**\n * Engine function paths for internal operations.\n *\n * Naming note: `LIST_TRIGGERS` / `INFO_TRIGGERS` cover trigger TYPES\n * (templates). `LIST_REGISTERED_TRIGGERS` / `INFO_REGISTERED_TRIGGERS`\n * cover trigger INSTANCES (subscriber rows). The old\n * `engine::trigger-types::list` builtin has been removed and is now\n * served by `engine::triggers::list`.\n */\nexport const EngineFunctions = {\n LIST_FUNCTIONS: 'engine::functions::list',\n INFO_FUNCTIONS: 'engine::functions::info',\n LIST_WORKERS: 'engine::workers::list',\n INFO_WORKERS: 'engine::workers::info',\n LIST_TRIGGERS: 'engine::triggers::list',\n INFO_TRIGGERS: 'engine::triggers::info',\n LIST_REGISTERED_TRIGGERS: 'engine::registered-triggers::list',\n INFO_REGISTERED_TRIGGERS: 'engine::registered-triggers::info',\n REGISTER_WORKER: 'engine::workers::register',\n} as const\n\n/** Engine trigger types */\nexport const EngineTriggers = {\n FUNCTIONS_AVAILABLE: 'engine::functions-available',\n LOG: 'log',\n} as const\n\n/** Log function paths */\nexport const LogFunctions = {\n INFO: 'engine::log::info',\n WARN: 'engine::log::warn',\n ERROR: 'engine::log::error',\n DEBUG: 'engine::log::debug',\n} as const\n\n/** Connection state for the III WebSocket */\nexport type IIIConnectionState =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface IIIReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_BRIDGE_RECONNECTION_CONFIG: IIIReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Default invocation timeout in milliseconds */\nexport const DEFAULT_INVOCATION_TIMEOUT_MS = 30000\n\n/** WebSocket opening-handshake timeout in ms (parity with Rust SDK connect_timeout, MOT-3857) */\nexport const WS_HANDSHAKE_TIMEOUT_MS = 10000\n\n/** Client keepalive ping cadence in ms (parity with Rust SDK ping_interval) */\nexport const WS_PING_INTERVAL_MS = 20000\n\n/** Force reconnect after this long with no inbound frame (parity with Rust SDK idle_timeout) */\nexport const WS_IDLE_TIMEOUT_MS = 60000\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAa,kBAAkB;CAC7B,gBAAgB;CAChB,gBAAgB;CAChB,cAAc;CACd,cAAc;CACd,eAAe;CACf,eAAe;CACf,0BAA0B;CAC1B,0BAA0B;CAC1B,iBAAiB;CAClB;;AAGD,MAAa,iBAAiB;CAC5B,qBAAqB;CACrB,KAAK;CACN;;AAiCD,MAAa,qCAA4D;CACvE,gBAAgB;CAChB,YAAY;CACZ,mBAAmB;CACnB,cAAc;CACd,YAAY;CACb;;AAGD,MAAa,gCAAgC;;AAG7C,MAAa,0BAA0B;;AAGvC,MAAa,sBAAsB;;AAGnC,MAAa,qBAAqB"}
@@ -37,7 +37,13 @@ const DEFAULT_BRIDGE_RECONNECTION_CONFIG = {
37
37
  };
38
38
  /** Default invocation timeout in milliseconds */
39
39
  const DEFAULT_INVOCATION_TIMEOUT_MS = 3e4;
40
+ /** WebSocket opening-handshake timeout in ms (parity with Rust SDK connect_timeout, MOT-3857) */
41
+ const WS_HANDSHAKE_TIMEOUT_MS = 1e4;
42
+ /** Client keepalive ping cadence in ms (parity with Rust SDK ping_interval) */
43
+ const WS_PING_INTERVAL_MS = 2e4;
44
+ /** Force reconnect after this long with no inbound frame (parity with Rust SDK idle_timeout) */
45
+ const WS_IDLE_TIMEOUT_MS = 6e4;
40
46
 
41
47
  //#endregion
42
- export { EngineTriggers as i, DEFAULT_INVOCATION_TIMEOUT_MS as n, EngineFunctions as r, DEFAULT_BRIDGE_RECONNECTION_CONFIG as t };
43
- //# sourceMappingURL=iii-constants-_k3SoHry.mjs.map
48
+ export { WS_HANDSHAKE_TIMEOUT_MS as a, EngineTriggers as i, DEFAULT_INVOCATION_TIMEOUT_MS as n, WS_IDLE_TIMEOUT_MS as o, EngineFunctions as r, WS_PING_INTERVAL_MS as s, DEFAULT_BRIDGE_RECONNECTION_CONFIG as t };
49
+ //# sourceMappingURL=iii-constants-TIcoyiOl.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"iii-constants-Br94RUNi.cjs","names":[],"sources":["../src/iii-constants.ts"],"sourcesContent":["/**\n * Constants for the III module.\n */\n\n/**\n * Engine function paths for internal operations.\n *\n * Naming note: `LIST_TRIGGERS` / `INFO_TRIGGERS` cover trigger TYPES\n * (templates). `LIST_REGISTERED_TRIGGERS` / `INFO_REGISTERED_TRIGGERS`\n * cover trigger INSTANCES (subscriber rows). The old\n * `engine::trigger-types::list` builtin has been removed and is now\n * served by `engine::triggers::list`.\n */\nexport const EngineFunctions = {\n LIST_FUNCTIONS: 'engine::functions::list',\n INFO_FUNCTIONS: 'engine::functions::info',\n LIST_WORKERS: 'engine::workers::list',\n INFO_WORKERS: 'engine::workers::info',\n LIST_TRIGGERS: 'engine::triggers::list',\n INFO_TRIGGERS: 'engine::triggers::info',\n LIST_REGISTERED_TRIGGERS: 'engine::registered-triggers::list',\n INFO_REGISTERED_TRIGGERS: 'engine::registered-triggers::info',\n REGISTER_WORKER: 'engine::workers::register',\n} as const\n\n/** Engine trigger types */\nexport const EngineTriggers = {\n FUNCTIONS_AVAILABLE: 'engine::functions-available',\n LOG: 'log',\n} as const\n\n/** Log function paths */\nexport const LogFunctions = {\n INFO: 'engine::log::info',\n WARN: 'engine::log::warn',\n ERROR: 'engine::log::error',\n DEBUG: 'engine::log::debug',\n} as const\n\n/** Connection state for the III WebSocket */\nexport type IIIConnectionState =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface IIIReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_BRIDGE_RECONNECTION_CONFIG: IIIReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Default invocation timeout in milliseconds */\nexport const DEFAULT_INVOCATION_TIMEOUT_MS = 30000\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAa,kBAAkB;CAC7B,gBAAgB;CAChB,gBAAgB;CAChB,cAAc;CACd,cAAc;CACd,eAAe;CACf,eAAe;CACf,0BAA0B;CAC1B,0BAA0B;CAC1B,iBAAiB;CAClB;;AAGD,MAAa,iBAAiB;CAC5B,qBAAqB;CACrB,KAAK;CACN;;AAiCD,MAAa,qCAA4D;CACvE,gBAAgB;CAChB,YAAY;CACZ,mBAAmB;CACnB,cAAc;CACd,YAAY;CACb;;AAGD,MAAa,gCAAgC"}
1
+ {"version":3,"file":"iii-constants-TIcoyiOl.mjs","names":[],"sources":["../src/iii-constants.ts"],"sourcesContent":["/**\n * Constants for the III module.\n */\n\n/**\n * Engine function paths for internal operations.\n *\n * Naming note: `LIST_TRIGGERS` / `INFO_TRIGGERS` cover trigger TYPES\n * (templates). `LIST_REGISTERED_TRIGGERS` / `INFO_REGISTERED_TRIGGERS`\n * cover trigger INSTANCES (subscriber rows). The old\n * `engine::trigger-types::list` builtin has been removed and is now\n * served by `engine::triggers::list`.\n */\nexport const EngineFunctions = {\n LIST_FUNCTIONS: 'engine::functions::list',\n INFO_FUNCTIONS: 'engine::functions::info',\n LIST_WORKERS: 'engine::workers::list',\n INFO_WORKERS: 'engine::workers::info',\n LIST_TRIGGERS: 'engine::triggers::list',\n INFO_TRIGGERS: 'engine::triggers::info',\n LIST_REGISTERED_TRIGGERS: 'engine::registered-triggers::list',\n INFO_REGISTERED_TRIGGERS: 'engine::registered-triggers::info',\n REGISTER_WORKER: 'engine::workers::register',\n} as const\n\n/** Engine trigger types */\nexport const EngineTriggers = {\n FUNCTIONS_AVAILABLE: 'engine::functions-available',\n LOG: 'log',\n} as const\n\n/** Log function paths */\nexport const LogFunctions = {\n INFO: 'engine::log::info',\n WARN: 'engine::log::warn',\n ERROR: 'engine::log::error',\n DEBUG: 'engine::log::debug',\n} as const\n\n/** Connection state for the III WebSocket */\nexport type IIIConnectionState =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface IIIReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_BRIDGE_RECONNECTION_CONFIG: IIIReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Default invocation timeout in milliseconds */\nexport const DEFAULT_INVOCATION_TIMEOUT_MS = 30000\n\n/** WebSocket opening-handshake timeout in ms (parity with Rust SDK connect_timeout, MOT-3857) */\nexport const WS_HANDSHAKE_TIMEOUT_MS = 10000\n\n/** Client keepalive ping cadence in ms (parity with Rust SDK ping_interval) */\nexport const WS_PING_INTERVAL_MS = 20000\n\n/** Force reconnect after this long with no inbound frame (parity with Rust SDK idle_timeout) */\nexport const WS_IDLE_TIMEOUT_MS = 60000\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,kBAAkB;CAC7B,gBAAgB;CAChB,gBAAgB;CAChB,cAAc;CACd,cAAc;CACd,eAAe;CACf,eAAe;CACf,0BAA0B;CAC1B,0BAA0B;CAC1B,iBAAiB;CAClB;;AAGD,MAAa,iBAAiB;CAC5B,qBAAqB;CACrB,KAAK;CACN;;AAiCD,MAAa,qCAA4D;CACvE,gBAAgB;CAChB,YAAY;CACZ,mBAAmB;CACnB,cAAc;CACd,YAAY;CACb;;AAGD,MAAa,gCAAgC;;AAG7C,MAAa,0BAA0B;;AAGvC,MAAa,sBAAsB;;AAGnC,MAAa,qBAAqB"}
@@ -11,6 +11,7 @@ let MessageType = /* @__PURE__ */ function(MessageType) {
11
11
  MessageType["UnregisterTriggerType"] = "unregistertriggertype";
12
12
  MessageType["TriggerRegistrationResult"] = "triggerregistrationresult";
13
13
  MessageType["WorkerRegistered"] = "workerregistered";
14
+ MessageType["Reattach"] = "reattach";
14
15
  return MessageType;
15
16
  }({});
16
17
 
@@ -21,4 +22,4 @@ Object.defineProperty(exports, 'MessageType', {
21
22
  return MessageType;
22
23
  }
23
24
  });
24
- //# sourceMappingURL=iii-types-6aHBgy7l.cjs.map
25
+ //# sourceMappingURL=iii-types-BvaIabiX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iii-types-BvaIabiX.cjs","names":[],"sources":["../src/iii-types.ts"],"sourcesContent":["import type { HttpInvocationConfig } from '@iii-dev/helpers/http'\n\n/**\n * Any JSON value: the TypeScript equivalent of the engine's arbitrary-JSON\n * wire values (Rust `serde_json::Value`). Used where the wire contract is\n * \"any JSON\", e.g. per-invocation `metadata`.\n */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue }\n\nexport enum MessageType {\n RegisterFunction = 'registerfunction',\n UnregisterFunction = 'unregisterfunction',\n InvokeFunction = 'invokefunction',\n InvocationResult = 'invocationresult',\n RegisterTriggerType = 'registertriggertype',\n RegisterTrigger = 'registertrigger',\n UnregisterTrigger = 'unregistertrigger',\n UnregisterTriggerType = 'unregistertriggertype',\n TriggerRegistrationResult = 'triggerregistrationresult',\n WorkerRegistered = 'workerregistered',\n Reattach = 'reattach',\n}\n\nexport type RegisterTriggerTypeMessage = {\n message_type: MessageType.RegisterTriggerType\n /** Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`). */\n id: string\n /** Human-readable description of what this trigger type does. */\n description: string\n}\n\nexport type UnregisterTriggerTypeMessage = {\n message_type: MessageType.UnregisterTriggerType\n id: string\n}\n\nexport type UnregisterTriggerMessage = {\n message_type: MessageType.UnregisterTrigger\n id: string\n type?: string\n}\n\nexport type ErrorBody = {\n code: string\n message: string\n stacktrace?: string\n}\n\nexport type TriggerRegistrationResultMessage = {\n message_type: MessageType.TriggerRegistrationResult\n id: string\n type: string\n function_id: string\n error?: ErrorBody\n}\n\nexport type RegisterTriggerMessage = {\n /** Wire discriminator; always `MessageType.RegisterTrigger`. */\n message_type: MessageType.RegisterTrigger\n /** Unique trigger identifier, generated by the SDK during registration. */\n id: string\n /** Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`). */\n type: string\n /** ID of the function this trigger invokes when it fires. */\n function_id: string\n /** Trigger-type-specific configuration, matching the shape the trigger type expects. */\n config: unknown\n /** Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. */\n metadata?: Record<string, unknown>\n}\n\nexport type RegisterFunctionFormat = {\n /**\n * The name of the parameter.\n */\n name?: string\n /**\n * The description of the parameter.\n */\n description?: string\n /**\n * The type of the parameter.\n */\n type?: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'map' | 'integer'\n /**\n * The body of the parameter (for objects).\n */\n properties?: Record<string, unknown>\n /**\n * The items of the parameter (for arrays).\n */\n items?: unknown\n /**\n * Whether the parameter is required.\n */\n required?: string[]\n [key: string]: unknown\n}\n\nexport type RegisterFunctionMessage = {\n message_type: MessageType.RegisterFunction\n /**\n * The path of the function (use :: for namespacing, e.g. external::my_lambda).\n */\n id: string\n /**\n * The description of the function.\n */\n description?: string\n /**\n * The request format of the function.\n */\n request_format?: RegisterFunctionFormat\n /**\n * The response format of the function.\n */\n response_format?: RegisterFunctionFormat\n /**\n * Arbitrary metadata attached to the function.\n */\n metadata?: Record<string, unknown>\n /**\n * HTTP invocation config for external HTTP functions (Lambda, Cloudflare Workers, etc.).\n */\n invocation?: HttpInvocationConfig\n}\n\n/**\n * Routing action for {@link TriggerRequest}. Determines how the engine\n * handles the invocation.\n *\n * - `enqueue`: Routes through a named queue for async processing.\n * - `void`: Fire-and-forget, no response.\n */\nexport type TriggerAction = { type: 'enqueue'; queue: string } | { type: 'void' }\n\n/**\n * Input passed to the RBAC middleware function on every function invocation\n * through the RBAC port. The middleware can inspect, modify, or reject the\n * call before it reaches the target function.\n */\nexport type MiddlewareFunctionInput = {\n /** ID of the function being invoked. */\n function_id: string\n /** Payload sent by the caller. */\n payload: Record<string, unknown>\n /** Routing action, if any. */\n action?: TriggerAction\n /** Auth context returned by the auth function for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Request object passed to {@link IIIClient.trigger}.\n *\n * @typeParam TInput - Type of the payload.\n */\nexport type TriggerRequest<TInput = unknown> = {\n /** ID of the function to invoke. */\n function_id: string\n /** Input data passed to the function. */\n payload: TInput\n /** Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue()`, `TriggerAction.Void()`). */\n action?: TriggerAction\n /** Override the default invocation timeout, in milliseconds. */\n timeoutMs?: number\n /** Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. */\n metadata?: unknown\n}\n\nexport type InvokeFunctionMessage = {\n message_type: MessageType.InvokeFunction\n /**\n * This is optional for async invocations\n */\n invocation_id?: string\n /**\n * The path of the function.\n */\n function_id: string\n /**\n * The data to pass to the function\n */\n data: unknown\n /**\n * W3C trace-context traceparent header for distributed tracing\n */\n traceparent?: string\n /**\n * W3C baggage header for cross-cutting context propagation\n */\n baggage?: string\n /**\n * Trigger action for queue routing or fire-and-forget\n */\n action?: TriggerAction\n /**\n * Optional per-invocation metadata (arbitrary JSON). Travels as a separate\n * channel from `data`. Omitted from the JSON when undefined; absence on\n * inbound means \"no metadata\" (backward compatible with older engines).\n */\n metadata?: JsonValue\n}\n\nexport type InvocationResultMessage = {\n message_type: MessageType.InvocationResult\n /**\n * The id of the invocation\n */\n invocation_id: string\n /**\n * The path of the function.\n */\n function_id: string\n result?: unknown\n error?: unknown\n /**\n * W3C trace-context traceparent header for distributed tracing\n */\n traceparent?: string\n /**\n * W3C baggage header for cross-cutting context propagation\n */\n baggage?: string\n}\n\nexport type WorkerRegisteredMessage = {\n message_type: MessageType.WorkerRegistered\n worker_id: string\n /** Secret to present in a reattach frame on reconnect; absent on older engines. */\n reattach_token?: string\n}\n\nexport type UnregisterFunctionMessage = {\n message_type: MessageType.UnregisterFunction\n id: string\n}\n\n/**\n * Serializable reference to one end of a streaming channel. Can be included\n * in invocation payloads to pass channel endpoints between workers.\n */\nexport type StreamChannelRef = {\n /** Unique channel identifier. */\n channel_id: string\n /** Access key for authentication. */\n access_key: string\n /** Whether this ref is for reading or writing. */\n direction: 'read' | 'write'\n}\n\nexport type IIIMessage =\n | RegisterFunctionMessage\n | UnregisterFunctionMessage\n | InvokeFunctionMessage\n | InvocationResultMessage\n | RegisterTriggerMessage\n | RegisterTriggerTypeMessage\n | UnregisterTriggerMessage\n | UnregisterTriggerTypeMessage\n | TriggerRegistrationResultMessage\n | WorkerRegisteredMessage\n"],"mappings":";;AAeA,IAAY,cAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;KACD"}
@@ -10,9 +10,10 @@ let MessageType = /* @__PURE__ */ function(MessageType) {
10
10
  MessageType["UnregisterTriggerType"] = "unregistertriggertype";
11
11
  MessageType["TriggerRegistrationResult"] = "triggerregistrationresult";
12
12
  MessageType["WorkerRegistered"] = "workerregistered";
13
+ MessageType["Reattach"] = "reattach";
13
14
  return MessageType;
14
15
  }({});
15
16
 
16
17
  //#endregion
17
18
  export { MessageType as t };
18
- //# sourceMappingURL=iii-types-CRx2qAjB.mjs.map
19
+ //# sourceMappingURL=iii-types-wPYrg7hX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iii-types-wPYrg7hX.mjs","names":[],"sources":["../src/iii-types.ts"],"sourcesContent":["import type { HttpInvocationConfig } from '@iii-dev/helpers/http'\n\n/**\n * Any JSON value: the TypeScript equivalent of the engine's arbitrary-JSON\n * wire values (Rust `serde_json::Value`). Used where the wire contract is\n * \"any JSON\", e.g. per-invocation `metadata`.\n */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue }\n\nexport enum MessageType {\n RegisterFunction = 'registerfunction',\n UnregisterFunction = 'unregisterfunction',\n InvokeFunction = 'invokefunction',\n InvocationResult = 'invocationresult',\n RegisterTriggerType = 'registertriggertype',\n RegisterTrigger = 'registertrigger',\n UnregisterTrigger = 'unregistertrigger',\n UnregisterTriggerType = 'unregistertriggertype',\n TriggerRegistrationResult = 'triggerregistrationresult',\n WorkerRegistered = 'workerregistered',\n Reattach = 'reattach',\n}\n\nexport type RegisterTriggerTypeMessage = {\n message_type: MessageType.RegisterTriggerType\n /** Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`). */\n id: string\n /** Human-readable description of what this trigger type does. */\n description: string\n}\n\nexport type UnregisterTriggerTypeMessage = {\n message_type: MessageType.UnregisterTriggerType\n id: string\n}\n\nexport type UnregisterTriggerMessage = {\n message_type: MessageType.UnregisterTrigger\n id: string\n type?: string\n}\n\nexport type ErrorBody = {\n code: string\n message: string\n stacktrace?: string\n}\n\nexport type TriggerRegistrationResultMessage = {\n message_type: MessageType.TriggerRegistrationResult\n id: string\n type: string\n function_id: string\n error?: ErrorBody\n}\n\nexport type RegisterTriggerMessage = {\n /** Wire discriminator; always `MessageType.RegisterTrigger`. */\n message_type: MessageType.RegisterTrigger\n /** Unique trigger identifier, generated by the SDK during registration. */\n id: string\n /** Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`). */\n type: string\n /** ID of the function this trigger invokes when it fires. */\n function_id: string\n /** Trigger-type-specific configuration, matching the shape the trigger type expects. */\n config: unknown\n /** Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. */\n metadata?: Record<string, unknown>\n}\n\nexport type RegisterFunctionFormat = {\n /**\n * The name of the parameter.\n */\n name?: string\n /**\n * The description of the parameter.\n */\n description?: string\n /**\n * The type of the parameter.\n */\n type?: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'map' | 'integer'\n /**\n * The body of the parameter (for objects).\n */\n properties?: Record<string, unknown>\n /**\n * The items of the parameter (for arrays).\n */\n items?: unknown\n /**\n * Whether the parameter is required.\n */\n required?: string[]\n [key: string]: unknown\n}\n\nexport type RegisterFunctionMessage = {\n message_type: MessageType.RegisterFunction\n /**\n * The path of the function (use :: for namespacing, e.g. external::my_lambda).\n */\n id: string\n /**\n * The description of the function.\n */\n description?: string\n /**\n * The request format of the function.\n */\n request_format?: RegisterFunctionFormat\n /**\n * The response format of the function.\n */\n response_format?: RegisterFunctionFormat\n /**\n * Arbitrary metadata attached to the function.\n */\n metadata?: Record<string, unknown>\n /**\n * HTTP invocation config for external HTTP functions (Lambda, Cloudflare Workers, etc.).\n */\n invocation?: HttpInvocationConfig\n}\n\n/**\n * Routing action for {@link TriggerRequest}. Determines how the engine\n * handles the invocation.\n *\n * - `enqueue`: Routes through a named queue for async processing.\n * - `void`: Fire-and-forget, no response.\n */\nexport type TriggerAction = { type: 'enqueue'; queue: string } | { type: 'void' }\n\n/**\n * Input passed to the RBAC middleware function on every function invocation\n * through the RBAC port. The middleware can inspect, modify, or reject the\n * call before it reaches the target function.\n */\nexport type MiddlewareFunctionInput = {\n /** ID of the function being invoked. */\n function_id: string\n /** Payload sent by the caller. */\n payload: Record<string, unknown>\n /** Routing action, if any. */\n action?: TriggerAction\n /** Auth context returned by the auth function for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Request object passed to {@link IIIClient.trigger}.\n *\n * @typeParam TInput - Type of the payload.\n */\nexport type TriggerRequest<TInput = unknown> = {\n /** ID of the function to invoke. */\n function_id: string\n /** Input data passed to the function. */\n payload: TInput\n /** Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue()`, `TriggerAction.Void()`). */\n action?: TriggerAction\n /** Override the default invocation timeout, in milliseconds. */\n timeoutMs?: number\n /** Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. */\n metadata?: unknown\n}\n\nexport type InvokeFunctionMessage = {\n message_type: MessageType.InvokeFunction\n /**\n * This is optional for async invocations\n */\n invocation_id?: string\n /**\n * The path of the function.\n */\n function_id: string\n /**\n * The data to pass to the function\n */\n data: unknown\n /**\n * W3C trace-context traceparent header for distributed tracing\n */\n traceparent?: string\n /**\n * W3C baggage header for cross-cutting context propagation\n */\n baggage?: string\n /**\n * Trigger action for queue routing or fire-and-forget\n */\n action?: TriggerAction\n /**\n * Optional per-invocation metadata (arbitrary JSON). Travels as a separate\n * channel from `data`. Omitted from the JSON when undefined; absence on\n * inbound means \"no metadata\" (backward compatible with older engines).\n */\n metadata?: JsonValue\n}\n\nexport type InvocationResultMessage = {\n message_type: MessageType.InvocationResult\n /**\n * The id of the invocation\n */\n invocation_id: string\n /**\n * The path of the function.\n */\n function_id: string\n result?: unknown\n error?: unknown\n /**\n * W3C trace-context traceparent header for distributed tracing\n */\n traceparent?: string\n /**\n * W3C baggage header for cross-cutting context propagation\n */\n baggage?: string\n}\n\nexport type WorkerRegisteredMessage = {\n message_type: MessageType.WorkerRegistered\n worker_id: string\n /** Secret to present in a reattach frame on reconnect; absent on older engines. */\n reattach_token?: string\n}\n\nexport type UnregisterFunctionMessage = {\n message_type: MessageType.UnregisterFunction\n id: string\n}\n\n/**\n * Serializable reference to one end of a streaming channel. Can be included\n * in invocation payloads to pass channel endpoints between workers.\n */\nexport type StreamChannelRef = {\n /** Unique channel identifier. */\n channel_id: string\n /** Access key for authentication. */\n access_key: string\n /** Whether this ref is for reading or writing. */\n direction: 'read' | 'write'\n}\n\nexport type IIIMessage =\n | RegisterFunctionMessage\n | UnregisterFunctionMessage\n | InvokeFunctionMessage\n | InvocationResultMessage\n | RegisterTriggerMessage\n | RegisterTriggerTypeMessage\n | UnregisterTriggerMessage\n | UnregisterTriggerTypeMessage\n | TriggerRegistrationResultMessage\n | WorkerRegisteredMessage\n"],"mappings":";AAeA,IAAY,cAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;KACD"}
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_utils = require('./utils-63wxBJg-.cjs');
3
3
  const require_errors = require('./errors.cjs');
4
- const require_channels = require('./channels-DfBRsGN1.cjs');
5
- const require_iii_constants = require('./iii-constants-Br94RUNi.cjs');
6
- const require_iii_types = require('./iii-types-6aHBgy7l.cjs');
4
+ const require_iii_constants = require('./iii-constants-M_BGfxGD.cjs');
5
+ const require_channels = require('./channels-C2ezAJ_g.cjs');
6
+ const require_iii_types = require('./iii-types-BvaIabiX.cjs');
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
8
8
  let node_module = require("node:module");
9
9
  let node_os = require("node:os");
@@ -249,6 +249,7 @@ var Sdk = class {
249
249
  this.stopMetricsReporting();
250
250
  await (0, _iii_dev_helpers_observability.shutdownOtel)();
251
251
  this.clearReconnectTimeout();
252
+ this.stopHeartbeat();
252
253
  for (const [_id, invocation] of this.invocations) {
253
254
  if (invocation.timeout) clearTimeout(invocation.timeout);
254
255
  invocation.reject(/* @__PURE__ */ new Error("iii is shutting down"));
@@ -307,7 +308,10 @@ var Sdk = class {
307
308
  connect() {
308
309
  if (this.isShuttingDown) return;
309
310
  this.setConnectionState("connecting");
310
- this.ws = new ws.WebSocket(this.address, { headers: this.options?.headers });
311
+ this.ws = new ws.WebSocket(this.address, {
312
+ headers: this.options?.headers,
313
+ handshakeTimeout: require_iii_constants.WS_HANDSHAKE_TIMEOUT_MS
314
+ });
311
315
  this.ws.on("open", this.onSocketOpen.bind(this));
312
316
  this.ws.on("close", this.onSocketClose.bind(this));
313
317
  this.ws.on("error", this.onSocketError.bind(this));
@@ -318,6 +322,26 @@ var Sdk = class {
318
322
  this.reconnectTimeout = void 0;
319
323
  }
320
324
  }
325
+ startHeartbeat() {
326
+ this.stopHeartbeat();
327
+ this.idleTimeout = setTimeout(() => {
328
+ this.logError(`No inbound data for ${require_iii_constants.WS_IDLE_TIMEOUT_MS}ms, terminating connection to force reconnect`);
329
+ this.ws?.terminate();
330
+ }, require_iii_constants.WS_IDLE_TIMEOUT_MS);
331
+ this.heartbeatInterval = setInterval(() => {
332
+ if (this.ws && this.isOpen()) this.ws.ping();
333
+ }, require_iii_constants.WS_PING_INTERVAL_MS);
334
+ }
335
+ stopHeartbeat() {
336
+ if (this.heartbeatInterval) {
337
+ clearInterval(this.heartbeatInterval);
338
+ this.heartbeatInterval = void 0;
339
+ }
340
+ if (this.idleTimeout) {
341
+ clearTimeout(this.idleTimeout);
342
+ this.idleTimeout = void 0;
343
+ }
344
+ }
321
345
  scheduleReconnect() {
322
346
  if (this.isShuttingDown) return;
323
347
  const { maxRetries, initialDelayMs, backoffMultiplier, maxDelayMs, jitterFactor } = this.reconnectionConfig;
@@ -358,6 +382,7 @@ var Sdk = class {
358
382
  (0, _iii_dev_helpers_observability.stopWorkerGauges)();
359
383
  }
360
384
  onSocketClose() {
385
+ this.stopHeartbeat();
361
386
  this.ws?.removeAllListeners();
362
387
  this.ws?.terminate();
363
388
  this.ws = void 0;
@@ -370,6 +395,18 @@ var Sdk = class {
370
395
  this.reconnectAttempt = 0;
371
396
  this.setConnectionState("connected");
372
397
  this.ws?.on("message", this.onMessage.bind(this));
398
+ const touch = () => {
399
+ this.idleTimeout?.refresh();
400
+ };
401
+ this.ws?.on("message", touch);
402
+ this.ws?.on("ping", touch);
403
+ this.ws?.on("pong", touch);
404
+ this.startHeartbeat();
405
+ if (this.workerId) this.sendMessageRaw(JSON.stringify({
406
+ type: require_iii_types.MessageType.Reattach,
407
+ previous_worker_id: this.workerId,
408
+ reattach_token: this.reattachToken
409
+ }));
373
410
  this.triggerTypes.forEach(({ message }) => {
374
411
  this.sendMessage(require_iii_types.MessageType.RegisterTriggerType, message, true);
375
412
  });
@@ -619,8 +656,9 @@ var Sdk = class {
619
656
  else if (msgType === require_iii_types.MessageType.UnregisterTrigger) this.onUnregisterTrigger(message);
620
657
  else if (msgType === require_iii_types.MessageType.TriggerRegistrationResult) this.onTriggerRegistrationResult(message);
621
658
  else if (msgType === require_iii_types.MessageType.WorkerRegistered) {
622
- const { worker_id } = message;
659
+ const { worker_id, reattach_token } = message;
623
660
  this.workerId = worker_id;
661
+ this.reattachToken = reattach_token;
624
662
  console.debug("[iii] Worker registered with ID:", worker_id);
625
663
  this.startMetricsReporting();
626
664
  }