iii-sdk 0.24.0 → 0.24.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/channel.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_channels = require('./channels-C2ezAJ_g.cjs');
2
+ const require_channels = require('./channels-Dn3OKXH5.cjs');
3
3
 
4
4
  exports.ChannelReader = require_channels.ChannelReader;
5
5
  exports.ChannelWriter = require_channels.ChannelWriter;
package/dist/channel.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { i as ChannelWriter, r as ChannelReader } from "./channels-C4f7nfQr.mjs";
1
+ import { i as ChannelWriter, r as ChannelReader } from "./channels-Di68FfqY.mjs";
2
2
 
3
3
  export { ChannelReader, ChannelWriter };
@@ -13,12 +13,14 @@ const ChannelDirection = {
13
13
  Write: "write"
14
14
  };
15
15
  const ChannelItem = {
16
+ /** Construct a text channel item. */
16
17
  Text(value) {
17
18
  return {
18
19
  type: "text",
19
20
  value
20
21
  };
21
22
  },
23
+ /** Construct a binary channel item. */
22
24
  Binary(value) {
23
25
  return {
24
26
  type: "binary",
@@ -222,4 +224,4 @@ function buildChannelUrl(engineWsBase, channelId, accessKey, direction) {
222
224
 
223
225
  //#endregion
224
226
  export { ChannelWriter as i, ChannelItem as n, ChannelReader as r, ChannelDirection as t };
225
- //# sourceMappingURL=channels-C4f7nfQr.mjs.map
227
+ //# sourceMappingURL=channels-Di68FfqY.mjs.map
@@ -1 +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":";;;;;;;;;;AAUA,MAAa,mBAAmB;CAC9B,MAAM;CACN,OAAO;CACR;AAaD,MAAa,cAAc;CAEzB,KAAK,OAA4B;AAC/B,SAAO;GAAE,MAAM;GAAQ;GAAO;;CAGhC,OAAO,OAAgC;AACrC,SAAO;GAAE,MAAM;GAAU;GAAO;;CAEnC;;;;;;;;;;;;;;;;;;;AAoBD,IAAa,gBAAb,MAAa,cAAc;;oBACY,KAAK;;CAW1C,YAAY,cAAsB,KAAuB;YAV1B;iBACb;yBAIZ,EAAE;AAMN,OAAK,MAAM,gBAAgB,cAAc,IAAI,YAAY,IAAI,YAAY,QAAQ;AAEjF,OAAK,SAAS,IAAI,SAAS;GACzB,QAAQ,OAAe,WAAW,aAAa;IAC7C,MAAM,MAAM,OAAO,SAAS,MAAM,GAAG,QAAQ,OAAO,KAAK,MAAM;AAC/D,SAAK,YAAY,KAAK,SAAS;;GAEjC,QAAQ,aAAa;AACnB,QAAI,CAAC,KAAK,IAAI;AACZ,eAAU;AACV;;IAKF,MAAM,gBAAgB;AACpB,SAAI,KAAK,GACP,MAAK,GAAG,MAAM,KAAM,kBAAkB;AAExC,eAAU;;AAEZ,QAAI,KAAK,QACP,YAAW,SAAS,GAAG;QAEvB,MAAK,GAAG,GAAG,cAAc,WAAW,SAAS,GAAG,CAAC;;GAGrD,UAAU,KAAK,aAAa;AAC1B,QAAI,KAAK,GAAI,MAAK,GAAG,WAAW;AAChC,aAAS,IAAI;;GAEhB,CAAC;;CAGJ,AAAQ,kBAAwB;AAK9B,MACE,KAAK,MACL,KAAK,GAAG,eAAe,UAAU,WACjC,KAAK,GAAG,eAAe,UAAU,OAEjC;AAEF,OAAK,UAAU;AACf,OAAK,KAAK,IAAI,UAAU,KAAK,KAAK,EAAE,kBAAkB,yBAAyB,CAAC;AAEhF,OAAK,GAAG,GAAG,cAAc;AACvB,QAAK,UAAU;AACf,QAAK,MAAM,EAAE,MAAM,cAAc,KAAK,gBACpC,MAAK,IAAI,KAAK,MAAM,SAAS;AAE/B,QAAK,gBAAgB,SAAS;IAC9B;AAEF,OAAK,GAAG,GAAG,UAAU,QAAQ;AAC3B,QAAK,UAAU;AACf,QAAK,OAAO,QAAQ,IAAI;IACxB;AAEF,OAAK,GAAG,GAAG,eAAe;AACxB,QAAK,UAAU;AACf,OAAI,CAAC,KAAK,OAAO,UACf,MAAK,OAAO,SAAS;IAEvB;;;CAIJ,YAAY,KAAmB;AAC7B,OAAK,iBAAiB;AACtB,OAAK,QAAQ,MAAM,QAAQ;AACzB,OAAI,IAAK,MAAK,OAAO,QAAQ,IAAI;IACjC;;;CAIJ,QAAc;AACZ,MAAI,CAAC,KAAK,GAAI;EACd,MAAM,gBAAgB;AACpB,OAAI,KAAK,GACP,MAAK,GAAG,MAAM,KAAM,gBAAgB;;AAGxC,MAAI,KAAK,QACP,UAAS;MAET,MAAK,GAAG,GAAG,cAAc,SAAS,CAAC;;CAIvC,AAAQ,YAAY,MAAc,UAA8C;EAC9E,IAAI,SAAS;EACb,MAAM,YAAY,QAA6B;AAC7C,OAAI,KAAK;AACP,aAAS,IAAI;AACb;;AAGF,OAAI,UAAU,KAAK,QAAQ;AACzB,aAAS,KAAK;AACd;;GAGF,MAAM,MAAM,KAAK,IAAI,SAAS,cAAc,YAAY,KAAK,OAAO;GACpE,MAAM,OAAO,KAAK,SAAS,QAAQ,IAAI;AACvC,YAAS;AACT,QAAK,QAAQ,MAAM,SAAS;;AAE9B,WAAS,KAAK;;CAGhB,AAAQ,QAAQ,MAAuB,UAA8C;AACnF,OAAK,iBAAiB;AAKtB,MAAI,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,KAC9C,KAAI;AACF,QAAK,GAAG,KAAK,OAAO,QAAQ,SAAS,OAAO,KAAK,CAAC;UAC5C;AACN,QAAK,gBAAgB,KAAK;IAAE;IAAM;IAAU,CAAC;;MAG/C,MAAK,gBAAgB,KAAK;GAAE;GAAM;GAAU,CAAC;;;;;;;;;;;;;;;;;;;AAqBnD,IAAa,gBAAb,MAA2B;CAQzB,YAAY,cAAsB,KAAuB;YAP1B;mBACX;0BAC8C,EAAE;AAMlE,OAAK,MAAM,gBAAgB,cAAc,IAAI,YAAY,IAAI,YAAY,OAAO;EAEhF,MAAM,OAAO;AACb,OAAK,SAAS,IAAI,SAAS;GACzB,OAAO;AACL,SAAK,iBAAiB;AACtB,QAAI,KAAK,GAAI,MAAK,GAAG,QAAQ;;GAE/B,QAAQ,KAAK,UAAU;AACrB,QAAI,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,OAC9C,MAAK,GAAG,WAAW;AAErB,SAAK,KAAK;AACV,aAAS,IAAI;;GAEhB,CAAC;;CAGJ,AAAQ,kBAAwB;AAC9B,MAAI,KAAK,UAAW;AACpB,OAAK,YAAY;AACjB,OAAK,KAAK,IAAI,UAAU,KAAK,KAAK,EAAE,kBAAkB,yBAAyB,CAAC;AAEhF,OAAK,GAAG,GAAG,cAAc;AACtB,GAAC,KAAK,GAAyC,aAAa;IAC7D;AAEF,OAAK,GAAG,GAAG,YAAY,MAAc,aAAsB;AACzD,OAAI,UACF;QAAI,CAAC,KAAK,OAAO,KAAK,KAAK,CACzB,MAAK,IAAI,OAAO;UAEb;IACL,MAAM,MAAM,KAAK,SAAS,QAAQ;AAClC,SAAK,MAAM,MAAM,KAAK,iBACpB,IAAG,IAAI;;IAGX;AAEF,OAAK,GAAG,GAAG,eAAe;AACxB,QAAK,KAAK;AACV,OAAI,CAAC,KAAK,OAAO,UAAW,MAAK,OAAO,KAAK,KAAK;IAClD;AAEF,OAAK,GAAG,GAAG,UAAU,QAAQ;AAC3B,QAAK,OAAO,QAAQ,IAAI;IACxB;;;CAIJ,UAAU,UAAuC;AAC/C,OAAK,iBAAiB,KAAK,SAAS;;CAGtC,MAAM,UAA2B;AAC/B,OAAK,iBAAiB;EACtB,MAAM,SAAmB,EAAE;AAE3B,aAAW,MAAM,SAAS,KAAK,OAC7B,QAAO,KAAK,OAAO,SAAS,MAAM,GAAG,QAAQ,OAAO,KAAK,MAAM,CAAC;AAGlE,SAAO,OAAO,OAAO,OAAO;;CAG9B,QAAc;AACZ,MAAI,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,OAC9C,MAAK,GAAG,MAAM,KAAM,gBAAgB;;;AAK1C,SAAS,gBACP,cACA,WACA,WACA,WACQ;AAER,QAAO,GADM,aAAa,QAAQ,OAAO,GAAG,CAC7B,eAAe,UAAU,OAAO,mBAAmB,UAAU,CAAC,OAAO"}
1
+ {"version":3,"file":"channels-Di68FfqY.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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"}
@@ -1,4 +1,4 @@
1
- const require_utils = require('./utils-63wxBJg-.cjs');
1
+ const require_utils = require('./utils-SpwzEB77.cjs');
2
2
  const require_iii_constants = require('./iii-constants-M_BGfxGD.cjs');
3
3
  let ws = require("ws");
4
4
  let node_stream = require("node:stream");
@@ -14,12 +14,14 @@ const ChannelDirection = {
14
14
  Write: "write"
15
15
  };
16
16
  const ChannelItem = {
17
+ /** Construct a text channel item. */
17
18
  Text(value) {
18
19
  return {
19
20
  type: "text",
20
21
  value
21
22
  };
22
23
  },
24
+ /** Construct a binary channel item. */
23
25
  Binary(value) {
24
26
  return {
25
27
  type: "binary",
@@ -246,4 +248,4 @@ Object.defineProperty(exports, 'ChannelWriter', {
246
248
  return ChannelWriter;
247
249
  }
248
250
  });
249
- //# sourceMappingURL=channels-C2ezAJ_g.cjs.map
251
+ //# sourceMappingURL=channels-Dn3OKXH5.cjs.map
@@ -1 +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
+ {"version":3,"file":"channels-Dn3OKXH5.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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"}
package/dist/helpers.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_utils = require('./utils-63wxBJg-.cjs');
3
- const require_channels = require('./channels-C2ezAJ_g.cjs');
2
+ const require_utils = require('./utils-SpwzEB77.cjs');
3
+ const require_channels = require('./channels-Dn3OKXH5.cjs');
4
4
 
5
5
  //#region src/helpers.ts
6
6
  /**
package/dist/helpers.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as ChannelItem, t as ChannelDirection } from "./channels-C4f7nfQr.mjs";
1
+ import { n as ChannelItem, t as ChannelDirection } from "./channels-Di68FfqY.mjs";
2
2
  import { n as extractChannelRefs, r as isChannelRef } from "./utils-8G4hHqvZ.mjs";
3
3
 
4
4
  //#region src/helpers.ts
package/dist/index.cjs CHANGED
@@ -1,13 +1,13 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_utils = require('./utils-63wxBJg-.cjs');
2
+ const require_utils = require('./utils-SpwzEB77.cjs');
3
3
  const require_errors = require('./errors.cjs');
4
4
  const require_iii_constants = require('./iii-constants-M_BGfxGD.cjs');
5
- const require_channels = require('./channels-C2ezAJ_g.cjs');
5
+ const require_channels = require('./channels-Dn3OKXH5.cjs');
6
6
  const require_iii_types = require('./iii-types-BHasLgj1.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");
10
- node_os = require_utils.__toESM(node_os);
10
+ node_os = require_utils.__toESM(node_os, 1);
11
11
  let ws = require("ws");
12
12
  let _iii_dev_helpers_observability = require("@iii-dev/helpers/observability");
13
13
  let _iii_dev_helpers_observability_internal = require("@iii-dev/helpers/observability/internal");
@@ -84,11 +84,11 @@ var Sdk = class {
84
84
  this.connectionState = "disconnected";
85
85
  this.isShuttingDown = false;
86
86
  this.registerTriggerType = (triggerType, handler) => {
87
- this.sendMessage(require_iii_types.MessageType.RegisterTriggerType, triggerType, true);
87
+ this.sendMessage("registertriggertype", triggerType, true);
88
88
  this.triggerTypes.set(triggerType.id, {
89
89
  message: {
90
90
  ...triggerType,
91
- message_type: require_iii_types.MessageType.RegisterTriggerType
91
+ message_type: "registertriggertype"
92
92
  },
93
93
  handler
94
94
  });
@@ -120,7 +120,7 @@ var Sdk = class {
120
120
  };
121
121
  };
122
122
  this.unregisterTriggerType = (triggerType) => {
123
- this.sendMessage(require_iii_types.MessageType.UnregisterTriggerType, triggerType, true);
123
+ this.sendMessage("unregistertriggertype", triggerType, true);
124
124
  this.triggerTypes.delete(triggerType.id);
125
125
  };
126
126
  this.registerTrigger = (trigger) => {
@@ -128,18 +128,18 @@ var Sdk = class {
128
128
  const fullTrigger = {
129
129
  ...trigger,
130
130
  id,
131
- message_type: require_iii_types.MessageType.RegisterTrigger,
131
+ message_type: "registertrigger",
132
132
  ...(() => {
133
133
  const namespace = callNamespace(trigger.namespace, this.namespace, "RegisterTriggerInput.namespace");
134
134
  return namespace !== void 0 ? { namespace } : {};
135
135
  })()
136
136
  };
137
- this.sendMessage(require_iii_types.MessageType.RegisterTrigger, fullTrigger, true);
137
+ this.sendMessage("registertrigger", fullTrigger, true);
138
138
  this.triggers.set(id, fullTrigger);
139
139
  return { unregister: () => {
140
- this.sendMessage(require_iii_types.MessageType.UnregisterTrigger, {
140
+ this.sendMessage("unregistertrigger", {
141
141
  id,
142
- message_type: require_iii_types.MessageType.UnregisterTrigger,
142
+ message_type: "unregistertrigger",
143
143
  type: fullTrigger.type
144
144
  });
145
145
  this.triggers.delete(id);
@@ -152,11 +152,11 @@ var Sdk = class {
152
152
  const fullMessage = isHandler ? {
153
153
  ...options,
154
154
  id: functionId,
155
- message_type: require_iii_types.MessageType.RegisterFunction
155
+ message_type: "registerfunction"
156
156
  } : {
157
157
  ...options,
158
158
  id: functionId,
159
- message_type: require_iii_types.MessageType.RegisterFunction,
159
+ message_type: "registerfunction",
160
160
  invocation: {
161
161
  url: handlerOrInvocation.url,
162
162
  method: handlerOrInvocation.method ?? "POST",
@@ -165,7 +165,7 @@ var Sdk = class {
165
165
  auth: handlerOrInvocation.auth
166
166
  }
167
167
  };
168
- this.sendMessage(require_iii_types.MessageType.RegisterFunction, fullMessage, true);
168
+ this.sendMessage("registerfunction", fullMessage, true);
169
169
  if (isHandler) {
170
170
  const handler = handlerOrInvocation;
171
171
  this.functions.set(functionId, {
@@ -222,7 +222,7 @@ var Sdk = class {
222
222
  return {
223
223
  id: functionId,
224
224
  unregister: () => {
225
- this.sendMessage(require_iii_types.MessageType.UnregisterFunction, { id: functionId }, true);
225
+ this.sendMessage("unregisterfunction", { id: functionId }, true);
226
226
  this.functions.delete(functionId);
227
227
  }
228
228
  };
@@ -246,7 +246,7 @@ var Sdk = class {
246
246
  if (action?.type === "void") {
247
247
  const traceparent = (0, _iii_dev_helpers_observability.injectTraceparent)();
248
248
  const baggage = (0, _iii_dev_helpers_observability.injectBaggage)();
249
- this.sendMessage(require_iii_types.MessageType.InvokeFunction, {
249
+ this.sendMessage("invokefunction", {
250
250
  function_id,
251
251
  data: payload,
252
252
  traceparent,
@@ -283,7 +283,7 @@ var Sdk = class {
283
283
  function_id,
284
284
  timeout
285
285
  });
286
- this.sendMessage(require_iii_types.MessageType.InvokeFunction, {
286
+ this.sendMessage("invokefunction", {
287
287
  invocation_id,
288
288
  function_id,
289
289
  data: payload,
@@ -466,24 +466,24 @@ var Sdk = class {
466
466
  this.ws?.on("pong", touch);
467
467
  this.startHeartbeat();
468
468
  if (this.workerId) this.sendMessageRaw(JSON.stringify({
469
- type: require_iii_types.MessageType.Reattach,
469
+ type: "reattach",
470
470
  previous_worker_id: this.workerId,
471
471
  reattach_token: this.reattachToken
472
472
  }));
473
473
  this.registerWorkerMetadata();
474
474
  this.triggerTypes.forEach(({ message }) => {
475
- this.sendMessage(require_iii_types.MessageType.RegisterTriggerType, message, true);
475
+ this.sendMessage("registertriggertype", message, true);
476
476
  });
477
477
  this.functions.forEach(({ message }) => {
478
- this.sendMessage(require_iii_types.MessageType.RegisterFunction, message, true);
478
+ this.sendMessage("registerfunction", message, true);
479
479
  });
480
480
  this.triggers.forEach((trigger) => {
481
- this.sendMessage(require_iii_types.MessageType.RegisterTrigger, trigger, true);
481
+ this.sendMessage("registertrigger", trigger, true);
482
482
  });
483
483
  const pending = this.messagesToSend;
484
484
  this.messagesToSend = [];
485
485
  for (const message of pending) {
486
- if (message.type === require_iii_types.MessageType.InvokeFunction && typeof message.invocation_id === "string" && !this.invocations.has(message.invocation_id)) continue;
486
+ if (message.type === "invokefunction" && typeof message.invocation_id === "string" && !this.invocations.has(message.invocation_id)) continue;
487
487
  this.sendMessageRaw(JSON.stringify(message));
488
488
  }
489
489
  }
@@ -501,7 +501,7 @@ var Sdk = class {
501
501
  }
502
502
  toWireFormat(messageType, message) {
503
503
  const { message_type: _, ...rest } = message;
504
- if (messageType === require_iii_types.MessageType.RegisterTrigger && "type" in message) {
504
+ if (messageType === "registertrigger" && "type" in message) {
505
505
  const { type: triggerType, ...triggerRest } = message;
506
506
  return {
507
507
  type: messageType,
@@ -509,7 +509,7 @@ var Sdk = class {
509
509
  trigger_type: triggerType
510
510
  };
511
511
  }
512
- if (messageType === require_iii_types.MessageType.UnregisterTrigger && "type" in message) {
512
+ if (messageType === "unregistertrigger" && "type" in message) {
513
513
  const { type: triggerType, ...triggerRest } = message;
514
514
  return {
515
515
  type: messageType,
@@ -517,7 +517,7 @@ var Sdk = class {
517
517
  trigger_type: triggerType
518
518
  };
519
519
  }
520
- if (messageType === require_iii_types.MessageType.TriggerRegistrationResult && "type" in message) {
520
+ if (messageType === "triggerregistrationresult" && "type" in message) {
521
521
  const { type: triggerType, ...resultRest } = message;
522
522
  return {
523
523
  type: messageType,
@@ -650,7 +650,7 @@ var Sdk = class {
650
650
  }
651
651
  try {
652
652
  const result = await fn.handler(resolvedInput, metadata, traceparent, baggage);
653
- this.sendMessage(require_iii_types.MessageType.InvocationResult, {
653
+ this.sendMessage("invocationresult", {
654
654
  invocation_id,
655
655
  function_id,
656
656
  result,
@@ -659,7 +659,7 @@ var Sdk = class {
659
659
  });
660
660
  } catch (error) {
661
661
  const isError = error instanceof Error;
662
- this.sendMessage(require_iii_types.MessageType.InvocationResult, {
662
+ this.sendMessage("invocationresult", {
663
663
  invocation_id,
664
664
  function_id,
665
665
  error: {
@@ -674,7 +674,7 @@ var Sdk = class {
674
674
  } else {
675
675
  const errorCode = fn ? "function_not_invokable" : "function_not_found";
676
676
  const errorMessage = fn ? "Function is HTTP-invoked and cannot be invoked locally" : "Function not found";
677
- if (invocation_id) this.sendMessage(require_iii_types.MessageType.InvocationResult, {
677
+ if (invocation_id) this.sendMessage("invocationresult", {
678
678
  invocation_id,
679
679
  function_id,
680
680
  error: {
@@ -697,16 +697,16 @@ var Sdk = class {
697
697
  metadata,
698
698
  namespace
699
699
  });
700
- this.sendMessage(require_iii_types.MessageType.TriggerRegistrationResult, {
700
+ this.sendMessage("triggerregistrationresult", {
701
701
  id,
702
- message_type: require_iii_types.MessageType.TriggerRegistrationResult,
702
+ message_type: "triggerregistrationresult",
703
703
  type: trigger_type,
704
704
  function_id
705
705
  });
706
706
  } catch (error) {
707
- this.sendMessage(require_iii_types.MessageType.TriggerRegistrationResult, {
707
+ this.sendMessage("triggerregistrationresult", {
708
708
  id,
709
- message_type: require_iii_types.MessageType.TriggerRegistrationResult,
709
+ message_type: "triggerregistrationresult",
710
710
  type: trigger_type,
711
711
  function_id,
712
712
  error: {
@@ -715,9 +715,9 @@ var Sdk = class {
715
715
  }
716
716
  });
717
717
  }
718
- else this.sendMessage(require_iii_types.MessageType.TriggerRegistrationResult, {
718
+ else this.sendMessage("triggerregistrationresult", {
719
719
  id,
720
- message_type: require_iii_types.MessageType.TriggerRegistrationResult,
720
+ message_type: "triggerregistrationresult",
721
721
  type: trigger_type,
722
722
  function_id,
723
723
  error: {
@@ -760,22 +760,22 @@ var Sdk = class {
760
760
  this.logError("Failed to parse incoming message", error);
761
761
  return;
762
762
  }
763
- if (msgType === require_iii_types.MessageType.InvocationResult) {
763
+ if (msgType === "invocationresult") {
764
764
  const { invocation_id, result, error } = message;
765
765
  this.onInvocationResult(invocation_id, result, error);
766
- } else if (msgType === require_iii_types.MessageType.InvokeFunction) {
766
+ } else if (msgType === "invokefunction") {
767
767
  const { invocation_id, function_id, data, metadata, traceparent, baggage } = message;
768
768
  this.onInvokeFunction(invocation_id, function_id, data, metadata, traceparent, baggage);
769
- } else if (msgType === require_iii_types.MessageType.RegisterTrigger) this.onRegisterTrigger(message);
770
- else if (msgType === require_iii_types.MessageType.UnregisterTrigger) this.onUnregisterTrigger(message);
771
- else if (msgType === require_iii_types.MessageType.TriggerRegistrationResult) this.onTriggerRegistrationResult(message);
772
- else if (msgType === require_iii_types.MessageType.WorkerRegistered) {
769
+ } else if (msgType === "registertrigger") this.onRegisterTrigger(message);
770
+ else if (msgType === "unregistertrigger") this.onUnregisterTrigger(message);
771
+ else if (msgType === "triggerregistrationresult") this.onTriggerRegistrationResult(message);
772
+ else if (msgType === "workerregistered") {
773
773
  const { worker_id, reattach_token } = message;
774
774
  this.workerId = worker_id;
775
775
  this.reattachToken = reattach_token;
776
776
  console.debug("[iii] Worker registered with ID:", worker_id);
777
777
  this.startMetricsReporting();
778
- } else if (msgType === require_iii_types.MessageType.RegistrationRejected) {
778
+ } else if (msgType === "registrationrejected") {
779
779
  const { code, namespace, worker_name, function_id, owner_worker_id } = message;
780
780
  this.onRegistrationRejected({
781
781
  code,
@@ -810,10 +810,25 @@ var Sdk = class {
810
810
  * ```
811
811
  */
812
812
  const TriggerAction = {
813
+ /**
814
+ * Routes the invocation through a named queue. The engine enqueues the job,
815
+ * acknowledges the caller with `{ messageReceiptId }`, and processes it
816
+ * asynchronously.
817
+ *
818
+ * Requires the `queue` worker in `worker-compose.yaml`.
819
+ * Without it the trigger rejects with `enqueue_error` (no queue provider).
820
+ *
821
+ * @param opts - Queue routing options.
822
+ * @param opts.queue - Name of the target queue.
823
+ */
813
824
  Enqueue: (opts) => ({
814
825
  type: "enqueue",
815
826
  ...opts
816
827
  }),
828
+ /**
829
+ * Fire-and-forget routing. The engine forwards the invocation without
830
+ * waiting for a response or queuing the job.
831
+ */
817
832
  Void: () => ({ type: "void" })
818
833
  };
819
834
  /**