iii-browser-sdk 0.22.0 → 0.22.1-alpha.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.
package/dist/index.mjs CHANGED
@@ -1,5 +1,24 @@
1
1
  import { n as isChannelRef, o as ChannelReader, r as randomUUID, s as ChannelWriter } from "./utils-Dc59paBI.mjs";
2
2
 
3
+ //#region src/errors.ts
4
+ /**
5
+ * A terminal registration rejection from the engine. Thrown into every pending
6
+ * invocation and exposed via `getFatalError()` when a worker-name collision
7
+ * (or other non-retryable rejection) closes the connection for good.
8
+ */
9
+ var RegistrationRejectedError = class extends Error {
10
+ constructor(init) {
11
+ super(`${init.code}: registration rejected for ${init.function_id !== void 0 ? `function "${init.function_id}"` : `worker "${init.worker_name ?? "<unknown>"}"`} in namespace "${init.namespace}" (already owned by worker ${init.owner_worker_id})`);
12
+ this.name = "RegistrationRejectedError";
13
+ this.code = init.code;
14
+ this.namespace = init.namespace;
15
+ this.worker_name = init.worker_name;
16
+ this.function_id = init.function_id;
17
+ this.owner_worker_id = init.owner_worker_id;
18
+ }
19
+ };
20
+
21
+ //#endregion
3
22
  //#region src/iii-constants.ts
4
23
  /**
5
24
  * Constants for the III module.
@@ -49,6 +68,7 @@ let MessageType = /* @__PURE__ */ function(MessageType) {
49
68
  MessageType["UnregisterTrigger"] = "unregistertrigger";
50
69
  MessageType["UnregisterTriggerType"] = "unregistertriggertype";
51
70
  MessageType["TriggerRegistrationResult"] = "triggerregistrationresult";
71
+ MessageType["RegistrationRejected"] = "registrationrejected";
52
72
  MessageType["WorkerRegistered"] = "workerregistered";
53
73
  MessageType["Reattach"] = "reattach";
54
74
  return MessageType;
@@ -56,6 +76,13 @@ let MessageType = /* @__PURE__ */ function(MessageType) {
56
76
 
57
77
  //#endregion
58
78
  //#region src/iii.ts
79
+ /** Short random suffix; `crypto.randomUUID` is unavailable on insecure origins. */
80
+ function randomId() {
81
+ const c = globalThis.crypto;
82
+ if (c?.randomUUID) return c.randomUUID().slice(0, 8);
83
+ if (c?.getRandomValues) return Array.from(c.getRandomValues(new Uint8Array(4))).map((b) => b.toString(16).padStart(2, "0")).join("");
84
+ return Math.random().toString(16).slice(2, 10);
85
+ }
59
86
  var Sdk = class {
60
87
  constructor(address, options) {
61
88
  this.address = address;
@@ -84,7 +111,8 @@ var Sdk = class {
84
111
  return this.registerTrigger({
85
112
  type: triggerType.id,
86
113
  function_id: functionId,
87
- config
114
+ config,
115
+ namespace: this.namespace
88
116
  });
89
117
  },
90
118
  registerFunction: (functionId, handler, config) => {
@@ -92,7 +120,8 @@ var Sdk = class {
92
120
  this.registerTrigger({
93
121
  type: triggerType.id,
94
122
  function_id: functionId,
95
- config
123
+ config,
124
+ namespace: this.namespace
96
125
  });
97
126
  return ref;
98
127
  },
@@ -160,13 +189,14 @@ var Sdk = class {
160
189
  };
161
190
  };
162
191
  this.trigger = async (request) => {
163
- const { function_id, payload, action, timeoutMs } = request;
192
+ const { function_id, payload, action, timeoutMs, namespace } = request;
164
193
  const effectiveTimeout = timeoutMs ?? this.invocationTimeoutMs;
165
194
  if (action?.type === "void") {
166
195
  this.sendMessage(MessageType.InvokeFunction, {
167
196
  function_id,
168
197
  data: payload,
169
- action
198
+ action,
199
+ ...namespace !== void 0 ? { namespace } : {}
170
200
  });
171
201
  return;
172
202
  }
@@ -193,7 +223,8 @@ var Sdk = class {
193
223
  invocation_id,
194
224
  function_id,
195
225
  data: payload,
196
- action
226
+ action,
227
+ ...namespace !== void 0 ? { namespace } : {}
197
228
  });
198
229
  });
199
230
  };
@@ -204,6 +235,7 @@ var Sdk = class {
204
235
  this.registerFunction(`stream::list(${streamName})`, stream.list.bind(stream));
205
236
  this.registerFunction(`stream::list_groups(${streamName})`, stream.listGroups.bind(stream));
206
237
  };
238
+ this.getFatalError = () => this.fatalError;
207
239
  this.shutdown = async () => {
208
240
  this.isShuttingDown = true;
209
241
  this.clearReconnectTimeout();
@@ -233,6 +265,8 @@ var Sdk = class {
233
265
  this.connectionListeners.delete(handler);
234
266
  };
235
267
  };
268
+ this.workerName = options?.workerName ?? `browser:${randomId()}`;
269
+ this.namespace = options?.namespace;
236
270
  this.invocationTimeoutMs = options?.invocationTimeoutMs ?? 3e4;
237
271
  this.reconnectionConfig = {
238
272
  ...DEFAULT_BRIDGE_RECONNECTION_CONFIG,
@@ -296,6 +330,7 @@ var Sdk = class {
296
330
  this.ws.onmessage = null;
297
331
  }
298
332
  this.ws = void 0;
333
+ if (this.isShuttingDown) return;
299
334
  this.setConnectionState("disconnected");
300
335
  this.scheduleReconnect();
301
336
  }
@@ -309,6 +344,7 @@ var Sdk = class {
309
344
  previous_worker_id: this.workerId,
310
345
  reattach_token: this.reattachToken
311
346
  }));
347
+ this.registerWorkerMetadata();
312
348
  this.triggerTypes.forEach(({ message }) => {
313
349
  this.sendMessage(MessageType.RegisterTriggerType, message, true);
314
350
  });
@@ -366,6 +402,23 @@ var Sdk = class {
366
402
  ...rest
367
403
  };
368
404
  }
405
+ /**
406
+ * Tells the engine who this connection is. Sent on every open, before any
407
+ * registration, so the engine can resolve this connection's namespace and
408
+ * drain its buffered registrations immediately.
409
+ */
410
+ registerWorkerMetadata() {
411
+ this.sendMessage(MessageType.InvokeFunction, {
412
+ function_id: EngineFunctions.REGISTER_WORKER,
413
+ data: {
414
+ runtime: "browser",
415
+ name: this.workerName,
416
+ os: globalThis.navigator?.userAgent ?? "browser",
417
+ ...this.namespace !== void 0 ? { namespace: this.namespace } : {}
418
+ },
419
+ action: { type: "void" }
420
+ });
421
+ }
369
422
  sendMessage(messageType, message, skipIfClosed = false) {
370
423
  const wireMessage = this.toWireFormat(messageType, message);
371
424
  if (this.isOpen()) this.sendMessageRaw(JSON.stringify(wireMessage));
@@ -440,13 +493,14 @@ var Sdk = class {
440
493
  }
441
494
  }
