iii-sdk 0.22.1 → 0.23.0-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.
Files changed (53) hide show
  1. package/dist/channel.d.cts +1 -1
  2. package/dist/channel.d.mts +1 -1
  3. package/dist/engine.d.cts +1 -2
  4. package/dist/engine.d.mts +1 -2
  5. package/dist/errors-B2LphIs-.d.cts +64 -0
  6. package/dist/errors-B2LphIs-.d.cts.map +1 -0
  7. package/dist/errors-BnYJZ4Ye.d.mts +64 -0
  8. package/dist/errors-BnYJZ4Ye.d.mts.map +1 -0
  9. package/dist/errors.cjs +20 -0
  10. package/dist/errors.cjs.map +1 -1
  11. package/dist/errors.d.cts +2 -40
  12. package/dist/errors.d.mts +2 -40
  13. package/dist/errors.mjs +20 -1
  14. package/dist/errors.mjs.map +1 -1
  15. package/dist/helpers.d.cts +1 -1
  16. package/dist/helpers.d.mts +1 -1
  17. package/dist/{iii-types-BvaIabiX.cjs → iii-types-BHasLgj1.cjs} +2 -1
  18. package/dist/iii-types-BHasLgj1.cjs.map +1 -0
  19. package/dist/{iii-types-wPYrg7hX.mjs → iii-types-Btz-0RpP.mjs} +2 -1
  20. package/dist/iii-types-Btz-0RpP.mjs.map +1 -0
  21. package/dist/index.cjs +145 -17
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +31 -11
  24. package/dist/index.d.cts.map +1 -1
  25. package/dist/index.d.mts +31 -11
  26. package/dist/index.d.mts.map +1 -1
  27. package/dist/index.mjs +145 -19
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/internal.d.cts +1 -1
  30. package/dist/internal.d.mts +1 -1
  31. package/dist/protocol.cjs +1 -1
  32. package/dist/protocol.d.cts +1 -1
  33. package/dist/protocol.d.mts +1 -1
  34. package/dist/protocol.mjs +1 -1
  35. package/dist/runtime.d.cts +1 -2
  36. package/dist/runtime.d.mts +1 -2
  37. package/dist/trigger.d.cts +1 -1
  38. package/dist/trigger.d.mts +1 -1
  39. package/dist/{types-BD2fp4Py.d.mts → types-Be3nGFI2.d.mts} +108 -2
  40. package/dist/types-Be3nGFI2.d.mts.map +1 -0
  41. package/dist/{types-n-760A15.d.cts → types-D-KH-5pT.d.cts} +108 -2
  42. package/dist/types-D-KH-5pT.d.cts.map +1 -0
  43. package/package.json +2 -2
  44. package/dist/errors.d.cts.map +0 -1
  45. package/dist/errors.d.mts.map +0 -1
  46. package/dist/iii-constants-Baptl8nm.d.mts +0 -47
  47. package/dist/iii-constants-Baptl8nm.d.mts.map +0 -1
  48. package/dist/iii-constants-BqXp8xSN.d.cts +0 -47
  49. package/dist/iii-constants-BqXp8xSN.d.cts.map +0 -1
  50. package/dist/iii-types-BvaIabiX.cjs.map +0 -1
  51. package/dist/iii-types-wPYrg7hX.mjs.map +0 -1
  52. package/dist/types-BD2fp4Py.d.mts.map +0 -1
  53. package/dist/types-n-760A15.d.cts.map +0 -1
package/dist/index.d.cts CHANGED
@@ -1,10 +1,15 @@
1
- import { C as MiddlewareFunctionInput, d as StreamResponse, r as IIIClient, u as StreamRequest, x as JsonValue } from "./types-n-760A15.cjs";
2
- import { i as IIIReconnectionConfig } from "./iii-constants-BqXp8xSN.cjs";
3
- import { InvocationError, InvocationErrorInit } from "./errors.cjs";
1
+ import { D as MiddlewareFunctionInput, T as JsonValue, d as StreamResponse, r as IIIClient, u as StreamRequest, v as IIIConnectionState, y as IIIReconnectionConfig } from "./types-D-KH-5pT.cjs";
2
+ import { n as InvocationErrorInit, r as RegistrationRejectedError, t as InvocationError } from "./errors-B2LphIs-.cjs";
4
3
  import { OtelConfig } from "@iii-dev/helpers/observability";
