iii-sdk 0.4.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,100 +1,87 @@
1
- # III SDK for Node.js
1
+ # iii-sdk
2
2
 
3
- ## Installation
3
+ Node.js / TypeScript SDK for the [iii engine](https://github.com/iii-hq/iii).
4
+
5
+ [![npm](https://img.shields.io/npm/v/iii-sdk)](https://www.npmjs.com/package/iii-sdk)
6
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](../../../LICENSE)
7
+
8
+ ## Install
4
9
 
5
10
  ```bash
6
11
  npm install iii-sdk
7
12
  ```
8
13
 
9
- ## Usage
14
+ ## Hello World
10
15
 
11
16
  ```javascript
12
- import { III } from 'iii-sdk'
17
+ import { init } from 'iii-sdk'
13
18
 
14
- /**
15
- * Make sure the III Core Instance is up and Running on the given URL.
16
- */
17
- const iii = new III(process.env.III_BRIDGE_URL ?? 'ws://localhost:49134')
19
+ const iii = init('ws://localhost:49134')
18
20
 
19
- iii.registerFunction({ id: 'myFunction' }, (req) => {
20
- return { status_code: 200, body: { message: 'Hello, world!' } }
21
+ iii.registerFunction({ id: 'greet' }, async (input) => {
22
+ return { message: `Hello, ${input.name}!` }
21
23
  })
22
24
 
23
25
  iii.registerTrigger({
24
26
  type: 'http',
25
- function_id: 'myFunction',
26
- config: { api_path: 'myApiPath', http_method: 'POST' },
27
+ function_id: 'greet',
28
+ config: { api_path: '/greet', http_method: 'POST' },
27
29
  })
30
+
31
+ const result = await iii.trigger('greet', { name: 'world' })
28
32
  ```
29
33
 
30
- ### Registering Functions
34
+ ## API
31
35
 
32
- III Allows you to register functions that can be invoked by other services.
36
+ | Operation | Signature | Description |
37
+ | ------------------------ | ---------------------------------------------------- | ------------------------------------------------------------ |
38
+ | Initialize | `init(url, options?)` | Create and connect to the engine. Returns an `ISdk` instance |
39
+ | Register function | `iii.registerFunction({ id }, handler)` | Register a function that can be invoked by name |
40
+ | Register trigger | `iii.registerTrigger({ type, function_id, config })` | Bind a trigger (HTTP, cron, queue, etc.) to a function |
41
+ | Invoke (await) | `await iii.trigger(id, data, timeoutMs?)` | Invoke a function and wait for the result |
42
+ | Invoke (fire-and-forget) | `iii.triggerVoid(id, data)` | Invoke a function without waiting (fire-and-forget) |
43
+
44
+ ### Registering Functions
33
45
 
34
46
  ```javascript
35
- iii.registerFunction({ id: 'myFunction' }, (req) => {
36
- // ... do something
37
- return { status_code: 200, body: { message: 'Hello, world!' } }
47
+ iii.registerFunction({ id: 'orders.create' }, async (input) => {
48
+ return { status_code: 201, body: { id: '123', item: input.body.item } }
38
49
  })
39
50
  ```
40
51
 
41
52
  ### Registering Triggers
42
53
 
43
- III Allows you to register triggers that can be invoked by other services.
44
-
45
54
  ```javascript
46
55
  iii.registerTrigger({
47
56
  type: 'http',
48
- function_id: 'myFunction',
49
- config: { api_path: 'myApiPath', http_method: 'POST' },
57
+ function_id: 'orders.create',
58
+ config: { api_path: '/orders', http_method: 'POST' },
50
59
  })
51
60
  ```
52
61
 
53
- ### Registering Trigger Types
54
-
55
- Triggers are mostly created by III Core Modules, but you can also create your own triggers
62
+ ### Invoking Functions
56
63
 
57
64
  ```javascript
58
- iii.registerTrigger_type(
59
- {
60
- /**
61
- * This is the id of the trigger type, it's unique.
62
- * Then, you can register a trigger by calling the registerTrigger method.
63
- */
64
- id: 'myTrigger_type',
65
- description: 'My trigger type',
66
- },
67
- {
68
- /**
69
- * Trigger config has: id, function_id, and config.
70
- * Your logic should know what to do with the config.
71
- */
72
- registerTrigger: async (config) => {
73
- // ... do something
74
- },
75
- unregisterTrigger: async (config) => {
76
- // ... do something
77
- },
78
- },
79
- )
80
- ```
65
+ const result = await iii.trigger('orders.create', { item: 'widget' })
81
66
 
82
- ### Invoking Functions
67
+ iii.triggerVoid('analytics.track', { event: 'page_view' })
68
+ ```
83
69
 
84
- III Allows you to invoke functions, they can be functions from the Core Modules or
85
- functions registered by workers.
70
+ ## Node Modules
86
71
 
87
- ```javascript
88
- const result = await iii.call('myFunction', { param1: 'value1' })
89
- console.log(result)
90
- ```
72
+ | Import | What it provides |
73
+ | ------------------- | ------------------------------------- |
74
+ | `iii-sdk` | Core SDK (`init`, types) |
75
+ | `iii-sdk/stream` | Stream client for real-time state |
76
+ | `iii-sdk/state` | State client for key-value operations |
77
+ | `iii-sdk/telemetry` | OpenTelemetry integration |
91
78
 
92
- ### Invoking Functions Async
79
+ ## Deprecated
93
80
 
94
- III Allows you to invoke functions asynchronously, they can be functions from the Core Modules or functions registered by workers.
81
+ `call()` and `callVoid()` are deprecated aliases for `trigger()` and `triggerVoid()`. They still work but will be removed in a future release.
95
82
 
96
- ```javascript
97
- iii.callVoid('myFunction', { param1: 'value1' })
98
- ```
83
+ ## Resources
99
84
 
100
- This means the Engine won't hold the execution of the function, it will return immediately. Which means the function will be executed in the background.
85
+ - [Documentation](https://iii.dev/docs)
86
+ - [iii Engine](https://github.com/iii-hq/iii)
87
+ - [Examples](https://github.com/iii-hq/iii-examples)
package/dist/index.cjs CHANGED
@@ -25,7 +25,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
 
27
27
  //#endregion
28
- const require_otel_worker_gauges = require('./otel-worker-gauges-wK5b_eLY.cjs');
28
+ const require_utils = require('./utils-DYxVY7fy.cjs');
29
29
  let __opentelemetry_api = require("@opentelemetry/api");
30
30
  let node_module = require("node:module");
31
31
  let node_os = require("node:os");
@@ -189,7 +189,7 @@ let MessageType = /* @__PURE__ */ function(MessageType$1) {
189
189
  //#region src/logger.ts
190
190
  var Logger = class {
191
191
  get otelLogger() {
192
- if (!this._otelLogger) this._otelLogger = require_otel_worker_gauges.getLogger();
192
+ if (!this._otelLogger) this._otelLogger = require_utils.getLogger();
193
193
  return this._otelLogger;
194
194
  }
195
195
  constructor(traceId, serviceName, spanId) {
@@ -203,7 +203,7 @@ var Logger = class {
203
203
  if (this.traceId) attributes.trace_id = this.traceId;
204
204
  if (this.spanId) attributes.span_id = this.spanId;
205
205
  if (this.serviceName) attributes["service.name"] = this.serviceName;
206
- if (data !== void 0) attributes["log.data"] = typeof data === "string" ? data : require_otel_worker_gauges.safeStringify(data);
206
+ if (data !== void 0) attributes["log.data"] = data;
207
207
  if (this.otelLogger) this.otelLogger.emit({
208
208
  severityNumber: severity,
209
209
  body: message,
@@ -268,7 +268,6 @@ var Sdk = class {
268
268
  this.address = address;
269
269
  this.options = options;
270
270
  this.functions = /* @__PURE__ */ new Map();
271
- this.httpFunctions = /* @__PURE__ */ new Map();
272
271
  this.services = /* @__PURE__ */ new Map();
273
272
  this.invocations = /* @__PURE__ */ new Map();
274
273
  this.triggers = /* @__PURE__ */ new Map();
@@ -315,59 +314,50 @@ var Sdk = class {
315
314
  this.triggers.delete(id);
316
315
  } };
317
316
  };
318
- this.registerFunction = (message, handler) => {
317
+ this.registerFunction = (message, handlerOrInvocation) => {
319
318
  if (!message.id || message.id.trim() === "") throw new Error("id is required");
320
- if (this.httpFunctions.has(message.id)) throw new Error(`function id already registered: ${message.id}`);
321
- this.sendMessage(MessageType.RegisterFunction, message, true);
322
- this.functions.set(message.id, {
323
- message: {
324
- ...message,
325
- message_type: MessageType.RegisterFunction
326
- },
327
- handler: async (input, traceparent, baggage) => {
328
- if (require_otel_worker_gauges.getTracer()) {
329
- const parentContext = require_otel_worker_gauges.extractContext(traceparent, baggage);
330
- return __opentelemetry_api.context.with(parentContext, () => require_otel_worker_gauges.withSpan(`call ${message.id}`, { kind: __opentelemetry_api.SpanKind.SERVER }, async (span) => {
331
- const traceId = require_otel_worker_gauges.currentTraceId() ?? crypto.randomUUID();
332
- const spanId = require_otel_worker_gauges.currentSpanId();
333
- return withContext(async () => await handler(input), {
334
- logger: new Logger(traceId, message.id, spanId),
335
- trace: span
336
- });
337
- }));
338
- }
339
- return withContext(async () => await handler(input), { logger: new Logger(crypto.randomUUID(), message.id) });
340
- }
341
- });
342
- return {
343
- id: message.id,
344
- unregister: () => {
345
- this.sendMessage(MessageType.UnregisterFunction, { id: message.id }, true);
346
- this.functions.delete(message.id);
347
- }
348
- };
349
- };
350
- this.registerHttpFunction = (id, config) => {
351
- if (!id || id.trim() === "") throw new Error("id is required");
352
- if (this.functions.has(id) || this.httpFunctions.has(id)) throw new Error(`function id already registered: ${id}`);
353
- const message = {
319
+ if (this.functions.has(message.id)) throw new Error(`function id already registered: ${message.id}`);
320
+ const isHandler = typeof handlerOrInvocation === "function";
321
+ const fullMessage = isHandler ? {
322
+ ...message,
323
+ message_type: MessageType.RegisterFunction
324
+ } : {
325
+ ...message,
354
326
  message_type: MessageType.RegisterFunction,
355
- id,
356
327
  invocation: {
357
- url: config.url,
358
- method: config.method ?? "POST",
359
- timeout_ms: config.timeout_ms,
360
- headers: config.headers,
361
- auth: config.auth
328
+ url: handlerOrInvocation.url,
329
+ method: handlerOrInvocation.method ?? "POST",
330
+ timeout_ms: handlerOrInvocation.timeout_ms,
331
+ headers: handlerOrInvocation.headers,
332
+ auth: handlerOrInvocation.auth
362
333
  }
363
334
  };
364
- this.sendMessage(MessageType.RegisterFunction, message, true);
365
- this.httpFunctions.set(id, message);
335
+ this.sendMessage(MessageType.RegisterFunction, fullMessage, true);
336
+ if (isHandler) {
337
+ const handler = handlerOrInvocation;
338
+ this.functions.set(message.id, {
339
+ message: fullMessage,
340
+ handler: async (input, traceparent, baggage) => {
341
+ if (require_utils.getTracer()) {
342
+ const parentContext = require_utils.extractContext(traceparent, baggage);
343
+ return __opentelemetry_api.context.with(parentContext, () => require_utils.withSpan(`call ${message.id}`, { kind: __opentelemetry_api.SpanKind.SERVER }, async (span) => {
344
+ const traceId = require_utils.currentTraceId() ?? crypto.randomUUID();
345
+ const spanId = require_utils.currentSpanId();
346
+ return withContext(async () => await handler(input), {
347
+ logger: new Logger(traceId, message.id, spanId),
348
+ trace: span
349
+ });
350
+ }));
351
+ }
352
+ return withContext(async () => await handler(input), { logger: new Logger(crypto.randomUUID(), message.id) });
353
+ }
354
+ });
355
+ } else this.functions.set(message.id, { message: fullMessage });
366
356
  return {
367
- id,
357
+ id: message.id,
368
358
  unregister: () => {
369
- this.sendMessage(MessageType.UnregisterFunction, { id }, true);
370
- this.httpFunctions.delete(id);
359
+ this.sendMessage(MessageType.UnregisterFunction, { id: message.id }, true);
360
+ this.functions.delete(message.id);
371
361
  }
372
362
  };
373
363
  };
@@ -389,8 +379,8 @@ var Sdk = class {
389
379
  };
390
380
  this.trigger = async (function_id, data, timeoutMs) => {
391
381
  const invocation_id = crypto.randomUUID();
392
- const traceparent = require_otel_worker_gauges.injectTraceparent();
393
- const baggage = require_otel_worker_gauges.injectBaggage();
382
+ const traceparent = require_utils.injectTraceparent();
383
+ const baggage = require_utils.injectBaggage();
394
384
  const effectiveTimeout = timeoutMs ?? this.invocationTimeoutMs;
395
385
  return new Promise((resolve, reject) => {
396
386
  const timeout = setTimeout(() => {
@@ -420,8 +410,8 @@ var Sdk = class {
420
410
  });
421
411
  };
422
412
  this.triggerVoid = (function_id, data) => {
423
- const traceparent = require_otel_worker_gauges.injectTraceparent();
424
- const baggage = require_otel_worker_gauges.injectBaggage();
413
+ const traceparent = require_utils.injectTraceparent();
414
+ const baggage = require_utils.injectBaggage();
425
415
  this.sendMessage(MessageType.InvokeFunction, {
426
416
  function_id,
427
417
  data,
@@ -432,10 +422,10 @@ var Sdk = class {
432
422
  this.call = async (function_id, data, timeoutMs) => this.trigger(function_id, data, timeoutMs);
433
423
  this.callVoid = (function_id, data) => this.triggerVoid(function_id, data);
434
424
  this.listFunctions = async () => {
435
- return (await this.trigger(require_otel_worker_gauges.EngineFunctions.LIST_FUNCTIONS, {})).functions;
425
+ return (await this.trigger(require_utils.EngineFunctions.LIST_FUNCTIONS, {})).functions;
436
426
  };
437
427
  this.listWorkers = async () => {
438
- return (await this.trigger(require_otel_worker_gauges.EngineFunctions.LIST_WORKERS, {})).workers;
428
+ return (await this.trigger(require_utils.EngineFunctions.LIST_WORKERS, {})).workers;
439
429
  };
440
430
  this.createStream = (streamName, stream) => {
441
431
  this.registerFunction({ id: `stream::get(${streamName})` }, stream.get.bind(stream));
@@ -456,7 +446,7 @@ var Sdk = class {
456
446
  return null;
457
447
  });
458
448
  this.functionsAvailableTrigger = this.registerTrigger({
459
- type: require_otel_worker_gauges.EngineTriggers.FUNCTIONS_AVAILABLE,
449
+ type: require_utils.EngineTriggers.FUNCTIONS_AVAILABLE,
460
450
  function_id,
461
451
  config: {}
462
452
  });
@@ -487,7 +477,7 @@ var Sdk = class {
487
477
  return null;
488
478
  });
489
479
  this.logTrigger = this.registerTrigger({
490
- type: require_otel_worker_gauges.EngineTriggers.LOG,
480
+ type: require_utils.EngineTriggers.LOG,
491
481
  function_id,
492
482
  config: {
493
483
  level: "all",
@@ -514,7 +504,7 @@ var Sdk = class {
514
504
  this.shutdown = async () => {
515
505
  this.isShuttingDown = true;
516
506
  this.stopMetricsReporting();
517
- await require_otel_worker_gauges.shutdownOtel();
507
+ await require_utils.shutdownOtel();
518
508
  this.clearReconnectTimeout();
519
509
  for (const [_id, invocation] of this.invocations) {
520
510
  if (invocation.timeout) clearTimeout(invocation.timeout);
@@ -531,12 +521,12 @@ var Sdk = class {
531
521
  };
532
522
  this.workerName = options?.workerName ?? getDefaultWorkerName();
533
523
  this.metricsReportingEnabled = options?.enableMetricsReporting ?? true;
534
- this.invocationTimeoutMs = options?.invocationTimeoutMs ?? require_otel_worker_gauges.DEFAULT_INVOCATION_TIMEOUT_MS;
524
+ this.invocationTimeoutMs = options?.invocationTimeoutMs ?? require_utils.DEFAULT_INVOCATION_TIMEOUT_MS;
535
525
  this.reconnectionConfig = {
536
- ...require_otel_worker_gauges.DEFAULT_BRIDGE_RECONNECTION_CONFIG,
526
+ ...require_utils.DEFAULT_BRIDGE_RECONNECTION_CONFIG,
537
527
  ...options?.reconnectionConfig
538
528
  };
539
- require_otel_worker_gauges.initOtel({
529
+ require_utils.initOtel({
540
530
  ...options?.otel,
541
531
  engineWsUrl: this.address
542
532
  });
@@ -545,7 +535,7 @@ var Sdk = class {
545
535
  registerWorkerMetadata() {
546
536
  const telemetryOpts = this.options?.telemetry;
547
537
  const language = telemetryOpts?.language ?? Intl.DateTimeFormat().resolvedOptions().locale ?? process.env.LANG?.split(".")[0];
548
- this.triggerVoid(require_otel_worker_gauges.EngineFunctions.REGISTER_WORKER, {
538
+ this.triggerVoid(require_utils.EngineFunctions.REGISTER_WORKER, {
549
539
  runtime: "node",
550
540
  version: SDK_VERSION,
551
541
  name: this.workerName,
@@ -608,18 +598,18 @@ var Sdk = class {
608
598
  }
609
599
  startMetricsReporting() {
610
600
  if (!this.metricsReportingEnabled || !this.workerId) return;
611
- const meter = require_otel_worker_gauges.getMeter();
601
+ const meter = require_utils.getMeter();
612
602
  if (!meter) {
613
603
  console.warn("[iii] Worker metrics disabled: OpenTelemetry not initialized. Call initOtel() with metricsEnabled: true before creating the iii.");
614
604
  return;
615
605
  }
616
- require_otel_worker_gauges.registerWorkerGauges(meter, {
606
+ require_utils.registerWorkerGauges(meter, {
617
607
  workerId: this.workerId,
618
608
  workerName: this.workerName
619
609
  });
620
610
  }
621
611
  stopMetricsReporting() {
622
- require_otel_worker_gauges.stopWorkerGauges();
612
+ require_utils.stopWorkerGauges();
623
613
  }
624
614
  onSocketClose() {
625
615
  this.ws?.removeAllListeners();
@@ -643,9 +633,6 @@ var Sdk = class {
643
633
  this.functions.forEach(({ message }) => {
644
634
  this.sendMessage(MessageType.RegisterFunction, message, true);
645
635
  });
646
- this.httpFunctions.forEach((message) => {
647
- this.sendMessage(MessageType.RegisterFunction, message, true);
648
- });
649
636
  this.triggers.forEach((trigger) => {
650
637
  this.sendMessage(MessageType.RegisterTrigger, trigger, true);
651
638
  });
@@ -706,7 +693,7 @@ var Sdk = class {
706
693
  else if (!skipIfClosed) this.messagesToSend.push(wireMessage);
707
694
  }
708
695
  logError(message, error) {
709
- const otelLogger = require_otel_worker_gauges.getLogger();
696
+ const otelLogger = require_utils.getLogger();
710
697
  const errorMessage = error instanceof Error ? error.message : String(error ?? "");
711
698
  if (otelLogger) otelLogger.emit({
712
699
  severityNumber: __opentelemetry_api_logs.SeverityNumber.ERROR,
@@ -735,7 +722,7 @@ var Sdk = class {
735
722
  this.invocations.delete(invocation_id);
736
723
  }
737
724
  resolveChannelValue(value) {
738
- if (require_otel_worker_gauges.isChannelRef(value)) return value.direction === "read" ? new ChannelReader(this.address, value) : new ChannelWriter(this.address, value);
725
+ if (require_utils.isChannelRef(value)) return value.direction === "read" ? new ChannelReader(this.address, value) : new ChannelWriter(this.address, value);
739
726
  if (Array.isArray(value)) return value.map((item) => this.resolveChannelValue(item));
740
727
  if (value !== null && typeof value === "object") {
741
728
  const out = {};
@@ -746,10 +733,10 @@ var Sdk = class {
746
733
  }
747
734
  async onInvokeFunction(invocation_id, function_id, input, traceparent, baggage) {
748
735
  const fn = this.functions.get(function_id);
749
- const getResponseTraceparent = () => require_otel_worker_gauges.injectTraceparent() ?? traceparent;
750
- const getResponseBaggage = () => require_otel_worker_gauges.injectBaggage() ?? baggage;
736
+ const getResponseTraceparent = () => require_utils.injectTraceparent() ?? traceparent;
737
+ const getResponseBaggage = () => require_utils.injectBaggage() ?? baggage;
751
738
  const resolvedInput = this.resolveChannelValue(input);
752
- if (fn) {
739
+ if (fn?.handler) {
753
740
  if (!invocation_id) {
754
741
  try {
755
742
  await fn.handler(resolvedInput, traceparent, baggage);
@@ -779,16 +766,20 @@ var Sdk = class {
779
766
  baggage: getResponseBaggage()
780
767
  });
781
768
  }
782
- } else this.sendMessage(MessageType.InvocationResult, {
783
- invocation_id,
784
- function_id,
785
- error: {
786
- code: "function_not_found",
787
- message: "Function not found"
788
- },
789
- traceparent,
790
- baggage
791
- });
769
+ } else {
770
+ const errorCode = fn ? "function_not_invokable" : "function_not_found";
771
+ const errorMessage = fn ? "Function is HTTP-invoked and cannot be invoked locally" : "Function not found";
772
+ if (invocation_id) this.sendMessage(MessageType.InvocationResult, {
773
+ invocation_id,
774
+ function_id,
775
+ error: {
776
+ code: errorCode,
777
+ message: errorMessage
778
+ },
779
+ traceparent,
780
+ baggage
781
+ });
782
+ }
792
783
  }
793
784
  async onRegisterTrigger(message) {
794
785
  const { trigger_type, id, function_id, config } = message;
@@ -863,7 +854,7 @@ exports.ChannelWriter = ChannelWriter;
863
854
  exports.Logger = Logger;
864
855
  exports.__toESM = __toESM;
865
856
  exports.getContext = getContext;
866
- exports.http = require_otel_worker_gauges.http;
857
+ exports.http = require_utils.http;
867
858
  exports.init = init;
868
859
  exports.withContext = withContext;
869
860
  //# sourceMappingURL=index.cjs.map