442
495
  async onRegisterTrigger(message) {
443
- const { trigger_type, id, function_id, config } = message;
496
+ const { trigger_type, id, function_id, config, namespace } = message;
444
497
  const triggerTypeData = this.triggerTypes.get(trigger_type);
445
498
  if (triggerTypeData) try {
446
499
  await triggerTypeData.handler.registerTrigger({
447
500
  id,
448
501
  function_id,
449
- config
502
+ config,
503
+ namespace
450
504
  });
451
505
  this.sendMessage(MessageType.TriggerRegistrationResult, {
452
506
  id,
@@ -513,12 +567,39 @@ var Sdk = class {
513
567
  this.onInvokeFunction(invocation_id, function_id, data, traceparent, baggage);
514
568
  } else if (msgType === MessageType.RegisterTrigger) this.onRegisterTrigger(message);
515
569
  else if (msgType === MessageType.UnregisterTrigger) this.onUnregisterTrigger(message);
570
+ else if (msgType === MessageType.RegistrationRejected) this.onRegistrationRejected(message);
516
571
  else if (msgType === MessageType.WorkerRegistered) {
517
572
  const { worker_id, reattach_token } = message;
518
573
  this.workerId = worker_id;
519
574
  this.reattachToken = reattach_token;
520
575
  }
521
576
  }
577
+ /**
578
+ * The engine rejected a registration. A `FUNCTION_NAMESPACE_CONFLICT` costs
579
+ * one function and leaves the connection open, so log and keep serving. A
580
+ * `WORKER_NAMESPACE_CONFLICT` means another live worker owns this name in the
581
+ * namespace: it is terminal — stop and do not reconnect (otherwise the engine
582
+ * would only reject the same name again, which with `maxRetries: -1` loops
583
+ * forever).
584
+ */
585
+ onRegistrationRejected(init) {
586
+ if (init.code === "FUNCTION_NAMESPACE_CONFLICT") {
587
+ console.warn(`[iii] Function registration rejected: function "${init.function_id ?? "<unknown>"}" in namespace "${init.namespace}" is already exported by worker ${init.owner_worker_id}. Staying connected and serving the rest.`);
588
+ return;
589
+ }
590
+ console.error(`[iii] Registration rejected (${init.code}): worker "${init.worker_name}" in namespace "${init.namespace}" is already owned by ${init.owner_worker_id}. Not reconnecting.`);
591
+ this.isShuttingDown = true;
592
+ this.clearReconnectTimeout();
593
+ const error = new RegistrationRejectedError(init);
594
+ this.fatalError = error;
595
+ for (const [, invocation] of this.invocations) {
596
+ if (invocation.timeout) clearTimeout(invocation.timeout);
597
+ invocation.reject(error);
598
+ }
599
+ this.invocations.clear();
600
+ this.setConnectionState("failed");
601
+ this.ws?.close();
602
+ }
522
603
  };
523
604
  /**
524
605
  * Factory object that constructs routing actions for {@link ISdk.trigger}.
@@ -567,5 +648,5 @@ const TriggerAction = {
567
648
  const registerWorker = (address, options) => new Sdk(address, options);
568
649
 
569
650
  //#endregion
570
- export { ChannelReader, ChannelWriter, EngineFunctions, EngineTriggers, TriggerAction, registerWorker };
651
+ export { ChannelReader, ChannelWriter, EngineFunctions, EngineTriggers, RegistrationRejectedError, TriggerAction, registerWorker };
571
652
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/iii-constants.ts","../src/iii-types.ts","../src/iii.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} as const\n\n/** Connection state for the III WebSocket */\nexport type IIIConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | '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","export 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 TriggerRegistrationResultMessage = {\n message_type: MessageType.TriggerRegistrationResult\n id: string\n type: string\n function_id: string\n result?: unknown\n error?: unknown\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}\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 metadata?: Record<string, unknown>\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 auth function during WebSocket upgrade.\n * Contains the HTTP headers, query parameters, and client IP from the\n * connecting worker's upgrade request.\n */\nexport type AuthInput = {\n /** HTTP headers from the WebSocket upgrade request. */\n headers: Record<string, string>\n /** Query parameters from the upgrade URL. Each key maps to an array of values to support repeated keys. */\n query_params: Record<string, string[]>\n /** IP address of the connecting client. */\n ip_address: string\n}\n\n/**\n * Return value from the RBAC auth function. Controls which functions the\n * authenticated worker can invoke and what context is forwarded to the\n * middleware.\n */\nexport type AuthResult = {\n /** Additional function IDs to allow beyond the `expose_functions` config. Defaults to `[]` if omitted. */\n allowed_functions?: string[]\n /** Function IDs to deny even if they match `expose_functions`. Takes precedence over allowed. Defaults to `[]` if omitted. */\n forbidden_functions?: string[]\n /** Trigger type IDs the worker may register triggers for. When omitted, all types are allowed. */\n allowed_trigger_types?: string[]\n /** Whether the worker may register new trigger types. Defaults to `false` if omitted. */\n allow_trigger_type_registration?: boolean\n /** Whether the worker may register new functions. Defaults to `true` if omitted. */\n allow_function_registration?: boolean\n /** Arbitrary context forwarded to the middleware function on every invocation. Defaults to `{}` if omitted. */\n context?: Record<string, unknown>\n /** Optional prefix applied to all function IDs registered by this worker. */\n function_registration_prefix?: string\n}\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 * Input passed to the `on_trigger_type_registration_function_id` hook\n * when a worker attempts to register a new trigger type through the RBAC port.\n * Return an {@link OnTriggerTypeRegistrationResult} with the (possibly mapped)\n * fields, or throw to deny the registration.\n */\nexport type OnTriggerTypeRegistrationInput = {\n /** ID of the trigger type being registered. */\n trigger_type_id: string\n /** Human-readable description of the trigger type. */\n description: string\n /** Auth context from `AuthResult.context` for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Result returned from the `on_trigger_type_registration_function_id` hook.\n * All fields are optional; omitted fields keep the original value from the\n * registration request.\n */\nexport type OnTriggerTypeRegistrationResult = {\n /** Mapped trigger type ID. */\n trigger_type_id?: string\n /** Mapped description. */\n description?: string\n}\n\n/**\n * Input passed to the `on_trigger_registration_function_id` hook\n * when a worker attempts to register a trigger through the RBAC port.\n * Return an {@link OnTriggerRegistrationResult} with the (possibly mapped)\n * fields, or throw to deny the registration.\n */\nexport type OnTriggerRegistrationInput = {\n /** ID of the trigger being registered. */\n trigger_id: string\n /** Trigger type identifier. */\n trigger_type: string\n /** ID of the function this trigger is bound to. */\n function_id: string\n /** Trigger-specific configuration. */\n config: unknown\n /** Auth context from `AuthResult.context` for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Result returned from the `on_trigger_registration_function_id` hook.\n * All fields are optional; omitted fields keep the original value from the\n * registration request.\n */\nexport type OnTriggerRegistrationResult = {\n /** Mapped trigger ID. */\n trigger_id?: string\n /** Mapped trigger type. */\n trigger_type?: string\n /** Mapped function ID. */\n function_id?: string\n /** Mapped trigger configuration. */\n config?: unknown\n}\n\n/**\n * Input passed to the `on_function_registration_function_id` hook\n * when a worker attempts to register a function through the RBAC port.\n * Return an {@link OnFunctionRegistrationResult} with the (possibly mapped)\n * fields, or throw to deny the registration.\n */\nexport type OnFunctionRegistrationInput = {\n /** ID of the function being registered. */\n function_id: string\n /** Human-readable description of the function. */\n description?: string\n /** Arbitrary metadata attached to the function. */\n metadata?: Record<string, unknown>\n /** Auth context from `AuthResult.context` for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Result returned from the `on_function_registration_function_id` hook.\n * All fields are optional; omitted fields keep the original value from the\n * registration request.\n */\nexport type OnFunctionRegistrationResult = {\n /** Mapped function ID. */\n function_id?: string\n /** Mapped description. */\n description?: string\n /** Mapped metadata. */\n metadata?: Record<string, unknown>\n}\n\n/**\n * Result returned when a function is invoked with `TriggerAction.Enqueue`.\n */\nexport type EnqueueResult = {\n /** Unique receipt ID for the enqueued message. */\n messageReceiptId: string\n}\n\n/**\n * Request object passed to {@link ISdk.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}\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\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 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","import { ChannelReader, ChannelWriter } from './channels'\nimport {\n DEFAULT_BRIDGE_RECONNECTION_CONFIG,\n DEFAULT_INVOCATION_TIMEOUT_MS,\n type IIIConnectionState,\n type IIIReconnectionConfig,\n} from './iii-constants'\nimport {\n type IIIMessage,\n type InvocationResultMessage,\n type InvokeFunctionMessage,\n MessageType,\n type RegisterFunctionMessage,\n type RegisterTriggerMessage,\n type RegisterTriggerTypeMessage,\n type StreamChannelRef,\n type TriggerRegistrationResultMessage,\n type TriggerRequest,\n} from './iii-types'\nimport type { IStream } from './stream'\nimport type { TriggerHandler } from './triggers'\nimport type {\n FunctionRef,\n Invocation,\n ISdk,\n RegisterFunctionOptions,\n RemoteFunctionData,\n RemoteFunctionHandler,\n RemoteTriggerTypeData,\n Trigger,\n TriggerTypeRef,\n} from './types'\nimport { isChannelRef, randomUUID } from './utils'\n\n/** @internal */\nexport type TelemetryOptions = {\n language?: string\n project_name?: string\n framework?: string\n amplitude_api_key?: string\n}\n\n/**\n * Configuration options passed to {@link registerWorker}.\n *\n * @example\n * ```typescript\n * const worker = registerWorker('ws://localhost:49135', {\n * invocationTimeoutMs: 10000,\n * reconnectionConfig: { maxRetries: 5 },\n * })\n * ```\n */\nexport type InitOptions = {\n /** Default timeout for `worker.trigger()` invocations in milliseconds. Defaults to `30000`. */\n invocationTimeoutMs?: number\n /**\n * WebSocket reconnection behavior.\n *\n * @see {@link IIIReconnectionConfig} for available fields and defaults.\n */\n reconnectionConfig?: Partial<IIIReconnectionConfig>\n /** Browser WebSocket connections authenticate via query parameters or cookies; the `headers` option is ignored. */\n headers?: Record<string, string>\n}\n\nclass Sdk implements ISdk {\n private ws?: WebSocket\n private functions = new Map<string, RemoteFunctionData>()\n private invocations = new Map<string, Invocation & { timeout?: ReturnType<typeof setTimeout> }>()\n private triggers = new Map<string, RegisterTriggerMessage>()\n private triggerTypes = new Map<string, RemoteTriggerTypeData>()\n private messagesToSend: Record<string, unknown>[] = []\n private reconnectTimeout?: ReturnType<typeof setTimeout>\n private invocationTimeoutMs: number\n private reconnectionConfig: IIIReconnectionConfig\n private reconnectAttempt = 0\n private connectionState: IIIConnectionState = 'disconnected'\n private connectionListeners = new Set<(state: IIIConnectionState) => void>()\n private isShuttingDown = false\n private workerId?: string\n private reattachToken?: string\n\n constructor(\n private readonly address: string,\n private readonly options?: InitOptions,\n ) {\n this.invocationTimeoutMs = options?.invocationTimeoutMs ?? DEFAULT_INVOCATION_TIMEOUT_MS\n this.reconnectionConfig = {\n ...DEFAULT_BRIDGE_RECONNECTION_CONFIG,\n ...options?.reconnectionConfig,\n }\n\n this.connect()\n }\n\n /**\n * Registers a custom trigger type with the engine. A trigger type defines\n * how external events (HTTP, cron, queue, etc.) map to function invocations.\n *\n * @param triggerType - Trigger type registration input.\n * @param triggerType.id - Unique trigger type identifier.\n * @param triggerType.description - Human-readable description.\n * @param handler - Handler with `registerTrigger` / `unregisterTrigger` callbacks.\n *\n * @example\n * ```typescript\n * worker.registerTriggerType(\n * { id: 'my-trigger', description: 'Custom trigger' },\n * {\n * async registerTrigger({ id, function_id, config }) { },\n * async unregisterTrigger({ id, function_id, config }) { },\n * },\n * )\n * ```\n */\n registerTriggerType = <TConfig>(\n triggerType: Omit<RegisterTriggerTypeMessage, 'message_type'>,\n handler: TriggerHandler<TConfig>,\n ): TriggerTypeRef<TConfig> => {\n this.sendMessage(MessageType.RegisterTriggerType, triggerType, true)\n this.triggerTypes.set(triggerType.id, {\n message: { ...triggerType, message_type: MessageType.RegisterTriggerType },\n handler,\n })\n\n return {\n id: triggerType.id,\n registerTrigger: (functionId: string, config: TConfig) => {\n return this.registerTrigger({\n type: triggerType.id,\n function_id: functionId,\n config,\n })\n },\n registerFunction: (functionId, handler, config) => {\n const ref = this.registerFunction(functionId, handler)\n this.registerTrigger({\n type: triggerType.id,\n function_id: functionId,\n config,\n })\n return ref\n },\n unregister: () => {\n this.unregisterTriggerType(triggerType)\n },\n }\n }\n\n /**\n * Unregisters a previously registered trigger type.\n *\n * @param triggerType - The trigger type to unregister (must match the `id` used during registration).\n */\n unregisterTriggerType = (triggerType: Omit<RegisterTriggerTypeMessage, 'message_type'>): void => {\n this.sendMessage(MessageType.UnregisterTriggerType, triggerType, true)\n this.triggerTypes.delete(triggerType.id)\n }\n\n /**\n * Binds a trigger configuration to a registered function. When the trigger\n * fires, the engine invokes the target function.\n *\n * @param trigger - Trigger registration input.\n * @param trigger.type - Trigger type (e.g. `http`, `durable:subscriber`, `cron`).\n * @param trigger.function_id - ID of the function to invoke.\n * @param trigger.config - Trigger-specific configuration.\n * @returns A {@link Trigger} handle with an `unregister()` method.\n *\n * @example\n * ```typescript\n * const trigger = worker.registerTrigger({\n * type: 'http',\n * function_id: 'greet',\n * config: { api_path: '/greet', http_method: 'GET' },\n * })\n *\n * // Later...\n * trigger.unregister()\n * ```\n */\n registerTrigger = (trigger: Omit<RegisterTriggerMessage, 'message_type' | 'id'>): Trigger => {\n const id = randomUUID()\n const fullTrigger: RegisterTriggerMessage = {\n ...trigger,\n id,\n message_type: MessageType.RegisterTrigger,\n }\n this.sendMessage(MessageType.RegisterTrigger, fullTrigger, true)\n this.triggers.set(id, fullTrigger)\n\n return {\n unregister: () => {\n this.sendMessage(MessageType.UnregisterTrigger, {\n id,\n message_type: MessageType.UnregisterTrigger,\n type: fullTrigger.type,\n })\n this.triggers.delete(id)\n },\n }\n }\n\n /**\n * Registers a function with the engine. The `functionId` is the unique identifier\n * used by triggers and invocations.\n *\n * The handler runs locally in the browser session; HTTP invocation configs\n * are a Node.js SDK feature and are not accepted here.\n *\n * @param functionId - Unique function identifier.\n * @param handlerOrInvocation - Async handler executed when the function is invoked.\n * @param options - Optional function registration options (description, request/response formats, metadata).\n * @returns A {@link FunctionRef} with `id` and `unregister()`.\n *\n * @example\n * ```typescript\n * const fn = worker.registerFunction(\n * 'greet',\n * async (input: { name: string }) => {\n * return { message: `Hello, ${input.name}!` }\n * },\n * { description: 'Greets a user' },\n * )\n * ```\n */\n registerFunction = (\n functionId: string,\n handlerOrInvocation: RemoteFunctionHandler,\n options?: RegisterFunctionOptions,\n ): FunctionRef => {\n if (!functionId || functionId.trim() === '') {\n throw new Error('id is required')\n }\n if (this.functions.has(functionId)) {\n throw new Error(`function id already registered: ${functionId}`)\n }\n\n const fullMessage: RegisterFunctionMessage = {\n ...options,\n id: functionId,\n message_type: MessageType.RegisterFunction,\n }\n\n this.sendMessage(MessageType.RegisterFunction, fullMessage, true)\n\n const handler = handlerOrInvocation as RemoteFunctionHandler\n this.functions.set(functionId, {\n message: fullMessage,\n handler: async (input, _traceparent?: string, _baggage?: string) => {\n return await handler(input)\n },\n })\n\n return {\n id: functionId,\n unregister: () => {\n this.sendMessage(MessageType.UnregisterFunction, { id: functionId }, true)\n this.functions.delete(functionId)\n },\n }\n }\n\n /**\n * @internal Implementation backing the `createChannel` helper in the\n * `iii-browser-sdk/helpers` submodule. Not part of the public `ISdk` surface.\n *\n * Creates a streaming channel pair for worker-to-worker data transfer.\n * Returns a {@link Channel} with a local writer/reader and serializable refs\n * that can be passed as fields in invocation data to other functions.\n */\n __helpers_create_channel = async (bufferSize?: number): Promise<import('./types').Channel> => {\n const result = await this.trigger<{ buffer_size?: number }, { writer: StreamChannelRef; reader: StreamChannelRef }>(\n { function_id: 'engine::channels::create', payload: { buffer_size: bufferSize } },\n )\n\n return {\n writer: new ChannelWriter(this.address, result.writer),\n reader: new ChannelReader(this.address, result.reader),\n writerRef: result.writer,\n readerRef: result.reader,\n }\n }\n\n /**\n * Invokes a remote function. The routing behavior and return type depend\n * on the `action` field of the request.\n *\n * | `action` | Behavior | Return type |\n * |-------------------------------|----------------------------------------------------|----------------------- |\n * | _(none)_ | Synchronous: waits for the function to return | `Promise<TOutput>` |\n * | `TriggerAction.Enqueue(...)` | Async via named queue; engine acknowledges enqueue | `Promise<EnqueueResult>` |\n * | `TriggerAction.Void()` | Fire-and-forget, no response | `Promise<undefined>` |\n *\n * @param request - The trigger request.\n * @param request.function_id - ID of the function to invoke.\n * @param request.payload - Payload to pass to the function.\n * @param request.action - Routing action. Omit for synchronous request/response.\n * @param request.timeoutMs - Override the default invocation timeout.\n * @returns The result of the function invocation.\n *\n * @example\n * ```typescript\n * import { TriggerAction } from 'iii-browser-sdk'\n *\n * // Synchronous\n * const result = await worker.trigger({ function_id: 'get-order', payload: { id: '123' } })\n *\n * // Enqueue\n * const { messageReceiptId } = await worker.trigger({\n * function_id: 'payments::charge',\n * payload: { orderId: '123', amount: 49.99 },\n * action: TriggerAction.Enqueue({ queue: 'payment' }),\n * })\n *\n * // Fire-and-forget\n * worker.trigger({\n * function_id: 'notifications::send',\n * payload: { userId: '123' },\n * action: TriggerAction.Void(),\n * })\n * ```\n */\n // biome-ignore lint/suspicious/noExplicitAny: TOutput defaults to any so untyped calls type-check (the engine cannot express the return type statically)\n trigger = async <TInput = unknown, TOutput = any>(\n request: TriggerRequest<TInput>,\n ): Promise<TOutput> => {\n const { function_id, payload, action, timeoutMs } = request\n const effectiveTimeout = timeoutMs ?? this.invocationTimeoutMs\n\n if (action?.type === 'void') {\n this.sendMessage(MessageType.InvokeFunction, {\n function_id,\n data: payload,\n action,\n })\n return undefined as TOutput\n }\n\n const invocation_id = randomUUID()\n\n return new Promise<TOutput>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const invocation = this.invocations.get(invocation_id)\n if (invocation) {\n this.invocations.delete(invocation_id)\n reject(new Error(`Invocation timeout after ${effectiveTimeout}ms: ${function_id}`))\n }\n }, effectiveTimeout)\n\n this.invocations.set(invocation_id, {\n resolve: (result: TOutput) => {\n clearTimeout(timeout)\n resolve(result)\n },\n reject: (error: unknown) => {\n clearTimeout(timeout)\n reject(error)\n },\n timeout,\n })\n\n this.sendMessage(MessageType.InvokeFunction, {\n invocation_id,\n function_id,\n data: payload,\n action,\n })\n })\n }\n\n /**\n * @internal Implementation backing the `createStream` helper in the\n * `iii-browser-sdk/helpers` submodule. Not part of the public `ISdk` surface.\n *\n * Registers a custom stream implementation, overriding the engine default\n * for the given stream name.\n */\n __helpers_create_stream = <TData>(streamName: string, stream: IStream<TData>): void => {\n this.registerFunction(`stream::get(${streamName})`, stream.get.bind(stream))\n this.registerFunction(`stream::set(${streamName})`, stream.set.bind(stream))\n this.registerFunction(`stream::delete(${streamName})`, stream.delete.bind(stream))\n this.registerFunction(`stream::list(${streamName})`, stream.list.bind(stream))\n this.registerFunction(`stream::list_groups(${streamName})`, stream.listGroups.bind(stream))\n }\n\n /**\n * Gracefully shutdown the SDK, cleaning up all resources.\n */\n shutdown = async (): Promise<void> => {\n this.isShuttingDown = true\n\n this.clearReconnectTimeout()\n\n for (const [_id, invocation] of this.invocations) {\n if (invocation.timeout) {\n clearTimeout(invocation.timeout)\n }\n invocation.reject(new Error('iii is shutting down'))\n }\n this.invocations.clear()\n\n if (this.ws) {\n this.ws.onopen = null\n this.ws.onclose = null\n this.ws.onerror = null\n this.ws.onmessage = null\n this.ws.close()\n this.ws = undefined\n }\n\n this.setConnectionState('disconnected')\n }\n\n /**\n * Subscribe to connection-state transitions. The handler is fired immediately\n * with the current state, then on every transition. Multiple listeners are\n * supported. Returns an unsubscribe function.\n */\n addConnectionStateListener = (handler: (state: IIIConnectionState) => void): (() => void) => {\n this.connectionListeners.add(handler)\n try {\n handler(this.connectionState)\n } catch (e) {\n console.error('[iii] connection listener threw on initial fire', e)\n }\n return () => {\n this.connectionListeners.delete(handler)\n }\n }\n\n // private methods\n\n private setConnectionState(state: IIIConnectionState): void {\n if (this.connectionState !== state) {\n this.connectionState = state\n for (const handler of this.connectionListeners) {\n try {\n handler(state)\n } catch (e) {\n console.error('[iii] connection listener threw', e)\n }\n }\n }\n }\n\n private connect(): void {\n if (this.isShuttingDown) {\n return\n }\n\n this.setConnectionState('connecting')\n this.ws = new WebSocket(this.address)\n this.ws.onopen = this.onSocketOpen.bind(this)\n this.ws.onclose = this.onSocketClose.bind(this)\n this.ws.onerror = this.onSocketError.bind(this)\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = undefined\n }\n }\n\n private scheduleReconnect(): void {\n if (this.isShuttingDown) {\n return\n }\n\n const { maxRetries, initialDelayMs, backoffMultiplier, maxDelayMs, jitterFactor } = this.reconnectionConfig\n\n if (maxRetries !== -1 && this.reconnectAttempt >= maxRetries) {\n this.setConnectionState('failed')\n console.error(`[iii] Max reconnection retries (${maxRetries}) reached, giving up`)\n return\n }\n\n if (this.reconnectTimeout) {\n return\n }\n\n const exponentialDelay = initialDelayMs * backoffMultiplier ** this.reconnectAttempt\n const cappedDelay = Math.min(exponentialDelay, maxDelayMs)\n const jitter = cappedDelay * jitterFactor * (2 * Math.random() - 1)\n const delay = Math.floor(cappedDelay + jitter)\n\n this.setConnectionState('reconnecting')\n console.debug(`[iii] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt + 1})...`)\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = undefined\n this.reconnectAttempt++\n this.connect()\n }, delay)\n }\n\n private onSocketError(): void {\n console.error('[iii] WebSocket error')\n }\n\n private onSocketClose(): void {\n if (this.ws) {\n this.ws.onopen = null\n this.ws.onclose = null\n this.ws.onerror = null\n this.ws.onmessage = null\n }\n this.ws = undefined\n\n this.setConnectionState('disconnected')\n this.scheduleReconnect()\n }\n\n private onSocketOpen(): void {\n this.clearReconnectTimeout()\n this.reconnectAttempt = 0\n this.setConnectionState('connected')\n\n if (this.ws) {\n this.ws.onmessage = this.onMessage.bind(this)\n }\n\n // Reconnect: present the previous engine-assigned identity BEFORE the\n // registration replay so the engine retires the old connection and the\n // replay lands on a clean slate instead of racing its cleanup. The\n // token proves we ARE that worker (ids alone are publicly listable).\n if (this.workerId) {\n this.sendMessageRaw(\n JSON.stringify({\n type: MessageType.Reattach,\n previous_worker_id: this.workerId,\n reattach_token: this.reattachToken,\n }),\n )\n }\n\n this.triggerTypes.forEach(({ message }) => {\n this.sendMessage(MessageType.RegisterTriggerType, message, true)\n })\n this.functions.forEach(({ message }) => {\n this.sendMessage(MessageType.RegisterFunction, message, true)\n })\n this.triggers.forEach((trigger) => {\n this.sendMessage(MessageType.RegisterTrigger, trigger, true)\n })\n\n const pending = this.messagesToSend\n this.messagesToSend = []\n for (const message of pending) {\n if (\n message.type === MessageType.InvokeFunction &&\n typeof message.invocation_id === 'string' &&\n !this.invocations.has(message.invocation_id)\n ) {\n continue\n }\n this.sendMessageRaw(JSON.stringify(message))\n }\n }\n\n private isOpen(): boolean {\n return this.ws?.readyState === WebSocket.OPEN\n }\n\n private sendMessageRaw(data: string): void {\n if (this.ws && this.isOpen()) {\n try {\n this.ws.send(data)\n } catch (error) {\n console.error('[iii] Exception while sending message', error)\n }\n }\n }\n\n private toWireFormat(messageType: MessageType, message: Omit<IIIMessage, 'message_type'>): Record<string, unknown> {\n const { message_type: _, ...rest } = message as Record<string, unknown>\n if (messageType === MessageType.RegisterTrigger && 'type' in message) {\n const { type: triggerType, ...triggerRest } = message as RegisterTriggerMessage\n return { type: messageType, ...triggerRest, trigger_type: triggerType }\n }\n if (messageType === MessageType.UnregisterTrigger && 'type' in message) {\n const { type: triggerType, ...triggerRest } = message as RegisterTriggerMessage\n return { type: messageType, ...triggerRest, trigger_type: triggerType }\n }\n if (messageType === MessageType.TriggerRegistrationResult && 'type' in message) {\n const { type: triggerType, ...resultRest } = message as TriggerRegistrationResultMessage\n return { type: messageType, ...resultRest, trigger_type: triggerType }\n }\n return { type: messageType, ...rest } as Record<string, unknown>\n }\n\n private sendMessage(messageType: MessageType, message: Omit<IIIMessage, 'message_type'>, skipIfClosed = false): void {\n const wireMessage = this.toWireFormat(messageType, message)\n if (this.isOpen()) {\n this.sendMessageRaw(JSON.stringify(wireMessage))\n } else if (!skipIfClosed) {\n this.messagesToSend.push(wireMessage)\n }\n }\n\n private onInvocationResult(invocation_id: string, result: unknown, error: unknown): void {\n const invocation = this.invocations.get(invocation_id)\n\n if (invocation) {\n if (invocation.timeout) {\n clearTimeout(invocation.timeout)\n }\n error ? invocation.reject(error) : invocation.resolve(result)\n }\n\n this.invocations.delete(invocation_id)\n }\n\n private resolveChannelValue(value: unknown): unknown {\n if (isChannelRef(value)) {\n return value.direction === 'read'\n ? new ChannelReader(this.address, value)\n : new ChannelWriter(this.address, value)\n }\n if (Array.isArray(value)) {\n return value.map((item) => this.resolveChannelValue(item))\n }\n if (value !== null && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = this.resolveChannelValue(v)\n }\n return out\n }\n return value\n }\n\n private async onInvokeFunction<TInput>(\n invocation_id: string | undefined,\n function_id: string,\n input: TInput,\n traceparent?: string,\n baggage?: string,\n ): Promise<unknown> {\n const fn = this.functions.get(function_id)\n\n const resolvedInput = this.resolveChannelValue(input) as TInput\n\n if (fn?.handler) {\n if (!invocation_id) {\n try {\n await fn.handler(resolvedInput, traceparent, baggage)\n } catch (error) {\n console.error(`[iii] Error invoking function ${function_id}`, error)\n }\n return\n }\n\n try {\n const result = await fn.handler(resolvedInput, traceparent, baggage)\n this.sendMessage(MessageType.InvocationResult, {\n invocation_id,\n function_id,\n result,\n traceparent,\n baggage,\n })\n } catch (error) {\n const isError = error instanceof Error\n this.sendMessage(MessageType.InvocationResult, {\n invocation_id,\n function_id,\n error: {\n code: 'invocation_failed',\n message: isError ? error.message : String(error),\n stacktrace: isError ? error.stack : undefined,\n },\n traceparent,\n baggage,\n })\n }\n } else {\n const errorCode = fn ? 'function_not_invokable' : 'function_not_found'\n const errorMessage = fn ? 'Function is HTTP-invoked and cannot be invoked locally' : 'Function not found'\n if (invocation_id) {\n this.sendMessage(MessageType.InvocationResult, {\n invocation_id,\n function_id,\n error: { code: errorCode, message: errorMessage },\n traceparent,\n baggage,\n })\n }\n }\n }\n\n private async onRegisterTrigger(message: { trigger_type: string; id: string; function_id: string; config: unknown }) {\n const { trigger_type, id, function_id, config } = message\n const triggerTypeData = this.triggerTypes.get(trigger_type)\n\n if (triggerTypeData) {\n try {\n await triggerTypeData.handler.registerTrigger({ id, function_id, config })\n this.sendMessage(MessageType.TriggerRegistrationResult, {\n id,\n message_type: MessageType.TriggerRegistrationResult,\n type: trigger_type,\n function_id,\n })\n } catch (error) {\n this.sendMessage(MessageType.TriggerRegistrationResult, {\n id,\n message_type: MessageType.TriggerRegistrationResult,\n type: trigger_type,\n function_id,\n error: { code: 'trigger_registration_failed', message: (error as Error).message },\n })\n }\n } else {\n this.sendMessage(MessageType.TriggerRegistrationResult, {\n id,\n message_type: MessageType.TriggerRegistrationResult,\n type: trigger_type,\n function_id,\n error: { code: 'trigger_type_not_found', message: 'Trigger type not found' },\n })\n }\n }\n\n private async onUnregisterTrigger(message: {\n trigger_type?: string\n id: string\n function_id?: string\n config?: unknown\n }) {\n const trigger_type = message.trigger_type\n if (!trigger_type) return\n\n const triggerTypeData = this.triggerTypes.get(trigger_type)\n if (!triggerTypeData) return\n\n const { id, function_id = '', config } = message\n try {\n await triggerTypeData.handler.unregisterTrigger({ id, function_id, config })\n } catch (error) {\n console.error(`[iii] Error unregistering trigger ${id}`, error)\n }\n }\n\n private onMessage(event: MessageEvent): void {\n let msgType: MessageType\n let message: Record<string, unknown>\n\n try {\n const parsed = JSON.parse(typeof event.data === 'string' ? event.data : '') as Record<string, unknown>\n msgType = parsed.type as MessageType\n const { type: _, ...rest } = parsed\n message = rest\n } catch (error) {\n console.error('[iii] Failed to parse incoming message', error)\n return\n }\n\n if (msgType === MessageType.InvocationResult) {\n const { invocation_id, result, error } = message as InvocationResultMessage\n this.onInvocationResult(invocation_id, result, error)\n } else if (msgType === MessageType.InvokeFunction) {\n const { invocation_id, function_id, data, traceparent, baggage } = message as InvokeFunctionMessage\n this.onInvokeFunction(invocation_id, function_id, data, traceparent, baggage)\n } else if (msgType === MessageType.RegisterTrigger) {\n this.onRegisterTrigger(message as { trigger_type: string; id: string; function_id: string; config: unknown })\n } else if (msgType === MessageType.UnregisterTrigger) {\n this.onUnregisterTrigger(\n message as { trigger_type?: string; id: string; function_id?: string; config?: unknown },\n )\n } else if (msgType === MessageType.WorkerRegistered) {\n const { worker_id, reattach_token } = message as { worker_id: string; reattach_token?: string }\n this.workerId = worker_id\n this.reattachToken = reattach_token\n }\n }\n}\n\n/**\n * Factory object that constructs routing actions for {@link ISdk.trigger}.\n *\n * @example\n * ```typescript\n * import { TriggerAction } from 'iii-browser-sdk'\n *\n * // Enqueue to a named queue\n * worker.trigger({\n * function_id: 'process',\n * payload: { data: 'hello' },\n * action: TriggerAction.Enqueue({ queue: 'jobs' }),\n * })\n *\n * // Fire-and-forget\n * worker.trigger({\n * function_id: 'notify',\n * payload: {},\n * action: TriggerAction.Void(),\n * })\n * ```\n */\nexport const TriggerAction = {\n /**\n * Routes the invocation through a named queue. The engine enqueues the job,\n * acknowledges the caller with `{ messageReceiptId }`, and processes it\n * asynchronously.\n *\n * @param opts - Queue routing options.\n * @param opts.queue - Name of the target queue.\n */\n Enqueue: (opts: { queue: string }) => ({ type: 'enqueue' as const, ...opts }),\n /**\n * Fire-and-forget routing. The engine forwards the invocation without\n * waiting for a response or queuing the job.\n */\n Void: () => ({ type: 'void' as const }),\n} as const\n\n/**\n * Register the worker with a iii instance, returns a connected worker client.\n * The WebSocket connection is established automatically.\n *\n * @param address - WebSocket URL of the III engine (e.g. `ws://localhost:49135`).\n * @param options - Optional {@link InitOptions} for worker name, timeouts, and reconnection.\n * @returns A connected {@link ISdk} instance.\n *\n * @example\n * ```typescript\n * import { registerWorker } from 'iii-browser-sdk'\n *\n * const worker = registerWorker('ws://localhost:49135')\n * ```\n */\nexport const registerWorker = (address: string, options?: InitOptions): ISdk => new Sdk(address, options)\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/errors.ts","../src/iii-constants.ts","../src/iii-types.ts","../src/iii.ts"],"sourcesContent":["export type RegistrationRejectedInit = {\n code: string\n namespace: string\n worker_name?: string\n function_id?: string\n owner_worker_id: string\n}\n\n/**\n * A terminal registration rejection from the engine. Thrown into every pending\n * invocation and exposed via `getFatalError()` when a worker-name collision\n * (or other non-retryable rejection) closes the connection for good.\n */\nexport class RegistrationRejectedError extends Error {\n public readonly code: string\n public readonly namespace: string\n public readonly worker_name?: string\n public readonly function_id?: string\n public readonly owner_worker_id: string\n\n constructor(init: RegistrationRejectedInit) {\n super(\n `${init.code}: registration rejected for ${init.function_id !== undefined ? `function \"${init.function_id}\"` : `worker \"${init.worker_name ?? '<unknown>'}\"`} in namespace \"${init.namespace}\" (already owned by worker ${init.owner_worker_id})`,\n )\n this.name = 'RegistrationRejectedError'\n this.code = init.code\n this.namespace = init.namespace\n this.worker_name = init.worker_name\n this.function_id = init.function_id\n this.owner_worker_id = init.owner_worker_id\n }\n}\n","/**\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} as const\n\n/** Connection state for the III WebSocket */\nexport type IIIConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | '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","export 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 RegistrationRejected = 'registrationrejected',\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 TriggerRegistrationResultMessage = {\n message_type: MessageType.TriggerRegistrationResult\n id: string\n type: string\n function_id: string\n result?: unknown\n error?: unknown\n}\n\n/**\n * The engine refused a registration. `FUNCTION_NAMESPACE_CONFLICT` costs one\n * function and leaves the connection open; `WORKER_NAMESPACE_CONFLICT` is\n * terminal — another live worker owns this name in the namespace.\n */\nexport type RegistrationRejectedMessage = {\n message_type: MessageType.RegistrationRejected\n /** Rejection code: `FUNCTION_NAMESPACE_CONFLICT` or `WORKER_NAMESPACE_CONFLICT`. */\n code: string\n /** Namespace the conflict occurred in. */\n namespace: string\n /** Contested worker name. Present only for `WORKER_NAMESPACE_CONFLICT`. */\n worker_name?: string\n /** Contested function id. Present only for `FUNCTION_NAMESPACE_CONFLICT`. */\n function_id?: string\n /** ID of the worker that already owns the name. */\n owner_worker_id: string\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 /**\n * Namespace the trigger's target function resolves in. Omit for the engine's\n * default namespace, independent of this connection's namespace.\n */\n namespace?: string\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 metadata?: Record<string, unknown>\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 auth function during WebSocket upgrade.\n * Contains the HTTP headers, query parameters, and client IP from the\n * connecting worker's upgrade request.\n */\nexport type AuthInput = {\n /** HTTP headers from the WebSocket upgrade request. */\n headers: Record<string, string>\n /** Query parameters from the upgrade URL. Each key maps to an array of values to support repeated keys. */\n query_params: Record<string, string[]>\n /** IP address of the connecting client. */\n ip_address: string\n}\n\n/**\n * Return value from the RBAC auth function. Controls which functions the\n * authenticated worker can invoke and what context is forwarded to the\n * middleware.\n */\nexport type AuthResult = {\n /** Additional function IDs to allow beyond the `expose_functions` config. Defaults to `[]` if omitted. */\n allowed_functions?: string[]\n /** Function IDs to deny even if they match `expose_functions`. Takes precedence over allowed. Defaults to `[]` if omitted. */\n forbidden_functions?: string[]\n /** Trigger type IDs the worker may register triggers for. When omitted, all types are allowed. */\n allowed_trigger_types?: string[]\n /** Whether the worker may register new trigger types. Defaults to `false` if omitted. */\n allow_trigger_type_registration?: boolean\n /** Whether the worker may register new functions. Defaults to `true` if omitted. */\n allow_function_registration?: boolean\n /** Arbitrary context forwarded to the middleware function on every invocation. Defaults to `{}` if omitted. */\n context?: Record<string, unknown>\n /** Optional prefix applied to all function IDs registered by this worker. */\n function_registration_prefix?: string\n}\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 * Target namespace the invoke addressed; forward the call here to stay in the\n * caller's namespace. Absent → the engine's default namespace.\n */\n namespace?: string\n}\n\n/**\n * Input passed to the `on_trigger_type_registration_function_id` hook\n * when a worker attempts to register a new trigger type through the RBAC port.\n * Return an {@link OnTriggerTypeRegistrationResult} with the (possibly mapped)\n * fields, or throw to deny the registration.\n */\nexport type OnTriggerTypeRegistrationInput = {\n /** ID of the trigger type being registered. */\n trigger_type_id: string\n /** Human-readable description of the trigger type. */\n description: string\n /** Auth context from `AuthResult.context` for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Result returned from the `on_trigger_type_registration_function_id` hook.\n * All fields are optional; omitted fields keep the original value from the\n * registration request.\n */\nexport type OnTriggerTypeRegistrationResult = {\n /** Mapped trigger type ID. */\n trigger_type_id?: string\n /** Mapped description. */\n description?: string\n}\n\n/**\n * Input passed to the `on_trigger_registration_function_id` hook\n * when a worker attempts to register a trigger through the RBAC port.\n * Return an {@link OnTriggerRegistrationResult} with the (possibly mapped)\n * fields, or throw to deny the registration.\n */\nexport type OnTriggerRegistrationInput = {\n /** ID of the trigger being registered. */\n trigger_id: string\n /** Trigger type identifier. */\n trigger_type: string\n /** ID of the function this trigger is bound to. */\n function_id: string\n /** Trigger-specific configuration. */\n config: unknown\n /**\n * Namespace the trigger's target resolves in (explicit, or `default` when\n * absent). The same id can exist in several namespaces, so the hook needs this\n * to authorize per target namespace.\n */\n namespace?: string\n /** Auth context from `AuthResult.context` for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Result returned from the `on_trigger_registration_function_id` hook.\n * All fields are optional; omitted fields keep the original value from the\n * registration request.\n */\nexport type OnTriggerRegistrationResult = {\n /** Mapped trigger ID. */\n trigger_id?: string\n /** Mapped trigger type. */\n trigger_type?: string\n /** Mapped function ID. */\n function_id?: string\n /** Mapped trigger configuration. */\n config?: unknown\n}\n\n/**\n * Input passed to the `on_function_registration_function_id` hook\n * when a worker attempts to register a function through the RBAC port.\n * Return an {@link OnFunctionRegistrationResult} with the (possibly mapped)\n * fields, or throw to deny the registration.\n */\nexport type OnFunctionRegistrationInput = {\n /** ID of the function being registered. */\n function_id: string\n /** Human-readable description of the function. */\n description?: string\n /** Arbitrary metadata attached to the function. */\n metadata?: Record<string, unknown>\n /**\n * Namespace the function registers in. The same id can exist in several\n * namespaces, so the hook needs this to authorize per namespace.\n */\n namespace?: string\n /** Auth context from `AuthResult.context` for this session. */\n context: Record<string, unknown>\n}\n\n/**\n * Result returned from the `on_function_registration_function_id` hook.\n * All fields are optional; omitted fields keep the original value from the\n * registration request.\n */\nexport type OnFunctionRegistrationResult = {\n /** Mapped function ID. */\n function_id?: string\n /** Mapped description. */\n description?: string\n /** Mapped metadata. */\n metadata?: Record<string, unknown>\n}\n\n/**\n * Result returned when a function is invoked with `TriggerAction.Enqueue`.\n */\nexport type EnqueueResult = {\n /** Unique receipt ID for the enqueued message. */\n messageReceiptId: string\n}\n\n/**\n * Request object passed to {@link ISdk.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 /** Namespace to route this invocation to. Omit to use the engine's default namespace. */\n namespace?: string\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 * Namespace to route this invocation to. Omitted when routing within the default namespace.\n */\n namespace?: string\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 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 | RegistrationRejectedMessage\n","import { ChannelReader, ChannelWriter } from './channels'\nimport {\n DEFAULT_BRIDGE_RECONNECTION_CONFIG,\n DEFAULT_INVOCATION_TIMEOUT_MS,\n EngineFunctions,\n type IIIConnectionState,\n type IIIReconnectionConfig,\n} from './iii-constants'\nimport {\n type IIIMessage,\n type InvocationResultMessage,\n type InvokeFunctionMessage,\n MessageType,\n type RegisterFunctionMessage,\n type RegisterTriggerMessage,\n type RegisterTriggerTypeMessage,\n type StreamChannelRef,\n type TriggerRegistrationResultMessage,\n type TriggerRequest,\n} from './iii-types'\nimport type { IStream } from './stream'\nimport type { TriggerHandler } from './triggers'\nimport type {\n FunctionRef,\n Invocation,\n ISdk,\n RegisterFunctionOptions,\n RemoteFunctionData,\n RemoteFunctionHandler,\n RemoteTriggerTypeData,\n Trigger,\n TriggerTypeRef,\n} from './types'\nimport { isChannelRef, randomUUID } from './utils'\nimport { RegistrationRejectedError } from './errors'\n\n/** @internal */\nexport type TelemetryOptions = {\n language?: string\n project_name?: string\n framework?: string\n amplitude_api_key?: string\n}\n\n/**\n * Configuration options passed to {@link registerWorker}.\n *\n * @example\n * ```typescript\n * const worker = registerWorker('ws://localhost:49135', {\n * invocationTimeoutMs: 10000,\n * reconnectionConfig: { maxRetries: 5 },\n * })\n * ```\n */\nexport type InitOptions = {\n /**\n * Name this worker announces to the engine. Defaults to a unique\n * `browser:<random>` per client: a browser has no pid to disambiguate by, and\n * the engine allows only one live worker per name in a namespace, so two tabs\n * sharing a fixed name would evict each other.\n */\n workerName?: string\n /**\n * Namespace this worker registers under. When omitted the engine applies its\n * `default` namespace. Scopes worker and function registrations so\n * identically-named entries can coexist across namespaces. The browser has no\n * `process.env`, so there is no environment-variable fallback -- pass the\n * option explicitly.\n */\n namespace?: string\n /** Default timeout for `worker.trigger()` invocations in milliseconds. Defaults to `30000`. */\n invocationTimeoutMs?: number\n /**\n * WebSocket reconnection behavior.\n *\n * @see {@link IIIReconnectionConfig} for available fields and defaults.\n */\n reconnectionConfig?: Partial<IIIReconnectionConfig>\n /** Browser WebSocket connections authenticate via query parameters or cookies; the `headers` option is ignored. */\n headers?: Record<string, string>\n}\n\n/** Short random suffix; `crypto.randomUUID` is unavailable on insecure origins. */\nfunction randomId(): string {\n const c = globalThis.crypto\n if (c?.randomUUID) {\n return c.randomUUID().slice(0, 8)\n }\n if (c?.getRandomValues) {\n return Array.from(c.getRandomValues(new Uint8Array(4)))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n }\n return Math.random().toString(16).slice(2, 10)\n}\n\nclass Sdk implements ISdk {\n private ws?: WebSocket\n private functions = new Map<string, RemoteFunctionData>()\n private invocations = new Map<string, Invocation & { timeout?: ReturnType<typeof setTimeout> }>()\n private triggers = new Map<string, RegisterTriggerMessage>()\n private triggerTypes = new Map<string, RemoteTriggerTypeData>()\n private messagesToSend: Record<string, unknown>[] = []\n private reconnectTimeout?: ReturnType<typeof setTimeout>\n private invocationTimeoutMs: number\n private reconnectionConfig: IIIReconnectionConfig\n private reconnectAttempt = 0\n private connectionState: IIIConnectionState = 'disconnected'\n private connectionListeners = new Set<(state: IIIConnectionState) => void>()\n private isShuttingDown = false\n private readonly workerName: string\n private readonly namespace?: string\n private workerId?: string\n private reattachToken?: string\n private fatalError?: RegistrationRejectedError\n\n constructor(\n private readonly address: string,\n private readonly options?: InitOptions,\n ) {\n this.workerName = options?.workerName ?? `browser:${randomId()}`\n // No env fallback: the browser has no `process.env`.\n this.namespace = options?.namespace\n this.invocationTimeoutMs = options?.invocationTimeoutMs ?? DEFAULT_INVOCATION_TIMEOUT_MS\n this.reconnectionConfig = {\n ...DEFAULT_BRIDGE_RECONNECTION_CONFIG,\n ...options?.reconnectionConfig,\n }\n\n this.connect()\n }\n\n /**\n * Registers a custom trigger type with the engine. A trigger type defines\n * how external events (HTTP, cron, queue, etc.) map to function invocations.\n *\n * @param triggerType - Trigger type registration input.\n * @param triggerType.id - Unique trigger type identifier.\n * @param triggerType.description - Human-readable description.\n * @param handler - Handler with `registerTrigger` / `unregisterTrigger` callbacks.\n *\n * @example\n * ```typescript\n * worker.registerTriggerType(\n * { id: 'my-trigger', description: 'Custom trigger' },\n * {\n * async registerTrigger({ id, function_id, config }) { },\n * async unregisterTrigger({ id, function_id, config }) { },\n * },\n * )\n * ```\n */\n registerTriggerType = <TConfig>(\n triggerType: Omit<RegisterTriggerTypeMessage, 'message_type'>,\n handler: TriggerHandler<TConfig>,\n ): TriggerTypeRef<TConfig> => {\n this.sendMessage(MessageType.RegisterTriggerType, triggerType, true)\n this.triggerTypes.set(triggerType.id, {\n message: { ...triggerType, message_type: MessageType.RegisterTriggerType },\n handler,\n })\n\n return {\n id: triggerType.id,\n // Pairs a function with its trigger, so it defaults the trigger's namespace\n // to this worker's — otherwise the function lands in the worker's namespace\n // and the trigger in `default`, never resolving it. The low-level\n // `registerTrigger` keeps the engine default (`default`).\n registerTrigger: (functionId: string, config: TConfig) => {\n return this.registerTrigger({\n type: triggerType.id,\n function_id: functionId,\n config,\n namespace: this.namespace,\n })\n },\n registerFunction: (functionId, handler, config) => {\n const ref = this.registerFunction(functionId, handler)\n this.registerTrigger({\n type: triggerType.id,\n function_id: functionId,\n config,\n namespace: this.namespace,\n })\n return ref\n },\n unregister: () => {\n this.unregisterTriggerType(triggerType)\n },\n }\n }\n\n /**\n * Unregisters a previously registered trigger type.\n *\n * @param triggerType - The trigger type to unregister (must match the `id` used during registration).\n */\n unregisterTriggerType = (triggerType: Omit<RegisterTriggerTypeMessage, 'message_type'>): void => {\n this.sendMessage(MessageType.UnregisterTriggerType, triggerType, true)\n this.triggerTypes.delete(triggerType.id)\n }\n\n /**\n * Binds a trigger configuration to a registered function. When the trigger\n * fires, the engine invokes the target function.\n *\n * @param trigger - Trigger registration input.\n * @param trigger.type - Trigger type (e.g. `http`, `durable:subscriber`, `cron`).\n * @param trigger.function_id - ID of the function to invoke.\n * @param trigger.config - Trigger-specific configuration.\n * @returns A {@link Trigger} handle with an `unregister()` method.\n *\n * @example\n * ```typescript\n * const trigger = worker.registerTrigger({\n * type: 'http',\n * function_id: 'greet',\n * config: { api_path: '/greet', http_method: 'GET' },\n * })\n *\n * // Later...\n * trigger.unregister()\n * ```\n */\n registerTrigger = (trigger: Omit<RegisterTriggerMessage, 'message_type' | 'id'>): Trigger => {\n const id = randomUUID()\n const fullTrigger: RegisterTriggerMessage = {\n ...trigger,\n id,\n message_type: MessageType.RegisterTrigger,\n }\n this.sendMessage(MessageType.RegisterTrigger, fullTrigger, true)\n this.triggers.set(id, fullTrigger)\n\n return {\n unregister: () => {\n this.sendMessage(MessageType.UnregisterTrigger, {\n id,\n message_type: MessageType.UnregisterTrigger,\n type: fullTrigger.type,\n })\n this.triggers.delete(id)\n },\n }\n }\n\n /**\n * Registers a function with the engine. The `functionId` is the unique identifier\n * used by triggers and invocations.\n *\n * The handler runs locally in the browser session; HTTP invocation configs\n * are a Node.js SDK feature and are not accepted here.\n *\n * @param functionId - Unique function identifier.\n * @param handlerOrInvocation - Async handler executed when the function is invoked.\n * @param options - Optional function registration options (description, request/response formats, metadata).\n * @returns A {@link FunctionRef} with `id` and `unregister()`.\n *\n * @example\n * ```typescript\n * const fn = worker.registerFunction(\n * 'greet',\n * async (input: { name: string }) => {\n * return { message: `Hello, ${input.name}!` }\n * },\n * { description: 'Greets a user' },\n * )\n * ```\n */\n registerFunction = (\n functionId: string,\n handlerOrInvocation: RemoteFunctionHandler,\n options?: RegisterFunctionOptions,\n ): FunctionRef => {\n if (!functionId || functionId.trim() === '') {\n throw new Error('id is required')\n }\n if (this.functions.has(functionId)) {\n throw new Error(`function id already registered: ${functionId}`)\n }\n\n const fullMessage: RegisterFunctionMessage = {\n ...options,\n id: functionId,\n message_type: MessageType.RegisterFunction,\n }\n\n this.sendMessage(MessageType.RegisterFunction, fullMessage, true)\n\n const handler = handlerOrInvocation as RemoteFunctionHandler\n this.functions.set(functionId, {\n message: fullMessage,\n handler: async (input, _traceparent?: string, _baggage?: string) => {\n return await handler(input)\n },\n })\n\n return {\n id: functionId,\n unregister: () => {\n this.sendMessage(MessageType.UnregisterFunction, { id: functionId }, true)\n this.functions.delete(functionId)\n },\n }\n }\n\n /**\n * @internal Implementation backing the `createChannel` helper in the\n * `iii-browser-sdk/helpers` submodule. Not part of the public `ISdk` surface.\n *\n * Creates a streaming channel pair for worker-to-worker data transfer.\n * Returns a {@link Channel} with a local writer/reader and serializable refs\n * that can be passed as fields in invocation data to other functions.\n */\n __helpers_create_channel = async (bufferSize?: number): Promise<import('./types').Channel> => {\n const result = await this.trigger<{ buffer_size?: number }, { writer: StreamChannelRef; reader: StreamChannelRef }>(\n { function_id: 'engine::channels::create', payload: { buffer_size: bufferSize } },\n )\n\n return {\n writer: new ChannelWriter(this.address, result.writer),\n reader: new ChannelReader(this.address, result.reader),\n writerRef: result.writer,\n readerRef: result.reader,\n }\n }\n\n /**\n * Invokes a remote function. The routing behavior and return type depend\n * on the `action` field of the request.\n *\n * | `action` | Behavior | Return type |\n * |-------------------------------|----------------------------------------------------|----------------------- |\n * | _(none)_ | Synchronous: waits for the function to return | `Promise<TOutput>` |\n * | `TriggerAction.Enqueue(...)` | Async via named queue; engine acknowledges enqueue | `Promise<EnqueueResult>` |\n * | `TriggerAction.Void()` | Fire-and-forget, no response | `Promise<undefined>` |\n *\n * @param request - The trigger request.\n * @param request.function_id - ID of the function to invoke.\n * @param request.payload - Payload to pass to the function.\n * @param request.action - Routing action. Omit for synchronous request/response.\n * @param request.timeoutMs - Override the default invocation timeout.\n * @returns The result of the function invocation.\n *\n * @example\n * ```typescript\n * import { TriggerAction } from 'iii-browser-sdk'\n *\n * // Synchronous\n * const result = await worker.trigger({ function_id: 'get-order', payload: { id: '123' } })\n *\n * // Enqueue\n * const { messageReceiptId } = await worker.trigger({\n * function_id: 'payments::charge',\n * payload: { orderId: '123', amount: 49.99 },\n * action: TriggerAction.Enqueue({ queue: 'payment' }),\n * })\n *\n * // Fire-and-forget\n * worker.trigger({\n * function_id: 'notifications::send',\n * payload: { userId: '123' },\n * action: TriggerAction.Void(),\n * })\n * ```\n */\n // biome-ignore lint/suspicious/noExplicitAny: TOutput defaults to any so untyped calls type-check (the engine cannot express the return type statically)\n trigger = async <TInput = unknown, TOutput = any>(\n request: TriggerRequest<TInput>,\n ): Promise<TOutput> => {\n const { function_id, payload, action, timeoutMs, namespace } = request\n const effectiveTimeout = timeoutMs ?? this.invocationTimeoutMs\n\n if (action?.type === 'void') {\n this.sendMessage(MessageType.InvokeFunction, {\n function_id,\n data: payload,\n action,\n // Omit when absent so the engine routes within its default namespace.\n ...(namespace !== undefined ? { namespace } : {}),\n })\n return undefined as TOutput\n }\n\n const invocation_id = randomUUID()\n\n return new Promise<TOutput>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const invocation = this.invocations.get(invocation_id)\n if (invocation) {\n this.invocations.delete(invocation_id)\n reject(new Error(`Invocation timeout after ${effectiveTimeout}ms: ${function_id}`))\n }\n }, effectiveTimeout)\n\n this.invocations.set(invocation_id, {\n resolve: (result: TOutput) => {\n clearTimeout(timeout)\n resolve(result)\n },\n reject: (error: unknown) => {\n clearTimeout(timeout)\n reject(error)\n },\n timeout,\n })\n\n this.sendMessage(MessageType.InvokeFunction, {\n invocation_id,\n function_id,\n data: payload,\n action,\n // Omit when absent so the engine routes within its default namespace.\n ...(namespace !== undefined ? { namespace } : {}),\n })\n })\n }\n\n /**\n * @internal Implementation backing the `createStream` helper in the\n * `iii-browser-sdk/helpers` submodule. Not part of the public `ISdk` surface.\n *\n * Registers a custom stream implementation, overriding the engine default\n * for the given stream name.\n */\n __helpers_create_stream = <TData>(streamName: string, stream: IStream<TData>): void => {\n this.registerFunction(`stream::get(${streamName})`, stream.get.bind(stream))\n this.registerFunction(`stream::set(${streamName})`, stream.set.bind(stream))\n this.registerFunction(`stream::delete(${streamName})`, stream.delete.bind(stream))\n this.registerFunction(`stream::list(${streamName})`, stream.list.bind(stream))\n this.registerFunction(`stream::list_groups(${streamName})`, stream.listGroups.bind(stream))\n }\n\n /**\n * The terminal rejection that closed this connection for good, if any. Set\n * only for a non-retryable registration rejection (e.g. a worker-name\n * collision). Mirrors the Node SDK.\n */\n getFatalError = (): RegistrationRejectedError | undefined => this.fatalError\n\n /**\n * Gracefully shutdown the SDK, cleaning up all resources.\n */\n shutdown = async (): Promise<void> => {\n this.isShuttingDown = true\n\n this.clearReconnectTimeout()\n\n for (const [_id, invocation] of this.invocations) {\n if (invocation.timeout) {\n clearTimeout(invocation.timeout)\n }\n invocation.reject(new Error('iii is shutting down'))\n }\n this.invocations.clear()\n\n if (this.ws) {\n this.ws.onopen = null\n this.ws.onclose = null\n this.ws.onerror = null\n this.ws.onmessage = null\n this.ws.close()\n this.ws = undefined\n }\n\n this.setConnectionState('disconnected')\n }\n\n /**\n * Subscribe to connection-state transitions. The handler is fired immediately\n * with the current state, then on every transition. Multiple listeners are\n * supported. Returns an unsubscribe function.\n */\n addConnectionStateListener = (handler: (state: IIIConnectionState) => void): (() => void) => {\n this.connectionListeners.add(handler)\n try {\n handler(this.connectionState)\n } catch (e) {\n console.error('[iii] connection listener threw on initial fire', e)\n }\n return () => {\n this.connectionListeners.delete(handler)\n }\n }\n\n // private methods\n\n private setConnectionState(state: IIIConnectionState): void {\n if (this.connectionState !== state) {\n this.connectionState = state\n for (const handler of this.connectionListeners) {\n try {\n handler(state)\n } catch (e) {\n console.error('[iii] connection listener threw', e)\n }\n }\n }\n }\n\n private connect(): void {\n if (this.isShuttingDown) {\n return\n }\n\n this.setConnectionState('connecting')\n this.ws = new WebSocket(this.address)\n this.ws.onopen = this.onSocketOpen.bind(this)\n this.ws.onclose = this.onSocketClose.bind(this)\n this.ws.onerror = this.onSocketError.bind(this)\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = undefined\n }\n }\n\n private scheduleReconnect(): void {\n if (this.isShuttingDown) {\n return\n }\n\n const { maxRetries, initialDelayMs, backoffMultiplier, maxDelayMs, jitterFactor } = this.reconnectionConfig\n\n if (maxRetries !== -1 && this.reconnectAttempt >= maxRetries) {\n this.setConnectionState('failed')\n console.error(`[iii] Max reconnection retries (${maxRetries}) reached, giving up`)\n return\n }\n\n if (this.reconnectTimeout) {\n return\n }\n\n const exponentialDelay = initialDelayMs * backoffMultiplier ** this.reconnectAttempt\n const cappedDelay = Math.min(exponentialDelay, maxDelayMs)\n const jitter = cappedDelay * jitterFactor * (2 * Math.random() - 1)\n const delay = Math.floor(cappedDelay + jitter)\n\n this.setConnectionState('reconnecting')\n console.debug(`[iii] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt + 1})...`)\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = undefined\n this.reconnectAttempt++\n this.connect()\n }, delay)\n }\n\n private onSocketError(): void {\n console.error('[iii] WebSocket error')\n }\n\n private onSocketClose(): void {\n if (this.ws) {\n this.ws.onopen = null\n this.ws.onclose = null\n this.ws.onerror = null\n this.ws.onmessage = null\n }\n this.ws = undefined\n\n // A fatal registration rejection (or shutdown) sets `isShuttingDown` and a\n // terminal state before closing the socket. Do not overwrite that state with\n // `disconnected`, and do not schedule a reconnect the engine would only\n // reject again. `scheduleReconnect` already no-ops while shutting down.\n if (this.isShuttingDown) {\n return\n }\n\n this.setConnectionState('disconnected')\n this.scheduleReconnect()\n }\n\n private onSocketOpen(): void {\n this.clearReconnectTimeout()\n this.reconnectAttempt = 0\n this.setConnectionState('connected')\n\n if (this.ws) {\n this.ws.onmessage = this.onMessage.bind(this)\n }\n\n // Reconnect: present the previous engine-assigned identity BEFORE the\n // metadata announce and registration replay so the engine retires the old\n // connection and the replay lands on a clean slate instead of racing its\n // cleanup. This must precede registerWorkerMetadata(): otherwise the old\n // connection still holds this (namespace, worker_name) and the announce\n // would trip WORKER_NAMESPACE_CONFLICT against ourselves. The token proves\n // we ARE that worker (ids alone are publicly listable).\n if (this.workerId) {\n this.sendMessageRaw(\n JSON.stringify({\n type: MessageType.Reattach,\n previous_worker_id: this.workerId,\n reattach_token: this.reattachToken,\n }),\n )\n }\n\n // Announce before registering anything. The engine buffers a connection's\n // registrations until it knows the connection's namespace, which it takes\n // from this call — or, failing that, only after a grace period. Registering\n // first would stall every function behind that grace.\n this.registerWorkerMetadata()\n\n\n this.triggerTypes.forEach(({ message }) => {\n this.sendMessage(MessageType.RegisterTriggerType, message, true)\n })\n this.functions.forEach(({ message }) => {\n this.sendMessage(MessageType.RegisterFunction, message, true)\n })\n this.triggers.forEach((trigger) => {\n this.sendMessage(MessageType.RegisterTrigger, trigger, true)\n })\n\n const pending = this.messagesToSend\n this.messagesToSend = []\n for (const message of pending) {\n if (\n message.type === MessageType.InvokeFunction &&\n typeof message.invocation_id === 'string' &&\n !this.invocations.has(message.invocation_id)\n ) {\n continue\n }\n this.sendMessageRaw(JSON.stringify(message))\n }\n }\n\n private isOpen(): boolean {\n return this.ws?.readyState === WebSocket.OPEN\n }\n\n private sendMessageRaw(data: string): void {\n if (this.ws && this.isOpen()) {\n try {\n this.ws.send(data)\n } catch (error) {\n console.error('[iii] Exception while sending message', error)\n }\n }\n }\n\n private toWireFormat(messageType: MessageType, message: Omit<IIIMessage, 'message_type'>): Record<string, unknown> {\n const { message_type: _, ...rest } = message as Record<string, unknown>\n if (messageType === MessageType.RegisterTrigger && 'type' in message) {\n const { type: triggerType, ...triggerRest } = message as RegisterTriggerMessage\n return { type: messageType, ...triggerRest, trigger_type: triggerType }\n }\n if (messageType === MessageType.UnregisterTrigger && 'type' in message) {\n const { type: triggerType, ...triggerRest } = message as RegisterTriggerMessage\n return { type: messageType, ...triggerRest, trigger_type: triggerType }\n }\n if (messageType === MessageType.TriggerRegistrationResult && 'type' in message) {\n const { type: triggerType, ...resultRest } = message as TriggerRegistrationResultMessage\n return { type: messageType, ...resultRest, trigger_type: triggerType }\n }\n return { type: messageType, ...rest } as Record<string, unknown>\n }\n\n /**\n * Tells the engine who this connection is. Sent on every open, before any\n * registration, so the engine can resolve this connection's namespace and\n * drain its buffered registrations immediately.\n */\n private registerWorkerMetadata(): void {\n this.sendMessage(MessageType.InvokeFunction, {\n function_id: EngineFunctions.REGISTER_WORKER,\n data: {\n runtime: 'browser',\n name: this.workerName,\n os: globalThis.navigator?.userAgent ?? 'browser',\n // Omit when absent so the engine falls back to its `default` namespace.\n ...(this.namespace !== undefined ? { namespace: this.namespace } : {}),\n },\n action: { type: 'void' },\n } as unknown as Omit<IIIMessage, 'message_type'>)\n }\n\n private sendMessage(messageType: MessageType, message: Omit<IIIMessage, 'message_type'>, skipIfClosed = false): void {\n const wireMessage = this.toWireFormat(messageType, message)\n if (this.isOpen()) {\n this.sendMessageRaw(JSON.stringify(wireMessage))\n } else if (!skipIfClosed) {\n this.messagesToSend.push(wireMessage)\n }\n }\n\n private onInvocationResult(invocation_id: string, result: unknown, error: unknown): void {\n const invocation = this.invocations.get(invocation_id)\n\n if (invocation) {\n if (invocation.timeout) {\n clearTimeout(invocation.timeout)\n }\n error ? invocation.reject(error) : invocation.resolve(result)\n }\n\n this.invocations.delete(invocation_id)\n }\n\n private resolveChannelValue(value: unknown): unknown {\n if (isChannelRef(value)) {\n return value.direction === 'read'\n ? new ChannelReader(this.address, value)\n : new ChannelWriter(this.address, value)\n }\n if (Array.isArray(value)) {\n return value.map((item) => this.resolveChannelValue(item))\n }\n if (value !== null && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = this.resolveChannelValue(v)\n }\n return out\n }\n return value\n }\n\n private async onInvokeFunction<TInput>(\n invocation_id: string | undefined,\n function_id: string,\n input: TInput,\n traceparent?: string,\n baggage?: string,\n ): Promise<unknown> {\n const fn = this.functions.get(function_id)\n\n const resolvedInput = this.resolveChannelValue(input) as TInput\n\n if (fn?.handler) {\n if (!invocation_id) {\n try {\n await fn.handler(resolvedInput, traceparent, baggage)\n } catch (error) {\n console.error(`[iii] Error invoking function ${function_id}`, error)\n }\n return\n }\n\n try {\n const result = await fn.handler(resolvedInput, traceparent, baggage)\n this.sendMessage(MessageType.InvocationResult, {\n invocation_id,\n function_id,\n result,\n traceparent,\n baggage,\n })\n } catch (error) {\n const isError = error instanceof Error\n this.sendMessage(MessageType.InvocationResult, {\n invocation_id,\n function_id,\n error: {\n code: 'invocation_failed',\n message: isError ? error.message : String(error),\n stacktrace: isError ? error.stack : undefined,\n },\n traceparent,\n baggage,\n })\n }\n } else {\n const errorCode = fn ? 'function_not_invokable' : 'function_not_found'\n const errorMessage = fn ? 'Function is HTTP-invoked and cannot be invoked locally' : 'Function not found'\n if (invocation_id) {\n this.sendMessage(MessageType.InvocationResult, {\n invocation_id,\n function_id,\n error: { code: errorCode, message: errorMessage },\n traceparent,\n baggage,\n })\n }\n }\n }\n\n private async onRegisterTrigger(message: {\n trigger_type: string\n id: string\n function_id: string\n config: unknown\n namespace?: string\n }) {\n const { trigger_type, id, function_id, config, namespace } = message\n const triggerTypeData = this.triggerTypes.get(trigger_type)\n\n if (triggerTypeData) {\n try {\n await triggerTypeData.handler.registerTrigger({ id, function_id, config, namespace })\n this.sendMessage(MessageType.TriggerRegistrationResult, {\n id,\n message_type: MessageType.TriggerRegistrationResult,\n type: trigger_type,\n function_id,\n })\n } catch (error) {\n this.sendMessage(MessageType.TriggerRegistrationResult, {\n id,\n message_type: MessageType.TriggerRegistrationResult,\n type: trigger_type,\n function_id,\n error: { code: 'trigger_registration_failed', message: (error as Error).message },\n })\n }\n } else {\n this.sendMessage(MessageType.TriggerRegistrationResult, {\n id,\n message_type: MessageType.TriggerRegistrationResult,\n type: trigger_type,\n function_id,\n error: { code: 'trigger_type_not_found', message: 'Trigger type not found' },\n })\n }\n }\n\n private async onUnregisterTrigger(message: {\n trigger_type?: string\n id: string\n function_id?: string\n config?: unknown\n }) {\n const trigger_type = message.trigger_type\n if (!trigger_type) return\n\n const triggerTypeData = this.triggerTypes.get(trigger_type)\n if (!triggerTypeData) return\n\n const { id, function_id = '', config } = message\n try {\n await triggerTypeData.handler.unregisterTrigger({ id, function_id, config })\n } catch (error) {\n console.error(`[iii] Error unregistering trigger ${id}`, error)\n }\n }\n\n private onMessage(event: MessageEvent): void {\n let msgType: MessageType\n let message: Record<string, unknown>\n\n try {\n const parsed = JSON.parse(typeof event.data === 'string' ? event.data : '') as Record<string, unknown>\n msgType = parsed.type as MessageType\n const { type: _, ...rest } = parsed\n message = rest\n } catch (error) {\n console.error('[iii] Failed to parse incoming message', error)\n return\n }\n\n if (msgType === MessageType.InvocationResult) {\n const { invocation_id, result, error } = message as InvocationResultMessage\n this.onInvocationResult(invocation_id, result, error)\n } else if (msgType === MessageType.InvokeFunction) {\n const { invocation_id, function_id, data, traceparent, baggage } = message as InvokeFunctionMessage\n this.onInvokeFunction(invocation_id, function_id, data, traceparent, baggage)\n } else if (msgType === MessageType.RegisterTrigger) {\n this.onRegisterTrigger(message as { trigger_type: string; id: string; function_id: string; config: unknown })\n } else if (msgType === MessageType.UnregisterTrigger) {\n this.onUnregisterTrigger(\n message as { trigger_type?: string; id: string; function_id?: string; config?: unknown },\n )\n } else if (msgType === MessageType.RegistrationRejected) {\n this.onRegistrationRejected(\n message as { code: string; namespace: string; worker_name?: string; function_id?: string; owner_worker_id: string },\n )\n } else if (msgType === MessageType.WorkerRegistered) {\n const { worker_id, reattach_token } = message as { worker_id: string; reattach_token?: string }\n this.workerId = worker_id\n this.reattachToken = reattach_token\n }\n }\n\n /**\n * The engine rejected a registration. A `FUNCTION_NAMESPACE_CONFLICT` costs\n * one function and leaves the connection open, so log and keep serving. A\n * `WORKER_NAMESPACE_CONFLICT` means another live worker owns this name in the\n * namespace: it is terminal — stop and do not reconnect (otherwise the engine\n * would only reject the same name again, which with `maxRetries: -1` loops\n * forever).\n */\n private onRegistrationRejected(init: {\n code: string\n namespace: string\n worker_name?: string\n function_id?: string\n owner_worker_id: string\n }): void {\n if (init.code === 'FUNCTION_NAMESPACE_CONFLICT') {\n console.warn(\n `[iii] Function registration rejected: function \"${init.function_id ?? '<unknown>'}\" in namespace \"${init.namespace}\" is already exported by worker ${init.owner_worker_id}. Staying connected and serving the rest.`,\n )\n return\n }\n\n console.error(\n `[iii] Registration rejected (${init.code}): worker \"${init.worker_name}\" in namespace \"${init.namespace}\" is already owned by ${init.owner_worker_id}. Not reconnecting.`,\n )\n // Terminal: suppress reconnect so neither onSocketClose nor scheduleReconnect\n // revives a connection the engine would only reject again.\n this.isShuttingDown = true\n this.clearReconnectTimeout()\n\n // Reject every in-flight invocation now rather than leaving them to time out.\n const error = new RegistrationRejectedError(init)\n this.fatalError = error\n for (const [, invocation] of this.invocations) {\n if (invocation.timeout) {\n clearTimeout(invocation.timeout)\n }\n invocation.reject(error)\n }\n this.invocations.clear()\n\n // Drop the socket. onSocketClose sees `isShuttingDown` and leaves the\n // terminal `failed` state in place instead of overwriting it.\n this.setConnectionState('failed')\n this.ws?.close()\n }\n}\n\n/**\n * Factory object that constructs routing actions for {@link ISdk.trigger}.\n *\n * @example\n * ```typescript\n * import { TriggerAction } from 'iii-browser-sdk'\n *\n * // Enqueue to a named queue\n * worker.trigger({\n * function_id: 'process',\n * payload: { data: 'hello' },\n * action: TriggerAction.Enqueue({ queue: 'jobs' }),\n * })\n *\n * // Fire-and-forget\n * worker.trigger({\n * function_id: 'notify',\n * payload: {},\n * action: TriggerAction.Void(),\n * })\n * ```\n */\nexport const TriggerAction = {\n /**\n * Routes the invocation through a named queue. The engine enqueues the job,\n * acknowledges the caller with `{ messageReceiptId }`, and processes it\n * asynchronously.\n *\n * @param opts - Queue routing options.\n * @param opts.queue - Name of the target queue.\n */\n Enqueue: (opts: { queue: string }) => ({ type: 'enqueue' as const, ...opts }),\n /**\n * Fire-and-forget routing. The engine forwards the invocation without\n * waiting for a response or queuing the job.\n */\n Void: () => ({ type: 'void' as const }),\n} as const\n\n/**\n * Register the worker with a iii instance, returns a connected worker client.\n * The WebSocket connection is established automatically.\n *\n * @param address - WebSocket URL of the III engine (e.g. `ws://localhost:49135`).\n * @param options - Optional {@link InitOptions} for worker name, timeouts, and reconnection.\n * @returns A connected {@link ISdk} instance.\n *\n * @example\n * ```typescript\n * import { registerWorker } from 'iii-browser-sdk'\n *\n * const worker = registerWorker('ws://localhost:49135')\n * ```\n */\nexport const registerWorker = (address: string, options?: InitOptions): ISdk => new Sdk(address, options)\n"],"mappings":"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"}
@@ -9,6 +9,7 @@ declare enum MessageType {
9
9
  UnregisterTrigger = "unregistertrigger",
10
10
  UnregisterTriggerType = "unregistertriggertype",
11
11
  TriggerRegistrationResult = "triggerregistrationresult",
12
+ RegistrationRejected = "registrationrejected",
12
13
  WorkerRegistered = "workerregistered",
13
14
  Reattach = "reattach"
14
15
  }
@@ -23,6 +24,11 @@ type RegisterTriggerMessage = {
23
24
  type: string; /** ID of the function this trigger invokes when it fires. */
24
25
  function_id: string; /** Trigger-type-specific configuration, matching the shape the trigger type expects. */
25
26
  config: unknown;
27
+ /**
28
+ * Namespace the trigger's target function resolves in. Omit for the engine's
29
+ * default namespace, independent of this connection's namespace.
30
+ */
31
+ namespace?: string;
26
32
  };
27
33
  type RegisterFunctionFormat = {
28
34
  /**
@@ -118,6 +124,11 @@ type MiddlewareFunctionInput = {
118
124
  payload: Record<string, unknown>; /** Routing action, if any. */
119
125
  action?: TriggerAction; /** Auth context returned by the auth function for this session. */
120
126
  context: Record<string, unknown>;
127
+ /**
128
+ * Target namespace the invoke addressed; forward the call here to stay in the
129
+ * caller's namespace. Absent → the engine's default namespace.
130
+ */
131
+ namespace?: string;
121
132
  };
122
133
  /**
123
134
  * Input passed to the `on_trigger_type_registration_function_id` hook
@@ -149,7 +160,13 @@ type OnTriggerRegistrationInput = {
149
160
  /** ID of the trigger being registered. */trigger_id: string; /** Trigger type identifier. */
150
161
  trigger_type: string; /** ID of the function this trigger is bound to. */
151
162
  function_id: string; /** Trigger-specific configuration. */
152
- config: unknown; /** Auth context from `AuthResult.context` for this session. */
163
+ config: unknown;
164
+ /**
165
+ * Namespace the trigger's target resolves in (explicit, or `default` when
166
+ * absent). The same id can exist in several namespaces, so the hook needs this
167
+ * to authorize per target namespace.
168
+ */
169
+ namespace?: string; /** Auth context from `AuthResult.context` for this session. */
153
170
  context: Record<string, unknown>;
154
171
  };
155
172
  /**
@@ -172,7 +189,12 @@ type OnTriggerRegistrationResult = {
172
189
  type OnFunctionRegistrationInput = {
173
190
  /** ID of the function being registered. */function_id: string; /** Human-readable description of the function. */
174
191
  description?: string; /** Arbitrary metadata attached to the function. */
175
- metadata?: Record<string, unknown>; /** Auth context from `AuthResult.context` for this session. */
192
+ metadata?: Record<string, unknown>;
193
+ /**
194
+ * Namespace the function registers in. The same id can exist in several
195
+ * namespaces, so the hook needs this to authorize per namespace.
196
+ */
197
+ namespace?: string; /** Auth context from `AuthResult.context` for this session. */
176
198
  context: Record<string, unknown>;
177
199
  };
178
200
  /**
@@ -200,7 +222,8 @@ type TriggerRequest<TInput = unknown> = {
200
222
  /** ID of the function to invoke. */function_id: string; /** Input data passed to the function. */
201
223
  payload: TInput; /** Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue()`, `TriggerAction.Void()`). */
202
224
  action?: TriggerAction; /** Override the default invocation timeout, in milliseconds. */
203
- timeoutMs?: number;
225
+ timeoutMs?: number; /** Namespace to route this invocation to. Omit to use the engine's default namespace. */
226
+ namespace?: string;
204
227
  };
205
228
  /**
206
229
  * Serializable reference to one end of a streaming channel. Can be included
@@ -299,6 +322,28 @@ declare class ChannelReader {
299
322
  close(): void;
300
323
  }
301
324
  //#endregion
325
+ //#region src/errors.d.ts
326
+ type RegistrationRejectedInit = {
327
+ code: string;
328
+ namespace: string;
329
+ worker_name?: string;
330
+ function_id?: string;
331
+ owner_worker_id: string;
332
+ };
333
+ /**
334
+ * A terminal registration rejection from the engine. Thrown into every pending
335
+ * invocation and exposed via `getFatalError()` when a worker-name collision
336
+ * (or other non-retryable rejection) closes the connection for good.
337
+ */
338
+ declare class RegistrationRejectedError extends Error {
339
+ readonly code: string;
340
+ readonly namespace: string;
341
+ readonly worker_name?: string;
342
+ readonly function_id?: string;
343
+ readonly owner_worker_id: string;
344
+ constructor(init: RegistrationRejectedInit);
345
+ }
346
+ //#endregion
302
347
  //#region src/iii-constants.d.ts
303
348
  /**
304
349
  * Constants for the III module.
@@ -354,6 +399,12 @@ type TriggerConfig<TConfig> = {
354
399
  /** Trigger instance ID. */id: string; /** Function to invoke when the trigger fires. */
355
400
  function_id: string; /** Trigger-specific configuration. */
356
401
  config: TConfig;
402
+ /**
403
+ * Namespace the trigger's target `function_id` resolves in. A provider that
404
+ * stores this config and later fires the target must pass this namespace, or
405
+ * it fires in `default`. Absent means the engine's default namespace.
406
+ */
407
+ namespace?: string;
357
408
  };
358
409
  /**
359
410
  * Handler interface for custom trigger types. Passed to
@@ -537,6 +588,12 @@ interface ISdk {
537
588
  * ```
538
589
  */
539
590
  addConnectionStateListener(handler: (state: IIIConnectionState) => void): () => void;
591
+ /**
592
+ * The fatal registration rejection that terminated this connection, if any
593
+ * (e.g. a `WORKER_NAMESPACE_CONFLICT`); `undefined` while healthy. Mirrors the
594
+ * Node/Python/Rust SDKs.
595
+ */
596
+ getFatalError(): RegistrationRejectedError | undefined;
540
597
  }
541
598
  /**
542
599
  * Handle returned by {@link ISdk.registerTrigger}. Use `unregister()` to
@@ -648,5 +705,5 @@ type ApiResponse<TStatus extends number = number, TBody = string | Record<string
648
705
  body?: TBody;
649
706
  };
650
707
  //#endregion
651
- export { OnTriggerRegistrationInput as A, AuthInput as C, MiddlewareFunctionInput as D, MessageType as E, RegisterFunctionMessage as F, RegisterTriggerMessage as I, RegisterTriggerTypeMessage as L, OnTriggerTypeRegistrationInput as M, OnTriggerTypeRegistrationResult as N, OnFunctionRegistrationInput as O, RegisterFunctionFormat as P, StreamChannelRef as R, ChannelWriter as S, EnqueueResult as T, IIIConnectionState as _, ISdk as a, ChannelItem as b, RegisterTriggerInput as c, Trigger as d, TriggerTypeRef as f, EngineTriggers as g, EngineFunctions as h, FunctionRef as i, OnTriggerRegistrationResult as j, OnFunctionRegistrationResult as k, RegisterTriggerTypeInput as l, TriggerHandler as m, ApiResponse as n, RegisterFunctionInput as o, TriggerConfig as p, Channel as r, RegisterFunctionOptions as s, ApiRequest as t, RemoteFunctionHandler as u, IIIReconnectionConfig as v, AuthResult as w, ChannelReader as x, ChannelDirection as y, TriggerRequest as z };
652
- //# sourceMappingURL=types-Dj_5C0O1.d.cts.map
708
+ export { OnFunctionRegistrationInput as A, StreamChannelRef as B, ChannelReader as C, EnqueueResult as D, AuthResult as E, OnTriggerTypeRegistrationResult as F, RegisterFunctionFormat as I, RegisterFunctionMessage as L, OnTriggerRegistrationInput as M, OnTriggerRegistrationResult as N, MessageType as O, OnTriggerTypeRegistrationInput as P, RegisterTriggerMessage as R, ChannelItem as S, AuthInput as T, TriggerRequest as V, IIIConnectionState as _, ISdk as a, RegistrationRejectedInit as b, RegisterTriggerInput as c, Trigger as d, TriggerTypeRef as f, EngineTriggers as g, EngineFunctions as h, FunctionRef as i, OnFunctionRegistrationResult as j, MiddlewareFunctionInput as k, RegisterTriggerTypeInput as l, TriggerHandler as m, ApiResponse as n, RegisterFunctionInput as o, TriggerConfig as p, Channel as r, RegisterFunctionOptions as s, ApiRequest as t, RemoteFunctionHandler as u, IIIReconnectionConfig as v, ChannelWriter as w, ChannelDirection as x, RegistrationRejectedError as y, RegisterTriggerTypeMessage as z };
709
+ //# sourceMappingURL=types-C5bBdUVf.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-C5bBdUVf.d.mts","names":[],"sources":["../src/iii-types.ts","../src/channels.ts","../src/errors.ts","../src/iii-constants.ts","../src/triggers.ts","../src/types.ts"],"mappings":"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"}