5
4
  import { EnqueueResult } from "@iii-dev/helpers/queue";
6
5
 
7
6
  //#region src/iii.d.ts
7
+ /**
8
+ * Engine address used when neither an explicit address nor `III_URL` is set.
9
+ * The IPv4 loopback is spelled out on purpose: `localhost` can resolve to `::1`
10
+ * on a host whose engine only listens on IPv4.
11
+ */
12
+ declare const DEFAULT_ENGINE_URL = "ws://127.0.0.1:49134";
8
13
  /** Worker metadata reported to the engine (language, framework, project). */
9
14
  type TelemetryOptions = {
10
15
  /** Programming language of the worker. */language?: string; /** Name of the project this worker belongs to. */
@@ -25,7 +30,19 @@ type TelemetryOptions = {
25
30
  * ```
26
31
  */
27
32
  type InitOptions = {
28
- /** Display name for this worker. Defaults to `hostname:pid`. */workerName?: string;
33
+ /** Display name for this worker. A non-empty `III_WORKER_NAME` overrides it. Defaults to `hostname:pid`. */workerName?: string;
34
+ /**
35
+ * Namespace this worker belongs to. Resolution order:
36
+ * `options.namespace` -> `process.env.III_NAMESPACE` -> undefined. When
37
+ * undefined the engine applies its `default` namespace.
38
+ *
39
+ * It scopes more than the registration. The worker and its functions
40
+ * register here, so identically-named entries coexist across namespaces, and
41
+ * everything the worker does afterwards follows it: a `trigger` resolves its
42
+ * target here, and a `registerTrigger` binds here, unless the call names
43
+ * another namespace. One declaration places the whole worker.
44
+ */
45
+ namespace?: string;
29
46
  /**
30
47
  * One-line, human/LLM-readable summary of what this worker does.
31
48
  * Surfaces in `engine::workers::list` / `engine::workers::info`.
@@ -76,7 +93,7 @@ declare const TriggerAction: {
76
93
  * acknowledges the caller with `{ messageReceiptId }`, and processes it
77
94
  * asynchronously.
78
95
  *
79
- * Requires a queue worker in the project. Run `iii worker add queue`.
96
+ * Requires the `queue` worker in `worker-compose.yaml`.
80
97
  * Without it the trigger rejects with `enqueue_error` (no queue provider).
81
98
  *
82
99
  * @param opts - Queue routing options.
@@ -100,7 +117,8 @@ declare const TriggerAction: {
100
117
  * Register the worker with a iii instance, returns a connected worker client.
101
118
  * The WebSocket connection is established automatically.
102
119
  *
103
- * @param address - WebSocket URL of the III engine (e.g. `ws://localhost:49134`).
120
+ * @param address - WebSocket URL of the III engine. Omit to resolve it from
121
+ * `process.env.III_URL`, falling back to {@link DEFAULT_ENGINE_URL}.
104
122
  * @param options - Optional {@link InitOptions} for worker name, timeouts, reconnection, and OTel.
105
123
  * @returns A connected {@link IIIClient} instance.
106
124
  *
@@ -108,12 +126,14 @@ declare const TriggerAction: {
108
126
  * ```typescript
109
127
  * import { registerWorker } from 'iii-sdk'
110
128
  *
111
- * const worker = registerWorker(process.env.III_URL ?? 'ws://localhost:49134', {
112
- * workerName: 'my-worker',
113
- * })
129
+ * // Address from III_URL, set by whatever supervisor spawned this worker.
130
+ * const worker = registerWorker()
131
+ *
132
+ * // Or explicitly, which always wins over the environment.
133
+ * const other = registerWorker('ws://localhost:49134', { workerName: 'my-worker' })
114
134
  * ```
115
135
  */
116
- declare const registerWorker: (address: string, options?: InitOptions) => IIIClient;
136
+ declare const registerWorker: (address?: string, options?: InitOptions) => IIIClient;
117
137
  //#endregion
118
- export { type EnqueueResult, type IIIClient, type InitOptions, InvocationError, type InvocationErrorInit, type JsonValue, type MiddlewareFunctionInput, type StreamRequest, type StreamResponse, type TelemetryOptions, TriggerAction, registerWorker };
138
+ export { DEFAULT_ENGINE_URL, type EnqueueResult, type IIIClient, type IIIConnectionState, type InitOptions, InvocationError, type InvocationErrorInit, type JsonValue, type MiddlewareFunctionInput, RegistrationRejectedError, type StreamRequest, type StreamResponse, type TelemetryOptions, TriggerAction, registerWorker };
119
139
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/iii.ts"],"mappings":";;;;;;;;KAoFY,gBAAA;4CAEV,QAAA,WAFU;EAIV,YAAA;EAEA,SAAA,WAJA;EAMA,iBAAA;AAAA;;;;AAeF;;;;;;;;;KAAY,WAAA;EA2BkB,gEAzB5B,UAAA;EAKA;;;;EAAA,iBAAA,WAU6B;EAR7B,sBAAA,YAcO;EAZP,mBAAA;EAcA;;;;;EARA,kBAAA,GAAqB,OAAA,CAAQ,qBAAA;EAggClB;;;;;EA1/BX,IAAA,GAAO,IAAA,CAAK,UAAA;EAEZ,OAAA,GAAU,MAAA;EAEV,SAAA,GAAY,gBAAA;AAAA;;;AA2hCd;;;;;;;;;;;;;;;;;;;;cArCa,aAAA;;;;;;;;;;;;;IAYO,KAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyBP,cAAA,GAAkB,OAAA,UAAiB,OAAA,GAAU,WAAA,KAAc,SAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/iii.ts"],"mappings":";;;;;;;;;AAsGA;;cAAa,kBAAA;;KAmFD,gBAAA;EAAA,0CAEV,QAAA;EAEA,YAAA,WAFA;EAIA,SAAA;EAEA,iBAAA;AAAA;;AAeF;;;;;;;;;;;KAAY,WAAA;EAcV,4GAZA,UAAA;EAmBA;;;;;;;;;;;EAPA,SAAA;EAyB4B;;AAgpC9B;;EApqCE,iBAAA,WAsrCQ;EAprCR,sBAAA,YA8qCkB;EA5qClB,mBAAA;;;;;;EAMA,kBAAA,GAAqB,OAAA,CAAQ,qBAAA;EAksClB;;;;;EA5rCX,IAAA,GAAO,IAAA,CAAK,UAAA,kBA4rCmC;EA1rC/C,OAAA,GAAU,MAAA,kBA2rC+B;EAzrCzC,SAAA,GAAY,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;cAgpCD,aAAA;;;;;;;;;;;;;IAYO,KAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4BP,cAAA,GAAkB,OAAA,WAAkB,OAAA,GAAU,WAAA,KAAc,SAAA"}
package/dist/index.d.mts CHANGED
@@ -1,10 +1,15 @@
1
- import { C as MiddlewareFunctionInput, d as StreamResponse, r as IIIClient, u as StreamRequest, x as JsonValue } from "./types-BD2fp4Py.mjs";
2
- import { i as IIIReconnectionConfig } from "./iii-constants-Baptl8nm.mjs";
3
- import { InvocationError, InvocationErrorInit } from "./errors.mjs";
1
+ import { D as MiddlewareFunctionInput, T as JsonValue, d as StreamResponse, r as IIIClient, u as StreamRequest, v as IIIConnectionState, y as IIIReconnectionConfig } from "./types-Be3nGFI2.mjs";
2
+ import { n as InvocationErrorInit, r as RegistrationRejectedError, t as InvocationError } from "./errors-BnYJZ4Ye.mjs";
4
3
  import { OtelConfig } from "@iii-dev/helpers/observability";
5
4
  import { EnqueueResult } from "@iii-dev/helpers/queue";
6
5
 
7
6
  //#region src/iii.d.ts
7
+ /**
8
+ * Engine address used when neither an explicit address nor `III_URL` is set.
9
+ * The IPv4 loopback is spelled out on purpose: `localhost` can resolve to `::1`
10
+ * on a host whose engine only listens on IPv4.
11
+ */
12
+ declare const DEFAULT_ENGINE_URL = "ws://127.0.0.1:49134";
8
13
  /** Worker metadata reported to the engine (language, framework, project). */
9
14
  type TelemetryOptions = {
10
15
  /** Programming language of the worker. */language?: string; /** Name of the project this worker belongs to. */
@@ -25,7 +30,19 @@ type TelemetryOptions = {
25
30
  * ```
26
31
  */
27
32
  type InitOptions = {
28
- /** Display name for this worker. Defaults to `hostname:pid`. */workerName?: string;
33
+ /** Display name for this worker. A non-empty `III_WORKER_NAME` overrides it. Defaults to `hostname:pid`. */workerName?: string;
34
+ /**
35
+ * Namespace this worker belongs to. Resolution order:
36
+ * `options.namespace` -> `process.env.III_NAMESPACE` -> undefined. When
37
+ * undefined the engine applies its `default` namespace.
38
+ *
39
+ * It scopes more than the registration. The worker and its functions
40
+ * register here, so identically-named entries coexist across namespaces, and
41
+ * everything the worker does afterwards follows it: a `trigger` resolves its
42
+ * target here, and a `registerTrigger` binds here, unless the call names
43
+ * another namespace. One declaration places the whole worker.
44
+ */
45
+ namespace?: string;
29
46
  /**
30
47
  * One-line, human/LLM-readable summary of what this worker does.
31
48
  * Surfaces in `engine::workers::list` / `engine::workers::info`.
@@ -76,7 +93,7 @@ declare const TriggerAction: {
76
93
  * acknowledges the caller with `{ messageReceiptId }`, and processes it
77
94
  * asynchronously.
78
95
  *
79
- * Requires a queue worker in the project. Run `iii worker add queue`.
96
+ * Requires the `queue` worker in `worker-compose.yaml`.
80
97
  * Without it the trigger rejects with `enqueue_error` (no queue provider).
81
98
  *
82
99
  * @param opts - Queue routing options.
@@ -100,7 +117,8 @@ declare const TriggerAction: {
100
117
  * Register the worker with a iii instance, returns a connected worker client.
101
118
  * The WebSocket connection is established automatically.
102
119
  *
103
- * @param address - WebSocket URL of the III engine (e.g. `ws://localhost:49134`).
120
+ * @param address - WebSocket URL of the III engine. Omit to resolve it from
121
+ * `process.env.III_URL`, falling back to {@link DEFAULT_ENGINE_URL}.
104
122
  * @param options - Optional {@link InitOptions} for worker name, timeouts, reconnection, and OTel.
105
123
  * @returns A connected {@link IIIClient} instance.
106
124
  *
@@ -108,12 +126,14 @@ declare const TriggerAction: {
108
126
  * ```typescript
109
127
  * import { registerWorker } from 'iii-sdk'
110
128
  *
111
- * const worker = registerWorker(process.env.III_URL ?? 'ws://localhost:49134', {
112
- * workerName: 'my-worker',
113
- * })
129
+ * // Address from III_URL, set by whatever supervisor spawned this worker.
130
+ * const worker = registerWorker()
131
+ *
132
+ * // Or explicitly, which always wins over the environment.
133
+ * const other = registerWorker('ws://localhost:49134', { workerName: 'my-worker' })
114
134
  * ```
115
135
  */
116
- declare const registerWorker: (address: string, options?: InitOptions) => IIIClient;
136
+ declare const registerWorker: (address?: string, options?: InitOptions) => IIIClient;
117
137
  //#endregion
118
- export { type EnqueueResult, type IIIClient, type InitOptions, InvocationError, type InvocationErrorInit, type JsonValue, type MiddlewareFunctionInput, type StreamRequest, type StreamResponse, type TelemetryOptions, TriggerAction, registerWorker };
138
+ export { DEFAULT_ENGINE_URL, type EnqueueResult, type IIIClient, type IIIConnectionState, type InitOptions, InvocationError, type InvocationErrorInit, type JsonValue, type MiddlewareFunctionInput, RegistrationRejectedError, type StreamRequest, type StreamResponse, type TelemetryOptions, TriggerAction, registerWorker };
119
139
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/iii.ts"],"mappings":";;;;;;;;KAoFY,gBAAA;4CAEV,QAAA,WAFU;EAIV,YAAA;EAEA,SAAA,WAJA;EAMA,iBAAA;AAAA;;;;AAeF;;;;;;;;;KAAY,WAAA;EA2BkB,gEAzB5B,UAAA;EAKA;;;;EAAA,iBAAA,WAU6B;EAR7B,sBAAA,YAcO;EAZP,mBAAA;EAcA;;;;;EARA,kBAAA,GAAqB,OAAA,CAAQ,qBAAA;EAggClB;;;;;EA1/BX,IAAA,GAAO,IAAA,CAAK,UAAA;EAEZ,OAAA,GAAU,MAAA;EAEV,SAAA,GAAY,gBAAA;AAAA;;;AA2hCd;;;;;;;;;;;;;;;;;;;;cArCa,aAAA;;;;;;;;;;;;;IAYO,KAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyBP,cAAA,GAAkB,OAAA,UAAiB,OAAA,GAAU,WAAA,KAAc,SAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/iii.ts"],"mappings":";;;;;;;;;AAsGA;;cAAa,kBAAA;;KAmFD,gBAAA;EAAA,0CAEV,QAAA;EAEA,YAAA,WAFA;EAIA,SAAA;EAEA,iBAAA;AAAA;;AAeF;;;;;;;;;;;KAAY,WAAA;EAcV,4GAZA,UAAA;EAmBA;;;;;;;;;;;EAPA,SAAA;EAyB4B;;AAgpC9B;;EApqCE,iBAAA,WAsrCQ;EAprCR,sBAAA,YA8qCkB;EA5qClB,mBAAA;;;;;;EAMA,kBAAA,GAAqB,OAAA,CAAQ,qBAAA;EAksClB;;;;;EA5rCX,IAAA,GAAO,IAAA,CAAK,UAAA,kBA4rCmC;EA1rC/C,OAAA,GAAU,MAAA,kBA2rC+B;EAzrCzC,SAAA,GAAY,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;cAgpCD,aAAA;;;;;;;;;;;;;IAYO,KAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4BP,cAAA,GAAkB,OAAA,WAAkB,OAAA,GAAU,WAAA,KAAc,SAAA"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { InvocationError, isErrorBody } from "./errors.mjs";
1
+ import { InvocationError, RegistrationRejectedError, isErrorBody } from "./errors.mjs";
2
2
  import { a as WS_HANDSHAKE_TIMEOUT_MS, n as DEFAULT_INVOCATION_TIMEOUT_MS, o as WS_IDLE_TIMEOUT_MS, r as EngineFunctions, s as WS_PING_INTERVAL_MS, t as DEFAULT_BRIDGE_RECONNECTION_CONFIG } from "./iii-constants-TIcoyiOl.mjs";
3
3
  import { i as ChannelWriter, r as ChannelReader } from "./channels-C4f7nfQr.mjs";
4
- import { t as MessageType } from "./iii-types-wPYrg7hX.mjs";
4
+ import { t as MessageType } from "./iii-types-Btz-0RpP.mjs";
5
5
  import { r as isChannelRef, t as detectProjectName } from "./utils-8G4hHqvZ.mjs";
6
6
  import { createRequire } from "node:module";
7
7
  import { SpanKind, context, trace } from "@opentelemetry/api";
@@ -12,13 +12,62 @@ import { getMeter, getTracer } from "@iii-dev/helpers/observability/internal";
12
12
 
13
13
  //#region src/iii.ts
14
14
  const { version: SDK_VERSION } = createRequire(import.meta.url)("../package.json");
15
+ /**
16
+ * `registrationrejected` code (engine `protocol.rs`): another live worker
17
+ * already holds this `(namespace, worker_name)`. The engine closes the
18
+ * connection -- fatal.
19
+ */
20
+ const WORKER_NAMESPACE_CONFLICT = "WORKER_NAMESPACE_CONFLICT";
21
+ /**
22
+ * `registrationrejected` code (engine `protocol.rs`): another live worker in
23
+ * this namespace already exports this one function id. The connection stays
24
+ * open -- non-fatal.
25
+ */
26
+ const FUNCTION_NAMESPACE_CONFLICT = "FUNCTION_NAMESPACE_CONFLICT";
15
27
  function getOsInfo() {
16
28
  return `${os.platform()} ${os.release()} (${os.arch()})`;
17
29
  }
18
- function getDefaultWorkerName() {
30
+ function resolveWorkerName(explicitName) {
19
31
  const managedName = process.env.III_WORKER_NAME;
20
32
  if (managedName) return managedName;
21
- return `${os.hostname()}:${process.pid}`;
33
+ return explicitName ?? `${os.hostname()}:${process.pid}`;
34
+ }
35
+ /**
36
+ * Engine address used when neither an explicit address nor `III_URL` is set.
37
+ * The IPv4 loopback is spelled out on purpose: `localhost` can resolve to `::1`
38
+ * on a host whose engine only listens on IPv4.
39
+ */
40
+ const DEFAULT_ENGINE_URL = "ws://127.0.0.1:49134";
41
+ function resolveAddress(address) {
42
+ if (address) return address;
43
+ const fromEnv = process.env.III_URL;
44
+ if (fromEnv) return fromEnv;
45
+ return DEFAULT_ENGINE_URL;
46
+ }
47
+ /**
48
+ * The namespace one call or one binding resolves in.
49
+ *
50
+ * `undefined` inherits the worker's. A blank one is refused: named and left
51
+ * empty asks for the opposite of what absent asks for, and the two are only
52
+ * ever confused by accident -- `??` forwards the empty string, Python's `or`
53
+ * coerced it and Go dropped it, so one mistake produced three behaviours.
54
+ */
55
+ function callNamespace(explicit, worker, source) {
56
+ if (explicit !== void 0 && explicit.trim() === "") throw new Error(`namespace is empty: ${source} was set to ${JSON.stringify(explicit)}. Give it a name, or leave it unset to stay in this worker's namespace.`);
57
+ return explicit ?? worker;
58
+ }
59
+ /** Resolve one function invocation without leaking engine builtins into a worker namespace. */
60
+ function invocationNamespace(explicit, worker, functionId) {
61
+ const namespace = callNamespace(explicit, worker, "TriggerRequest.namespace");
62
+ return explicit === void 0 && functionId.startsWith("engine::") ? "default" : namespace;
63
+ }
64
+ function resolveNamespace(optionNamespace) {
65
+ if (optionNamespace !== void 0) {
66
+ if (optionNamespace.trim() === "") throw new Error(`namespace is empty: options.namespace was set to ${JSON.stringify(optionNamespace)}. Give it a name, or leave it unset to register in \`default\`.`);
67
+ return optionNamespace;
68
+ }
69
+ const managedNamespace = process.env.III_NAMESPACE;
70
+ if (managedNamespace) return managedNamespace;
22
71
  }
23
72
  var Sdk = class {
24
73
  constructor(address, options) {
@@ -48,7 +97,8 @@ var Sdk = class {
48
97
  type: triggerType.id,
49
98
  function_id: functionId,
50
99
  config,
51
- metadata
100
+ metadata,
101
+ namespace: this.namespace
52
102
  });
53
103
  },
54
104
  registerFunction: (functionId, handler, config, metadata) => {
@@ -57,7 +107,8 @@ var Sdk = class {
57
107
  type: triggerType.id,
58
108
  function_id: functionId,
59
109
  config,
60
- metadata
110
+ metadata,
111
+ namespace: this.namespace
61
112
  });
62
113
  return ref;
63
114
  },
@@ -75,7 +126,11 @@ var Sdk = class {
75
126
  const fullTrigger = {
76
127
  ...trigger,
77
128
  id,
78
- message_type: MessageType.RegisterTrigger
129
+ message_type: MessageType.RegisterTrigger,
130
+ ...(() => {
131
+ const namespace = callNamespace(trigger.namespace, this.namespace, "RegisterTriggerInput.namespace");
132
+ return namespace !== void 0 ? { namespace } : {};
133
+ })()
79
134
  };
80
135
  this.sendMessage(MessageType.RegisterTrigger, fullTrigger, true);
81
136
  this.triggers.set(id, fullTrigger);
@@ -184,6 +239,7 @@ var Sdk = class {
184
239
  };
185
240
  this.trigger = async (request) => {
186
241
  const { function_id, payload, action, timeoutMs, metadata } = request;
242
+ const namespace = invocationNamespace(request.namespace, this.namespace, function_id);
187
243
  const effectiveTimeout = timeoutMs ?? this.invocationTimeoutMs;
188
244
  if (action?.type === "void") {
189
245
  const traceparent = injectTraceparent();
@@ -194,7 +250,8 @@ var Sdk = class {
194
250
  traceparent,
195
251
  baggage,
196
252
  action,
197
- metadata
253
+ metadata,
254
+ ...namespace !== void 0 ? { namespace } : {}
198
255
  });
199
256
  return;
200
257
  }
@@ -231,7 +288,8 @@ var Sdk = class {
231
288
  traceparent,
232
289
  baggage,
233
290
  action,
234
- metadata
291
+ metadata,
292
+ ...namespace !== void 0 ? { namespace } : {}
235
293
  });
236
294
  });
237
295
  };
@@ -242,6 +300,9 @@ var Sdk = class {
242
300
  this.registerFunction(`stream::list(${streamName})`, stream.list.bind(stream));
243
301
  this.registerFunction(`stream::list_groups(${streamName})`, stream.listGroups.bind(stream));
244
302
  };
303
+ this.getConnectionState = () => this.connectionState;
304
+ this.getAddress = () => this.address;
305
+ this.getFatalError = () => this.fatalError;
245
306
  this.shutdown = async () => {
246
307
  this.isShuttingDown = true;
247
308
  this.stopMetricsReporting();
@@ -263,7 +324,8 @@ var Sdk = class {
263
324
  }
264
325
  this.setConnectionState("disconnected");
265
326
  };
266
- this.workerName = options?.workerName ?? getDefaultWorkerName();
327
+ this.workerName = resolveWorkerName(options?.workerName);
328
+ this.namespace = resolveNamespace(options?.namespace);
267
329
  this.workerDescription = options?.workerDescription;
268
330
  this.metricsReportingEnabled = options?.enableMetricsReporting ?? true;
269
331
  this.invocationTimeoutMs = options?.invocationTimeoutMs ?? 3e4;
@@ -290,6 +352,7 @@ var Sdk = class {
290
352
  os: getOsInfo(),
291
353
  pid: process.pid,
292
354
  isolation: process.env.III_ISOLATION || null,
355
+ ...this.namespace !== void 0 ? { namespace: this.namespace } : {},
293
356
  telemetry: {
294
357
  language,
295
358
  project_name: telemetryOpts?.project_name ?? detectProjectName(),
@@ -405,6 +468,7 @@ var Sdk = class {
405
468
  previous_worker_id: this.workerId,
406
469
  reattach_token: this.reattachToken
407
470
  }));
471
+ this.registerWorkerMetadata();
408
472
  this.triggerTypes.forEach(({ message }) => {
409
473
  this.sendMessage(MessageType.RegisterTriggerType, message, true);
410
474
  });
@@ -420,7 +484,6 @@ var Sdk = class {
420
484
  if (message.type === MessageType.InvokeFunction && typeof message.invocation_id === "string" && !this.invocations.has(message.invocation_id)) continue;
421
485
  this.sendMessageRaw(JSON.stringify(message));
422
486
  }
423
- this.registerWorkerMetadata();
424
487
  }
425
488
  isOpen() {
426
489
  return this.ws?.readyState === WebSocket.OPEN;
@@ -479,6 +542,56 @@ var Sdk = class {
479
542
  });
480
543
  else console.error(`[iii] ${message}`, error ?? "");
481
544
  }
545
+ logWarn(message) {
546
+ const otelLogger = getLogger();
547
+ if (otelLogger) otelLogger.emit({
548
+ severityNumber: SeverityNumber.WARN,
549
+ body: `[iii] ${message}`
550
+ });
551
+ else console.warn(`[iii] ${message}`);
552
+ }
553
+ /**
554
+ * Handle a `registrationrejected` from the engine. The `code` decides the
555
+ * severity:
556
+ *
557
+ * - {@link WORKER_NAMESPACE_CONFLICT}: another live worker already holds this
558
+ * `(namespace, worker_name)`. The engine closes the connection, so this is
559
+ * fatal -- stop the worker, do not reconnect, and surface a
560
+ * {@link RegistrationRejectedError} to every pending invocation.
561
+ * - {@link FUNCTION_NAMESPACE_CONFLICT}: another live worker in this namespace
562
+ * already exports this one function id. Only that registration is refused;
563
+ * the engine keeps the connection open and the worker keeps serving its
564
+ * other functions. Non-fatal -- log a warning and continue.
565
+ * - Any other code: treated as fatal (safe default).
566
+ */
567
+ onRegistrationRejected(init) {
568
+ if (init.code === FUNCTION_NAMESPACE_CONFLICT) {
569
+ this.logWarn(`Function registration rejected: function "${init.function_id ?? "<unknown>"}" in namespace "${init.namespace}" is already exported by worker ${init.owner_worker_id}. The worker stays connected and keeps serving its other functions.`);
570
+ return;
571
+ }
572
+ const error = new RegistrationRejectedError(init);
573
+ this.fatalError = error;
574
+ if (init.code === WORKER_NAMESPACE_CONFLICT) this.logError("Registration rejected by engine", error);
575
+ else this.logError(`Registration rejected by engine with unknown code "${init.code}"; treating as fatal`, error);
576
+ this.isShuttingDown = true;
577
+ this.clearReconnectTimeout();
578
+ this.stopHeartbeat();
579
+ for (const [, invocation] of this.invocations) {
580
+ if (invocation.timeout) clearTimeout(invocation.timeout);
581
+ invocation.reject(error);
582
+ }
583
+ this.invocations.clear();
584
+ if (this.ws) {
585
+ this.ws.removeAllListeners();
586
+ this.ws.on("error", () => {});
587
+ try {
588
+ this.ws.terminate();
589
+ } catch {}
590
+ this.ws = void 0;
591
+ }
592
+ this.stopMetricsReporting();
593
+ this.setConnectionState("failed");
594
+ }
482
595
  onInvocationResult(invocation_id, result, error) {
483
596
  const invocation = this.invocations.get(invocation_id);
484
597
  if (invocation) {
@@ -572,14 +685,15 @@ var Sdk = class {
572
685
  }
573
686
  }
574
687
  async onRegisterTrigger(message) {
575
- const { trigger_type, id, function_id, config, metadata } = message;
688
+ const { trigger_type, id, function_id, config, metadata, namespace } = message;
576
689
  const triggerTypeData = this.triggerTypes.get(trigger_type);
577
690
  if (triggerTypeData) try {
578
691
  await triggerTypeData.handler.registerTrigger({
579
692
  id,
580
693
  function_id,
581
694
  config,
582
- metadata
695
+ metadata,
696
+ namespace
583
697
  });
584
698
  this.sendMessage(MessageType.TriggerRegistrationResult, {
585
699
  id,
@@ -659,6 +773,15 @@ var Sdk = class {
659
773
  this.reattachToken = reattach_token;
660
774
  console.debug("[iii] Worker registered with ID:", worker_id);
661
775
  this.startMetricsReporting();
776
+ } else if (msgType === MessageType.RegistrationRejected) {
777
+ const { code, namespace, worker_name, function_id, owner_worker_id } = message;
778
+ this.onRegistrationRejected({
779
+ code,
780
+ namespace,
781
+ worker_name,
782
+ function_id,
783
+ owner_worker_id
784
+ });
662
785
  }
663
786
  }
664
787
  };
@@ -695,7 +818,8 @@ const TriggerAction = {
695
818
  * Register the worker with a iii instance, returns a connected worker client.
696
819
  * The WebSocket connection is established automatically.
697
820
  *
698
- * @param address - WebSocket URL of the III engine (e.g. `ws://localhost:49134`).
821
+ * @param address - WebSocket URL of the III engine. Omit to resolve it from
822
+ * `process.env.III_URL`, falling back to {@link DEFAULT_ENGINE_URL}.
699
823
  * @param options - Optional {@link InitOptions} for worker name, timeouts, reconnection, and OTel.
700
824
  * @returns A connected {@link IIIClient} instance.
701
825
  *
@@ -703,13 +827,15 @@ const TriggerAction = {
703
827
  * ```typescript
704
828
  * import { registerWorker } from 'iii-sdk'
705
829
  *
706
- * const worker = registerWorker(process.env.III_URL ?? 'ws://localhost:49134', {
707
- * workerName: 'my-worker',
708
- * })
830
+ * // Address from III_URL, set by whatever supervisor spawned this worker.
831
+ * const worker = registerWorker()
832
+ *
833
+ * // Or explicitly, which always wins over the environment.
834
+ * const other = registerWorker('ws://localhost:49134', { workerName: 'my-worker' })
709
835
  * ```
710
836
  */
711
- const registerWorker = (address, options) => new Sdk(address, options);
837
+ const registerWorker = (address, options) => new Sdk(resolveAddress(address), options);
712
838
 
713
839
  //#endregion
714
- export { InvocationError, TriggerAction, registerWorker };
840
+ export { DEFAULT_ENGINE_URL, InvocationError, RegistrationRejectedError, TriggerAction, registerWorker };
715
841
  //# sourceMappingURL=index.mjs.map