@kultify/kmicro-js 0.0.19 → 0.1.3

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,2 +1,111 @@
1
1
  # kmicro-js
2
- Simple microservice framework based on nats micro
2
+
3
+ Simple microservice framework based on [NATS micro](https://github.com/nats-io/nats.js/tree/main/services).
4
+
5
+ Features:
6
+
7
+ - Request/response RPC over NATS with binary payloads
8
+ - OpenTelemetry distributed tracing (context propagation across service calls)
9
+ - Automatic header propagation through call chains
10
+ - Call depth limiting (max 20) to prevent infinite loops
11
+ - Pino JSON logging with trace/span correlation
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @kultify/kmicro-js
17
+ ```
18
+
19
+ ## OpenTelemetry Setup
20
+
21
+ kmicro-js uses the [OpenTelemetry API](https://opentelemetry.io/docs/languages/js/libraries/) to create spans and propagate trace context. It does **not** initialize the OTel SDK — your application is responsible for that.
22
+
23
+ If no SDK is registered, tracing becomes a no-op.
24
+
25
+ Create an `instrumentation.ts` file and load it **before** any other imports:
26
+
27
+ ```typescript
28
+ // instrumentation.ts
29
+ import { NodeSDK } from "@opentelemetry/sdk-node";
30
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
31
+ import { resourceFromAttributes } from "@opentelemetry/resources";
32
+ import { PinoInstrumentation } from "@opentelemetry/instrumentation-pino";
33
+ import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
34
+ import { ATTR_MESSAGING_SYSTEM } from "@opentelemetry/semantic-conventions/incubating";
35
+
36
+ const sdk = new NodeSDK({
37
+ resource: resourceFromAttributes({
38
+ [ATTR_SERVICE_NAME]: "my-service",
39
+ [ATTR_MESSAGING_SYSTEM]: "nats",
40
+ }),
41
+ traceExporter: new OTLPTraceExporter(),
42
+ instrumentations: [
43
+ new PinoInstrumentation({ disableLogSending: true }),
44
+ ],
45
+ });
46
+
47
+ sdk.start();
48
+ ```
49
+
50
+ Then load it first via Node's `--import` flag:
51
+
52
+ ```bash
53
+ node --import ./instrumentation.js ./main.js
54
+ ```
55
+
56
+ Required OTel packages for the application:
57
+
58
+ ```bash
59
+ npm install @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-proto \
60
+ @opentelemetry/resources @opentelemetry/semantic-conventions \
61
+ @opentelemetry/instrumentation-pino
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ```typescript
67
+ import { init } from "@kultify/kmicro-js";
68
+
69
+ const service = await init("nats://localhost:4222", "my-service", "0.0.1");
70
+
71
+ // Register an endpoint
72
+ service.addEndpoint("greet", async (context, data) => {
73
+ const request = JSON.parse(Buffer.from(data).toString());
74
+ const logger = context.getLogger("greet");
75
+ logger.info({ request }, "received greeting request");
76
+
77
+ return Buffer.from(JSON.stringify({ hello: request.name }));
78
+ });
79
+
80
+ // Call another service
81
+ const result = await service.call(
82
+ "other-service.action",
83
+ Buffer.from(JSON.stringify({ key: "value" })),
84
+ );
85
+
86
+ // Call with custom headers and timeout
87
+ const result2 = await service.call(
88
+ "other-service.action",
89
+ Buffer.from(JSON.stringify({ key: "value" })),
90
+ {
91
+ timeout: 10000,
92
+ header: { "X-Auth": "token" },
93
+ },
94
+ );
95
+
96
+ // Downstream calls from within a handler preserve trace context and headers
97
+ service.addEndpoint("orchestrate", async (context, data) => {
98
+ const downstream = await context.call(
99
+ "other-service.action",
100
+ Buffer.from(JSON.stringify({ foo: "bar" })),
101
+ );
102
+ return downstream;
103
+ });
104
+
105
+ // Graceful shutdown
106
+ await service.stop();
107
+ ```
108
+
109
+ ## License
110
+
111
+ MIT
package/dist/index.cjs CHANGED
@@ -42,40 +42,37 @@ var import_node_assert = __toESM(require("assert"), 1);
42
42
  var import_services = require("@nats-io/services");
43
43
  var import_transport_node = require("@nats-io/transport-node");
44
44
  var import_api = require("@opentelemetry/api");
45
- var import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
46
- var import_instrumentation_pino = require("@opentelemetry/instrumentation-pino");
47
- var import_resources = require("@opentelemetry/resources");
48
- var import_sdk_node = require("@opentelemetry/sdk-node");
49
- var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
50
45
  var import_incubating = require("@opentelemetry/semantic-conventions/incubating");
51
46
  var import_pino = __toESM(require("pino"), 1);
52
- async function init(nats, serviceName, version, description, enableOtel = true) {
53
- const kmicro = new Kmicro({
54
- name: serviceName,
55
- version,
56
- description
57
- });
58
- await kmicro.init(nats, enableOtel);
47
+ async function init(nats, serviceName, version, description, logger) {
48
+ const kmicro = new Kmicro(
49
+ {
50
+ name: serviceName,
51
+ version,
52
+ description
53
+ },
54
+ logger
55
+ );
56
+ await kmicro.init(nats);
59
57
  return kmicro;
60
58
  }
61
59
  var Kmicro = class {
62
- constructor(meta) {
60
+ constructor(meta, logger) {
63
61
  this.meta = meta;
64
- this.pinoLogger = import_pino.default.pino();
62
+ this.logger = logger ?? import_pino.default.pino();
65
63
  }
66
64
  service;
67
65
  group;
68
66
  nc;
69
- otel;
70
- pinoLogger;
67
+ logger;
71
68
  getLogger(module2) {
72
- return this.pinoLogger.child({ module: module2 });
69
+ return this.logger.child({ module: module2 });
73
70
  }
74
71
  getNc() {
75
72
  (0, import_node_assert.default)(this.nc);
76
73
  return this.nc;
77
74
  }
78
- async init(natsURI, enableOtel = true) {
75
+ async init(natsURI) {
79
76
  const natsUrl = new URL(natsURI);
80
77
  this.nc = await (0, import_transport_node.connect)({
81
78
  name: this.meta.name,
@@ -90,22 +87,6 @@ var Kmicro = class {
90
87
  description: this.meta.description
91
88
  });
92
89
  this.group = this.service.addGroup(this.meta.name);
93
- if (enableOtel) {
94
- this.otel = new import_sdk_node.NodeSDK({
95
- serviceName: this.meta.name,
96
- traceExporter: new import_exporter_trace_otlp_proto.OTLPTraceExporter(),
97
- resource: (0, import_resources.resourceFromAttributes)({
98
- [import_semantic_conventions.ATTR_SERVICE_NAME]: this.meta.name,
99
- [import_incubating.ATTR_MESSAGING_SYSTEM]: "nats"
100
- }),
101
- instrumentations: [
102
- new import_instrumentation_pino.PinoInstrumentation({
103
- disableLogSending: true
104
- })
105
- ]
106
- });
107
- this.otel.start();
108
- }
109
90
  }
110
91
  async stop() {
111
92
  await this.service?.stop().catch((error) => {
@@ -114,9 +95,6 @@ var Kmicro = class {
114
95
  await this.nc?.close().catch((error) => {
115
96
  console.error(error);
116
97
  });
117
- await this.otel?.shutdown().catch((error) => {
118
- console.error(error);
119
- });
120
98
  }
121
99
  addEndpoint(name, handler) {
122
100
  (0, import_node_assert.default)(this.group);
@@ -154,7 +132,7 @@ var Kmicro = class {
154
132
  },
155
133
  contextWithOtel,
156
134
  async (span) => {
157
- const spanLogger = this.pinoLogger.child({
135
+ const spanLogger = this.logger.child({
158
136
  action: name,
159
137
  spanId: span.spanContext().spanId,
160
138
  traceId: span.spanContext().traceId
@@ -182,6 +160,13 @@ var Kmicro = class {
182
160
  message.respond(result);
183
161
  span.setStatus({ code: import_api.SpanStatusCode.OK });
184
162
  } catch (error_) {
163
+ this.logger.error(
164
+ {
165
+ err: error_,
166
+ action: name
167
+ },
168
+ `error in handler: ${error_?.message}`
169
+ );
185
170
  span.recordException(error_);
186
171
  message.respondError(500, error_.message);
187
172
  span.setStatus({ code: import_api.SpanStatusCode.ERROR });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/KMicro.ts"],"sourcesContent":["export * from \"./KMicro.js\";\n","import assert from \"node:assert\";\nimport { type Service, type ServiceGroup, Svcm } from \"@nats-io/services\";\nimport { connect, headers, type NatsConnection } from \"@nats-io/transport-node\";\nimport {\n\ttype Context,\n\tcontext,\n\tpropagation,\n\ttype Span,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from \"@opentelemetry/api\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-proto\";\nimport { PinoInstrumentation } from \"@opentelemetry/instrumentation-pino\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport { NodeSDK } from \"@opentelemetry/sdk-node\";\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\";\nimport {\n\tATTR_MESSAGING_SYSTEM,\n\tATTR_RPC_METHOD,\n\tATTR_RPC_SERVICE,\n} from \"@opentelemetry/semantic-conventions/incubating\";\nimport pino, { type Logger } from \"pino\";\n\n/**\n * Use init to create a kmicro instance and directly start (init) it\n */\nexport async function init(\n\tnats: string,\n\tserviceName: string,\n\tversion: string,\n\tdescription?: string,\n\tenableOtel = true,\n) {\n\tconst kmicro = new Kmicro({\n\t\tname: serviceName,\n\t\tversion,\n\t\tdescription,\n\t});\n\tawait kmicro.init(nats, enableOtel);\n\treturn kmicro;\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface Callable {\n\tcall(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t},\n\t): Promise<Uint8Array>;\n}\n\nexport class Kmicro implements Callable {\n\tprivate service: Service | undefined;\n\tprivate group: ServiceGroup | undefined;\n\tprivate nc: NatsConnection | undefined;\n\tprivate otel: NodeSDK | undefined;\n\tprivate readonly pinoLogger: pino.Logger;\n\n\tconstructor(\n\t\tprivate readonly meta: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\tdescription: string | undefined;\n\t\t},\n\t) {\n\t\tthis.pinoLogger = pino.pino();\n\t}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.pinoLogger.child({ module });\n\t}\n\n\tpublic getNc(): NatsConnection {\n\t\tassert(this.nc);\n\t\treturn this.nc;\n\t}\n\n\tpublic async init(natsURI: string, enableOtel = true) {\n\t\tconst natsUrl = new URL(natsURI);\n\t\tthis.nc = await connect({\n\t\t\tname: this.meta.name,\n\t\t\tuser: natsUrl.username,\n\t\t\tpass: natsUrl.password,\n\t\t\tservers: [natsUrl.host],\n\t\t});\n\t\tconst svc = new Svcm(this.nc);\n\t\tthis.service = await svc.add({\n\t\t\tname: this.meta.name,\n\t\t\tversion: this.meta.version,\n\t\t\tdescription: this.meta.description,\n\t\t});\n\t\tthis.group = this.service.addGroup(this.meta.name);\n\t\tif (enableOtel) {\n\t\t\tthis.otel = new NodeSDK({\n\t\t\t\tserviceName: this.meta.name,\n\t\t\t\ttraceExporter: new OTLPTraceExporter(),\n\t\t\t\tresource: resourceFromAttributes({\n\t\t\t\t\t[ATTR_SERVICE_NAME]: this.meta.name,\n\t\t\t\t\t[ATTR_MESSAGING_SYSTEM]: \"nats\",\n\t\t\t\t}),\n\t\t\t\tinstrumentations: [\n\t\t\t\t\tnew PinoInstrumentation({\n\t\t\t\t\t\tdisableLogSending: true,\n\t\t\t\t\t}),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tthis.otel.start();\n\t\t}\n\t}\n\n\tpublic async stop() {\n\t\tawait this.service?.stop().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t\tawait this.nc?.close().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t\tawait this.otel?.shutdown().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t}\n\n\tpublic addEndpoint(\n\t\tname: string,\n\t\thandler: (\n\t\t\tcontext_: RequestContext,\n\t\t\tdata: Uint8Array,\n\t\t) => Promise<Uint8Array>,\n\t) {\n\t\tassert(this.group);\n\n\t\tthis.group.addEndpoint(name, async (error, message) => {\n\t\t\tassert(this.nc);\n\t\t\tif (error) {\n\t\t\t\tconsole.error(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prevent infinite loops\n\t\t\tconst currentCallDepth = Number.parseInt(\n\t\t\t\tmessage.headers?.get(\"kmc-depth\") ?? \"0\",\n\t\t\t\t10,\n\t\t\t);\n\t\t\tif (currentCallDepth >= 20) {\n\t\t\t\tthrow new Error(`max call depth reached: ${currentCallDepth}`);\n\t\t\t}\n\n\t\t\tconst contextWithOtel: Context = propagation.extract(\n\t\t\t\tcontext.active(),\n\t\t\t\tmessage.headers,\n\t\t\t\t{\n\t\t\t\t\tget(carrier, key) {\n\t\t\t\t\t\treturn carrier?.get(key);\n\t\t\t\t\t},\n\t\t\t\t\tkeys(carrier) {\n\t\t\t\t\t\treturn carrier?.keys() ?? [];\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst tracer = trace.getTracer(this.meta.name, this.meta.version);\n\t\t\tconst spanName = `handle: ${this.meta.name}.${name}`;\n\t\t\tawait tracer.startActiveSpan(\n\t\t\t\tspanName,\n\t\t\t\t{\n\t\t\t\t\tkind: SpanKind.SERVER,\n\t\t\t\t},\n\t\t\t\tcontextWithOtel,\n\t\t\t\tasync (span) => {\n\t\t\t\t\tconst spanLogger = this.pinoLogger.child({\n\t\t\t\t\t\taction: name,\n\t\t\t\t\t\tspanId: span.spanContext().spanId,\n\t\t\t\t\t\ttraceId: span.spanContext().traceId,\n\t\t\t\t\t});\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst header: Record<string, string> = {};\n\t\t\t\t\t\tfor (const key of message.headers?.keys() ?? []) {\n\t\t\t\t\t\t\tif (message.headers?.has(key)) {\n\t\t\t\t\t\t\t\theader[key] = message.headers?.get(key);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst requestContext = new RequestContext(\n\t\t\t\t\t\t\tcontextWithOtel,\n\t\t\t\t\t\t\tspan,\n\t\t\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: Checked with assert\n\t\t\t\t\t\t\tthis.nc!,\n\t\t\t\t\t\t\tspanLogger,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallDepth: currentCallDepth,\n\t\t\t\t\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst result = await handler(requestContext, message.data);\n\t\t\t\t\t\tmessage.respond(result);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\t\t} catch (error_) {\n\t\t\t\t\t\tspan.recordException(error_ as Error);\n\t\t\t\t\t\tmessage.respondError(500, (error_ as Error).message);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tspan.end();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Start a new call\n\t */\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t\tmoleculerTrace?: {\n\t\t\t\ttraceId?: string | undefined;\n\t\t\t\tparentId?: string | undefined;\n\t\t\t};\n\t\t},\n\t): Promise<Uint8Array> {\n\t\tassert(this.nc);\n\n\t\tlet trace:\n\t\t\t| undefined\n\t\t\t| {\n\t\t\t\t\ttraceId: string;\n\t\t\t\t\tparentId: string;\n\t\t\t };\n\t\tif (options?.moleculerTrace) {\n\t\t\t// we have to shorten the moleculer trace id because the jaeger exporter uses only 16 chars\n\t\t\tconst molTraceId = options.moleculerTrace.traceId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\tconst traceId = Array.from({ length: 16 })\n\t\t\t\t.fill(\"0\")\n\t\t\t\t.join(\"\")\n\t\t\t\t.concat(molTraceId ?? \"\");\n\t\t\tconst molParentId = options.moleculerTrace.parentId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\ttrace = {\n\t\t\t\ttraceId,\n\t\t\t\tparentId: molParentId ?? \"\",\n\t\t\t};\n\t\t}\n\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: 0,\n\t\t\t\tcontext: undefined,\n\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\theader: options?.header ?? {},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttimeout: options?.timeout,\n\t\t\t\ttrace,\n\t\t\t},\n\t\t);\n\t}\n}\n\nexport class RequestContext {\n\t// eslint-disable-next-line max-params\n\tconstructor(\n\t\treadonly context: Context,\n\t\treadonly span: Span,\n\t\treadonly nc: NatsConnection,\n\t\tprivate readonly logger: Logger,\n\t\treadonly meta: {\n\t\t\tcallDepth: number;\n\t\t\tcurrentService: string;\n\t\t\theader: Record<string, string>;\n\t\t},\n\t) {}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.logger.child({\n\t\t\tmodule,\n\t\t});\n\t}\n\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t},\n\t): Promise<Uint8Array> {\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: this.meta.callDepth,\n\t\t\t\tcontext: this.context,\n\t\t\t\tcurrentService: this.meta.currentService,\n\t\t\t\theader: this.meta.header,\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n}\n\nexport class CallError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tprivate readonly target: string,\n\t\tprivate readonly payload: Uint8Array,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CallError\";\n\t}\n}\n\n// eslint-disable-next-line max-params\nasync function doCall(\n\tnc: NatsConnection,\n\ttarget: string,\n\tpayload: Uint8Array,\n\tmeta: {\n\t\tcallDepth: number;\n\t\t/**\n\t\t * The otel context\n\t\t */\n\t\tcontext: Context | undefined;\n\t\tcurrentService: string;\n\t\t/**\n\t\t * Headers from the parent calls\n\t\t */\n\t\theader: Record<string, string>;\n\t},\n\toptions?: {\n\t\t/**\n\t\t * @default 5000 ms\n\t\t */\n\t\ttimeout?: number;\n\t\theader?: Record<string, string>;\n\t\t/**\n\t\t * Optionally pass an existing trace from the moleculer framework\n\t\t */\n\t\ttrace?: {\n\t\t\t/**\n\t\t\t * This is the ID of the whole trace forest and is used to uniquely identify a distributed trace through a system.\n\t\t\t */\n\t\t\ttraceId: string | undefined;\n\t\t\t/**\n\t\t\t * or span id: This is the ID of this request as known by the caller\n\t\t\t */\n\t\t\tparentId: string | undefined;\n\t\t};\n\t},\n): Promise<Uint8Array> {\n\tif (meta.callDepth >= 20) {\n\t\tthrow new Error(`max call depth reached: ${meta.callDepth}`);\n\t}\n\n\tconst carrierData: Context | { traceparent?: string } = meta.context ?? {};\n\tif (options?.trace && !meta.context) {\n\t\tconst version = Buffer.alloc(1).toString(\"hex\");\n\t\tconst flags = \"01\"; // means sampled\n\t\tconst header = `${version}-${options.trace.traceId}-${options.trace.parentId}-${flags}`;\n\t\t(carrierData as { traceparent?: string | undefined }).traceparent = header;\n\t}\n\n\tconst callingContext: Context = propagation.extract(\n\t\tcontext.active(),\n\t\tcarrierData,\n\t);\n\tconst tracer = trace.getTracer(\"default\");\n\tconst [service, action] = target.split(\".\");\n\treturn tracer.startActiveSpan(\n\t\t`call: ${target}`,\n\t\t{\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: {\n\t\t\t\t[ATTR_RPC_SERVICE]: service,\n\t\t\t\t[ATTR_RPC_METHOD]: action,\n\t\t\t},\n\t\t},\n\t\tcallingContext,\n\t\tasync (span) => {\n\t\t\t// Add kmicro and otel headers to the nats message headers\n\t\t\tconst natsHeadersMap = headers();\n\t\t\tnatsHeadersMap.set(\"kmc-depth\", (meta.callDepth + 1).toFixed(0));\n\t\t\tpropagation.inject(context.active(), natsHeadersMap, {\n\t\t\t\tset(carrier, key, value) {\n\t\t\t\t\tcarrier.set(key, value);\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst mergedHeaders = { ...meta.header, ...options?.header };\n\t\t\tfor (const key in mergedHeaders) {\n\t\t\t\tif (!Object.hasOwn(mergedHeaders, key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mergedHeaders[key]) {\n\t\t\t\t\tnatsHeadersMap.set(key, mergedHeaders[key]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await nc.request(target, payload, {\n\t\t\t\t\theaders: natsHeadersMap,\n\t\t\t\t\ttimeout: options?.timeout ?? 5000,\n\t\t\t\t});\n\t\t\t\tif (result.headers?.get(\"Nats-Service-Error-Code\")) {\n\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\tspan.recordException(result.headers.get(\"Nats-Service-Error\"));\n\t\t\t\t\tthrow new CallError(\n\t\t\t\t\t\t`received error: ${result.headers.get(\"Nats-Service-Error\")}`,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\treturn result.data;\n\t\t\t} finally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t},\n\t);\n}\n"],"mappings":"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","names":["pino","module","assert","trace","context"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/KMicro.ts"],"sourcesContent":["export * from \"./KMicro.js\";\n","import assert from \"node:assert\";\nimport { type Service, type ServiceGroup, Svcm } from \"@nats-io/services\";\nimport { connect, headers, type NatsConnection } from \"@nats-io/transport-node\";\nimport {\n\ttype Context,\n\tcontext,\n\tpropagation,\n\ttype Span,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from \"@opentelemetry/api\";\nimport {\n\tATTR_RPC_METHOD,\n\tATTR_RPC_SERVICE,\n} from \"@opentelemetry/semantic-conventions/incubating\";\nimport pino, { type Logger } from \"pino\";\n\n/**\n * Use init to create a kmicro instance and directly start (init) it\n */\nexport async function init(\n\tnats: string,\n\tserviceName: string,\n\tversion: string,\n\tdescription?: string,\n\tlogger?: Logger,\n) {\n\tconst kmicro = new Kmicro(\n\t\t{\n\t\t\tname: serviceName,\n\t\t\tversion,\n\t\t\tdescription,\n\t\t},\n\t\tlogger,\n\t);\n\tawait kmicro.init(nats);\n\treturn kmicro;\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface Callable {\n\tcall(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t},\n\t): Promise<Uint8Array>;\n}\n\nexport class Kmicro implements Callable {\n\tprivate service: Service | undefined;\n\tprivate group: ServiceGroup | undefined;\n\tprivate nc: NatsConnection | undefined;\n\tprivate readonly logger: Logger;\n\n\tconstructor(\n\t\tprivate readonly meta: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\tdescription: string | undefined;\n\t\t},\n\t\tlogger?: Logger,\n\t) {\n\t\tthis.logger = logger ?? pino.pino();\n\t}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.logger.child({ module });\n\t}\n\n\tpublic getNc(): NatsConnection {\n\t\tassert(this.nc);\n\t\treturn this.nc;\n\t}\n\n\tpublic async init(natsURI: string) {\n\t\tconst natsUrl = new URL(natsURI);\n\t\tthis.nc = await connect({\n\t\t\tname: this.meta.name,\n\t\t\tuser: natsUrl.username,\n\t\t\tpass: natsUrl.password,\n\t\t\tservers: [natsUrl.host],\n\t\t});\n\t\tconst svc = new Svcm(this.nc);\n\t\tthis.service = await svc.add({\n\t\t\tname: this.meta.name,\n\t\t\tversion: this.meta.version,\n\t\t\tdescription: this.meta.description,\n\t\t});\n\t\tthis.group = this.service.addGroup(this.meta.name);\n\t}\n\n\tpublic async stop() {\n\t\tawait this.service?.stop().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t\tawait this.nc?.close().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t}\n\n\tpublic addEndpoint(\n\t\tname: string,\n\t\thandler: (\n\t\t\tcontext_: RequestContext,\n\t\t\tdata: Uint8Array,\n\t\t) => Promise<Uint8Array>,\n\t) {\n\t\tassert(this.group);\n\n\t\tthis.group.addEndpoint(name, async (error, message) => {\n\t\t\tassert(this.nc);\n\t\t\tif (error) {\n\t\t\t\tconsole.error(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prevent infinite loops\n\t\t\tconst currentCallDepth = Number.parseInt(\n\t\t\t\tmessage.headers?.get(\"kmc-depth\") ?? \"0\",\n\t\t\t\t10,\n\t\t\t);\n\t\t\tif (currentCallDepth >= 20) {\n\t\t\t\tthrow new Error(`max call depth reached: ${currentCallDepth}`);\n\t\t\t}\n\n\t\t\tconst contextWithOtel: Context = propagation.extract(\n\t\t\t\tcontext.active(),\n\t\t\t\tmessage.headers,\n\t\t\t\t{\n\t\t\t\t\tget(carrier, key) {\n\t\t\t\t\t\treturn carrier?.get(key);\n\t\t\t\t\t},\n\t\t\t\t\tkeys(carrier) {\n\t\t\t\t\t\treturn carrier?.keys() ?? [];\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst tracer = trace.getTracer(this.meta.name, this.meta.version);\n\t\t\tconst spanName = `handle: ${this.meta.name}.${name}`;\n\t\t\tawait tracer.startActiveSpan(\n\t\t\t\tspanName,\n\t\t\t\t{\n\t\t\t\t\tkind: SpanKind.SERVER,\n\t\t\t\t},\n\t\t\t\tcontextWithOtel,\n\t\t\t\tasync (span) => {\n\t\t\t\t\tconst spanLogger = this.logger.child({\n\t\t\t\t\t\taction: name,\n\t\t\t\t\t\tspanId: span.spanContext().spanId,\n\t\t\t\t\t\ttraceId: span.spanContext().traceId,\n\t\t\t\t\t});\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst header: Record<string, string> = {};\n\t\t\t\t\t\tfor (const key of message.headers?.keys() ?? []) {\n\t\t\t\t\t\t\tif (message.headers?.has(key)) {\n\t\t\t\t\t\t\t\theader[key] = message.headers?.get(key);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst requestContext = new RequestContext(\n\t\t\t\t\t\t\tcontextWithOtel,\n\t\t\t\t\t\t\tspan,\n\t\t\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: Checked with assert\n\t\t\t\t\t\t\tthis.nc!,\n\t\t\t\t\t\t\tspanLogger,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallDepth: currentCallDepth,\n\t\t\t\t\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst result = await handler(requestContext, message.data);\n\t\t\t\t\t\tmessage.respond(result);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\t\t} catch (error_) {\n\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terr: error_,\n\t\t\t\t\t\t\t\taction: name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t`error in handler: ${(error_ as Error)?.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tspan.recordException(error_ as Error);\n\t\t\t\t\t\tmessage.respondError(500, (error_ as Error).message);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tspan.end();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Start a new call\n\t */\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t\tmoleculerTrace?: {\n\t\t\t\ttraceId?: string | undefined;\n\t\t\t\tparentId?: string | undefined;\n\t\t\t};\n\t\t},\n\t): Promise<Uint8Array> {\n\t\tassert(this.nc);\n\n\t\tlet trace:\n\t\t\t| undefined\n\t\t\t| {\n\t\t\t\t\ttraceId: string;\n\t\t\t\t\tparentId: string;\n\t\t\t };\n\t\tif (options?.moleculerTrace) {\n\t\t\t// we have to shorten the moleculer trace id because the jaeger exporter uses only 16 chars\n\t\t\tconst molTraceId = options.moleculerTrace.traceId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\tconst traceId = Array.from({ length: 16 })\n\t\t\t\t.fill(\"0\")\n\t\t\t\t.join(\"\")\n\t\t\t\t.concat(molTraceId ?? \"\");\n\t\t\tconst molParentId = options.moleculerTrace.parentId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\ttrace = {\n\t\t\t\ttraceId,\n\t\t\t\tparentId: molParentId ?? \"\",\n\t\t\t};\n\t\t}\n\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: 0,\n\t\t\t\tcontext: undefined,\n\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\theader: options?.header ?? {},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttimeout: options?.timeout,\n\t\t\t\ttrace,\n\t\t\t},\n\t\t);\n\t}\n}\n\nexport class RequestContext {\n\t// eslint-disable-next-line max-params\n\tconstructor(\n\t\treadonly context: Context,\n\t\treadonly span: Span,\n\t\treadonly nc: NatsConnection,\n\t\tprivate readonly logger: Logger,\n\t\treadonly meta: {\n\t\t\tcallDepth: number;\n\t\t\tcurrentService: string;\n\t\t\theader: Record<string, string>;\n\t\t},\n\t) {}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.logger.child({\n\t\t\tmodule,\n\t\t});\n\t}\n\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t},\n\t): Promise<Uint8Array> {\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: this.meta.callDepth,\n\t\t\t\tcontext: this.context,\n\t\t\t\tcurrentService: this.meta.currentService,\n\t\t\t\theader: this.meta.header,\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n}\n\nexport class CallError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tprivate readonly target: string,\n\t\tprivate readonly payload: Uint8Array,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CallError\";\n\t}\n}\n\n// eslint-disable-next-line max-params\nasync function doCall(\n\tnc: NatsConnection,\n\ttarget: string,\n\tpayload: Uint8Array,\n\tmeta: {\n\t\tcallDepth: number;\n\t\t/**\n\t\t * The otel context\n\t\t */\n\t\tcontext: Context | undefined;\n\t\tcurrentService: string;\n\t\t/**\n\t\t * Headers from the parent calls\n\t\t */\n\t\theader: Record<string, string>;\n\t},\n\toptions?: {\n\t\t/**\n\t\t * @default 5000 ms\n\t\t */\n\t\ttimeout?: number;\n\t\theader?: Record<string, string>;\n\t\t/**\n\t\t * Optionally pass an existing trace from the moleculer framework\n\t\t */\n\t\ttrace?: {\n\t\t\t/**\n\t\t\t * This is the ID of the whole trace forest and is used to uniquely identify a distributed trace through a system.\n\t\t\t */\n\t\t\ttraceId: string | undefined;\n\t\t\t/**\n\t\t\t * or span id: This is the ID of this request as known by the caller\n\t\t\t */\n\t\t\tparentId: string | undefined;\n\t\t};\n\t},\n): Promise<Uint8Array> {\n\tif (meta.callDepth >= 20) {\n\t\tthrow new Error(`max call depth reached: ${meta.callDepth}`);\n\t}\n\n\tconst carrierData: Context | { traceparent?: string } = meta.context ?? {};\n\tif (options?.trace && !meta.context) {\n\t\tconst version = Buffer.alloc(1).toString(\"hex\");\n\t\tconst flags = \"01\"; // means sampled\n\t\tconst header = `${version}-${options.trace.traceId}-${options.trace.parentId}-${flags}`;\n\t\t(carrierData as { traceparent?: string | undefined }).traceparent = header;\n\t}\n\n\tconst callingContext: Context = propagation.extract(\n\t\tcontext.active(),\n\t\tcarrierData,\n\t);\n\tconst tracer = trace.getTracer(\"default\");\n\tconst [service, action] = target.split(\".\");\n\treturn tracer.startActiveSpan(\n\t\t`call: ${target}`,\n\t\t{\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: {\n\t\t\t\t[ATTR_RPC_SERVICE]: service,\n\t\t\t\t[ATTR_RPC_METHOD]: action,\n\t\t\t},\n\t\t},\n\t\tcallingContext,\n\t\tasync (span) => {\n\t\t\t// Add kmicro and otel headers to the nats message headers\n\t\t\tconst natsHeadersMap = headers();\n\t\t\tnatsHeadersMap.set(\"kmc-depth\", (meta.callDepth + 1).toFixed(0));\n\t\t\tpropagation.inject(context.active(), natsHeadersMap, {\n\t\t\t\tset(carrier, key, value) {\n\t\t\t\t\tcarrier.set(key, value);\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst mergedHeaders = { ...meta.header, ...options?.header };\n\t\t\tfor (const key in mergedHeaders) {\n\t\t\t\tif (!Object.hasOwn(mergedHeaders, key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mergedHeaders[key]) {\n\t\t\t\t\tnatsHeadersMap.set(key, mergedHeaders[key]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await nc.request(target, payload, {\n\t\t\t\t\theaders: natsHeadersMap,\n\t\t\t\t\ttimeout: options?.timeout ?? 5000,\n\t\t\t\t});\n\t\t\t\tif (result.headers?.get(\"Nats-Service-Error-Code\")) {\n\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\tspan.recordException(result.headers.get(\"Nats-Service-Error\"));\n\t\t\t\t\tthrow new CallError(\n\t\t\t\t\t\t`received error: ${result.headers.get(\"Nats-Service-Error\")}`,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\treturn result.data;\n\t\t\t} finally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t},\n\t);\n}\n"],"mappings":"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","names":["pino","module","assert","trace","context"]}
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@ import pino, { Logger } from 'pino';
5
5
  /**
6
6
  * Use init to create a kmicro instance and directly start (init) it
7
7
  */
8
- declare function init(nats: string, serviceName: string, version: string, description?: string, enableOtel?: boolean): Promise<Kmicro>;
8
+ declare function init(nats: string, serviceName: string, version: string, description?: string, logger?: Logger): Promise<Kmicro>;
9
9
  interface Callable {
10
10
  call(target: string, payload: Uint8Array, options?: {
11
11
  /**
@@ -19,16 +19,15 @@ declare class Kmicro implements Callable {
19
19
  private service;
20
20
  private group;
21
21
  private nc;
22
- private otel;
23
- private readonly pinoLogger;
22
+ private readonly logger;
24
23
  constructor(meta: {
25
24
  name: string;
26
25
  version: string;
27
26
  description: string | undefined;
28
- });
27
+ }, logger?: Logger);
29
28
  getLogger(module?: string): pino.Logger<never, boolean>;
30
29
  getNc(): NatsConnection;
31
- init(natsURI: string, enableOtel?: boolean): Promise<void>;
30
+ init(natsURI: string): Promise<void>;
32
31
  stop(): Promise<void>;
33
32
  addEndpoint(name: string, handler: (context_: RequestContext, data: Uint8Array) => Promise<Uint8Array>): void;
34
33
  /**
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import pino, { Logger } from 'pino';
5
5
  /**
6
6
  * Use init to create a kmicro instance and directly start (init) it
7
7
  */
8
- declare function init(nats: string, serviceName: string, version: string, description?: string, enableOtel?: boolean): Promise<Kmicro>;
8
+ declare function init(nats: string, serviceName: string, version: string, description?: string, logger?: Logger): Promise<Kmicro>;
9
9
  interface Callable {
10
10
  call(target: string, payload: Uint8Array, options?: {
11
11
  /**
@@ -19,16 +19,15 @@ declare class Kmicro implements Callable {
19
19
  private service;
20
20
  private group;
21
21
  private nc;
22
- private otel;
23
- private readonly pinoLogger;
22
+ private readonly logger;
24
23
  constructor(meta: {
25
24
  name: string;
26
25
  version: string;
27
26
  description: string | undefined;
28
- });
27
+ }, logger?: Logger);
29
28
  getLogger(module?: string): pino.Logger<never, boolean>;
30
29
  getNc(): NatsConnection;
31
- init(natsURI: string, enableOtel?: boolean): Promise<void>;
30
+ init(natsURI: string): Promise<void>;
32
31
  stop(): Promise<void>;
33
32
  addEndpoint(name: string, handler: (context_: RequestContext, data: Uint8Array) => Promise<Uint8Array>): void;
34
33
  /**
package/dist/index.js CHANGED
@@ -9,44 +9,40 @@ import {
9
9
  SpanStatusCode,
10
10
  trace
11
11
  } from "@opentelemetry/api";
12
- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
13
- import { PinoInstrumentation } from "@opentelemetry/instrumentation-pino";
14
- import { resourceFromAttributes } from "@opentelemetry/resources";
15
- import { NodeSDK } from "@opentelemetry/sdk-node";
16
- import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
17
12
  import {
18
- ATTR_MESSAGING_SYSTEM,
19
13
  ATTR_RPC_METHOD,
20
14
  ATTR_RPC_SERVICE
21
15
  } from "@opentelemetry/semantic-conventions/incubating";
22
16
  import pino from "pino";
23
- async function init(nats, serviceName, version, description, enableOtel = true) {
24
- const kmicro = new Kmicro({
25
- name: serviceName,
26
- version,
27
- description
28
- });
29
- await kmicro.init(nats, enableOtel);
17
+ async function init(nats, serviceName, version, description, logger) {
18
+ const kmicro = new Kmicro(
19
+ {
20
+ name: serviceName,
21
+ version,
22
+ description
23
+ },
24
+ logger
25
+ );
26
+ await kmicro.init(nats);
30
27
  return kmicro;
31
28
  }
32
29
  var Kmicro = class {
33
- constructor(meta) {
30
+ constructor(meta, logger) {
34
31
  this.meta = meta;
35
- this.pinoLogger = pino.pino();
32
+ this.logger = logger ?? pino.pino();
36
33
  }
37
34
  service;
38
35
  group;
39
36
  nc;
40
- otel;
41
- pinoLogger;
37
+ logger;
42
38
  getLogger(module) {
43
- return this.pinoLogger.child({ module });
39
+ return this.logger.child({ module });
44
40
  }
45
41
  getNc() {
46
42
  assert(this.nc);
47
43
  return this.nc;
48
44
  }
49
- async init(natsURI, enableOtel = true) {
45
+ async init(natsURI) {
50
46
  const natsUrl = new URL(natsURI);
51
47
  this.nc = await connect({
52
48
  name: this.meta.name,
@@ -61,22 +57,6 @@ var Kmicro = class {
61
57
  description: this.meta.description
62
58
  });
63
59
  this.group = this.service.addGroup(this.meta.name);
64
- if (enableOtel) {
65
- this.otel = new NodeSDK({
66
- serviceName: this.meta.name,
67
- traceExporter: new OTLPTraceExporter(),
68
- resource: resourceFromAttributes({
69
- [ATTR_SERVICE_NAME]: this.meta.name,
70
- [ATTR_MESSAGING_SYSTEM]: "nats"
71
- }),
72
- instrumentations: [
73
- new PinoInstrumentation({
74
- disableLogSending: true
75
- })
76
- ]
77
- });
78
- this.otel.start();
79
- }
80
60
  }
81
61
  async stop() {
82
62
  await this.service?.stop().catch((error) => {
@@ -85,9 +65,6 @@ var Kmicro = class {
85
65
  await this.nc?.close().catch((error) => {
86
66
  console.error(error);
87
67
  });
88
- await this.otel?.shutdown().catch((error) => {
89
- console.error(error);
90
- });
91
68
  }
92
69
  addEndpoint(name, handler) {
93
70
  assert(this.group);
@@ -125,7 +102,7 @@ var Kmicro = class {
125
102
  },
126
103
  contextWithOtel,
127
104
  async (span) => {
128
- const spanLogger = this.pinoLogger.child({
105
+ const spanLogger = this.logger.child({
129
106
  action: name,
130
107
  spanId: span.spanContext().spanId,
131
108
  traceId: span.spanContext().traceId
@@ -153,6 +130,13 @@ var Kmicro = class {
153
130
  message.respond(result);
154
131
  span.setStatus({ code: SpanStatusCode.OK });
155
132
  } catch (error_) {
133
+ this.logger.error(
134
+ {
135
+ err: error_,
136
+ action: name
137
+ },
138
+ `error in handler: ${error_?.message}`
139
+ );
156
140
  span.recordException(error_);
157
141
  message.respondError(500, error_.message);
158
142
  span.setStatus({ code: SpanStatusCode.ERROR });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/KMicro.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { type Service, type ServiceGroup, Svcm } from \"@nats-io/services\";\nimport { connect, headers, type NatsConnection } from \"@nats-io/transport-node\";\nimport {\n\ttype Context,\n\tcontext,\n\tpropagation,\n\ttype Span,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from \"@opentelemetry/api\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-proto\";\nimport { PinoInstrumentation } from \"@opentelemetry/instrumentation-pino\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport { NodeSDK } from \"@opentelemetry/sdk-node\";\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\";\nimport {\n\tATTR_MESSAGING_SYSTEM,\n\tATTR_RPC_METHOD,\n\tATTR_RPC_SERVICE,\n} from \"@opentelemetry/semantic-conventions/incubating\";\nimport pino, { type Logger } from \"pino\";\n\n/**\n * Use init to create a kmicro instance and directly start (init) it\n */\nexport async function init(\n\tnats: string,\n\tserviceName: string,\n\tversion: string,\n\tdescription?: string,\n\tenableOtel = true,\n) {\n\tconst kmicro = new Kmicro({\n\t\tname: serviceName,\n\t\tversion,\n\t\tdescription,\n\t});\n\tawait kmicro.init(nats, enableOtel);\n\treturn kmicro;\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface Callable {\n\tcall(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t},\n\t): Promise<Uint8Array>;\n}\n\nexport class Kmicro implements Callable {\n\tprivate service: Service | undefined;\n\tprivate group: ServiceGroup | undefined;\n\tprivate nc: NatsConnection | undefined;\n\tprivate otel: NodeSDK | undefined;\n\tprivate readonly pinoLogger: pino.Logger;\n\n\tconstructor(\n\t\tprivate readonly meta: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\tdescription: string | undefined;\n\t\t},\n\t) {\n\t\tthis.pinoLogger = pino.pino();\n\t}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.pinoLogger.child({ module });\n\t}\n\n\tpublic getNc(): NatsConnection {\n\t\tassert(this.nc);\n\t\treturn this.nc;\n\t}\n\n\tpublic async init(natsURI: string, enableOtel = true) {\n\t\tconst natsUrl = new URL(natsURI);\n\t\tthis.nc = await connect({\n\t\t\tname: this.meta.name,\n\t\t\tuser: natsUrl.username,\n\t\t\tpass: natsUrl.password,\n\t\t\tservers: [natsUrl.host],\n\t\t});\n\t\tconst svc = new Svcm(this.nc);\n\t\tthis.service = await svc.add({\n\t\t\tname: this.meta.name,\n\t\t\tversion: this.meta.version,\n\t\t\tdescription: this.meta.description,\n\t\t});\n\t\tthis.group = this.service.addGroup(this.meta.name);\n\t\tif (enableOtel) {\n\t\t\tthis.otel = new NodeSDK({\n\t\t\t\tserviceName: this.meta.name,\n\t\t\t\ttraceExporter: new OTLPTraceExporter(),\n\t\t\t\tresource: resourceFromAttributes({\n\t\t\t\t\t[ATTR_SERVICE_NAME]: this.meta.name,\n\t\t\t\t\t[ATTR_MESSAGING_SYSTEM]: \"nats\",\n\t\t\t\t}),\n\t\t\t\tinstrumentations: [\n\t\t\t\t\tnew PinoInstrumentation({\n\t\t\t\t\t\tdisableLogSending: true,\n\t\t\t\t\t}),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tthis.otel.start();\n\t\t}\n\t}\n\n\tpublic async stop() {\n\t\tawait this.service?.stop().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t\tawait this.nc?.close().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t\tawait this.otel?.shutdown().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t}\n\n\tpublic addEndpoint(\n\t\tname: string,\n\t\thandler: (\n\t\t\tcontext_: RequestContext,\n\t\t\tdata: Uint8Array,\n\t\t) => Promise<Uint8Array>,\n\t) {\n\t\tassert(this.group);\n\n\t\tthis.group.addEndpoint(name, async (error, message) => {\n\t\t\tassert(this.nc);\n\t\t\tif (error) {\n\t\t\t\tconsole.error(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prevent infinite loops\n\t\t\tconst currentCallDepth = Number.parseInt(\n\t\t\t\tmessage.headers?.get(\"kmc-depth\") ?? \"0\",\n\t\t\t\t10,\n\t\t\t);\n\t\t\tif (currentCallDepth >= 20) {\n\t\t\t\tthrow new Error(`max call depth reached: ${currentCallDepth}`);\n\t\t\t}\n\n\t\t\tconst contextWithOtel: Context = propagation.extract(\n\t\t\t\tcontext.active(),\n\t\t\t\tmessage.headers,\n\t\t\t\t{\n\t\t\t\t\tget(carrier, key) {\n\t\t\t\t\t\treturn carrier?.get(key);\n\t\t\t\t\t},\n\t\t\t\t\tkeys(carrier) {\n\t\t\t\t\t\treturn carrier?.keys() ?? [];\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst tracer = trace.getTracer(this.meta.name, this.meta.version);\n\t\t\tconst spanName = `handle: ${this.meta.name}.${name}`;\n\t\t\tawait tracer.startActiveSpan(\n\t\t\t\tspanName,\n\t\t\t\t{\n\t\t\t\t\tkind: SpanKind.SERVER,\n\t\t\t\t},\n\t\t\t\tcontextWithOtel,\n\t\t\t\tasync (span) => {\n\t\t\t\t\tconst spanLogger = this.pinoLogger.child({\n\t\t\t\t\t\taction: name,\n\t\t\t\t\t\tspanId: span.spanContext().spanId,\n\t\t\t\t\t\ttraceId: span.spanContext().traceId,\n\t\t\t\t\t});\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst header: Record<string, string> = {};\n\t\t\t\t\t\tfor (const key of message.headers?.keys() ?? []) {\n\t\t\t\t\t\t\tif (message.headers?.has(key)) {\n\t\t\t\t\t\t\t\theader[key] = message.headers?.get(key);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst requestContext = new RequestContext(\n\t\t\t\t\t\t\tcontextWithOtel,\n\t\t\t\t\t\t\tspan,\n\t\t\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: Checked with assert\n\t\t\t\t\t\t\tthis.nc!,\n\t\t\t\t\t\t\tspanLogger,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallDepth: currentCallDepth,\n\t\t\t\t\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst result = await handler(requestContext, message.data);\n\t\t\t\t\t\tmessage.respond(result);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\t\t} catch (error_) {\n\t\t\t\t\t\tspan.recordException(error_ as Error);\n\t\t\t\t\t\tmessage.respondError(500, (error_ as Error).message);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tspan.end();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Start a new call\n\t */\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t\tmoleculerTrace?: {\n\t\t\t\ttraceId?: string | undefined;\n\t\t\t\tparentId?: string | undefined;\n\t\t\t};\n\t\t},\n\t): Promise<Uint8Array> {\n\t\tassert(this.nc);\n\n\t\tlet trace:\n\t\t\t| undefined\n\t\t\t| {\n\t\t\t\t\ttraceId: string;\n\t\t\t\t\tparentId: string;\n\t\t\t };\n\t\tif (options?.moleculerTrace) {\n\t\t\t// we have to shorten the moleculer trace id because the jaeger exporter uses only 16 chars\n\t\t\tconst molTraceId = options.moleculerTrace.traceId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\tconst traceId = Array.from({ length: 16 })\n\t\t\t\t.fill(\"0\")\n\t\t\t\t.join(\"\")\n\t\t\t\t.concat(molTraceId ?? \"\");\n\t\t\tconst molParentId = options.moleculerTrace.parentId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\ttrace = {\n\t\t\t\ttraceId,\n\t\t\t\tparentId: molParentId ?? \"\",\n\t\t\t};\n\t\t}\n\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: 0,\n\t\t\t\tcontext: undefined,\n\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\theader: options?.header ?? {},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttimeout: options?.timeout,\n\t\t\t\ttrace,\n\t\t\t},\n\t\t);\n\t}\n}\n\nexport class RequestContext {\n\t// eslint-disable-next-line max-params\n\tconstructor(\n\t\treadonly context: Context,\n\t\treadonly span: Span,\n\t\treadonly nc: NatsConnection,\n\t\tprivate readonly logger: Logger,\n\t\treadonly meta: {\n\t\t\tcallDepth: number;\n\t\t\tcurrentService: string;\n\t\t\theader: Record<string, string>;\n\t\t},\n\t) {}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.logger.child({\n\t\t\tmodule,\n\t\t});\n\t}\n\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t},\n\t): Promise<Uint8Array> {\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: this.meta.callDepth,\n\t\t\t\tcontext: this.context,\n\t\t\t\tcurrentService: this.meta.currentService,\n\t\t\t\theader: this.meta.header,\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n}\n\nexport class CallError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tprivate readonly target: string,\n\t\tprivate readonly payload: Uint8Array,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CallError\";\n\t}\n}\n\n// eslint-disable-next-line max-params\nasync function doCall(\n\tnc: NatsConnection,\n\ttarget: string,\n\tpayload: Uint8Array,\n\tmeta: {\n\t\tcallDepth: number;\n\t\t/**\n\t\t * The otel context\n\t\t */\n\t\tcontext: Context | undefined;\n\t\tcurrentService: string;\n\t\t/**\n\t\t * Headers from the parent calls\n\t\t */\n\t\theader: Record<string, string>;\n\t},\n\toptions?: {\n\t\t/**\n\t\t * @default 5000 ms\n\t\t */\n\t\ttimeout?: number;\n\t\theader?: Record<string, string>;\n\t\t/**\n\t\t * Optionally pass an existing trace from the moleculer framework\n\t\t */\n\t\ttrace?: {\n\t\t\t/**\n\t\t\t * This is the ID of the whole trace forest and is used to uniquely identify a distributed trace through a system.\n\t\t\t */\n\t\t\ttraceId: string | undefined;\n\t\t\t/**\n\t\t\t * or span id: This is the ID of this request as known by the caller\n\t\t\t */\n\t\t\tparentId: string | undefined;\n\t\t};\n\t},\n): Promise<Uint8Array> {\n\tif (meta.callDepth >= 20) {\n\t\tthrow new Error(`max call depth reached: ${meta.callDepth}`);\n\t}\n\n\tconst carrierData: Context | { traceparent?: string } = meta.context ?? {};\n\tif (options?.trace && !meta.context) {\n\t\tconst version = Buffer.alloc(1).toString(\"hex\");\n\t\tconst flags = \"01\"; // means sampled\n\t\tconst header = `${version}-${options.trace.traceId}-${options.trace.parentId}-${flags}`;\n\t\t(carrierData as { traceparent?: string | undefined }).traceparent = header;\n\t}\n\n\tconst callingContext: Context = propagation.extract(\n\t\tcontext.active(),\n\t\tcarrierData,\n\t);\n\tconst tracer = trace.getTracer(\"default\");\n\tconst [service, action] = target.split(\".\");\n\treturn tracer.startActiveSpan(\n\t\t`call: ${target}`,\n\t\t{\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: {\n\t\t\t\t[ATTR_RPC_SERVICE]: service,\n\t\t\t\t[ATTR_RPC_METHOD]: action,\n\t\t\t},\n\t\t},\n\t\tcallingContext,\n\t\tasync (span) => {\n\t\t\t// Add kmicro and otel headers to the nats message headers\n\t\t\tconst natsHeadersMap = headers();\n\t\t\tnatsHeadersMap.set(\"kmc-depth\", (meta.callDepth + 1).toFixed(0));\n\t\t\tpropagation.inject(context.active(), natsHeadersMap, {\n\t\t\t\tset(carrier, key, value) {\n\t\t\t\t\tcarrier.set(key, value);\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst mergedHeaders = { ...meta.header, ...options?.header };\n\t\t\tfor (const key in mergedHeaders) {\n\t\t\t\tif (!Object.hasOwn(mergedHeaders, key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mergedHeaders[key]) {\n\t\t\t\t\tnatsHeadersMap.set(key, mergedHeaders[key]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await nc.request(target, payload, {\n\t\t\t\t\theaders: natsHeadersMap,\n\t\t\t\t\ttimeout: options?.timeout ?? 5000,\n\t\t\t\t});\n\t\t\t\tif (result.headers?.get(\"Nats-Service-Error-Code\")) {\n\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\tspan.recordException(result.headers.get(\"Nats-Service-Error\"));\n\t\t\t\t\tthrow new CallError(\n\t\t\t\t\t\t`received error: ${result.headers.get(\"Nats-Service-Error\")}`,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\treturn result.data;\n\t\t\t} finally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t},\n\t);\n}\n"],"mappings":"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","names":["trace","context"]}
1
+ {"version":3,"sources":["../src/KMicro.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { type Service, type ServiceGroup, Svcm } from \"@nats-io/services\";\nimport { connect, headers, type NatsConnection } from \"@nats-io/transport-node\";\nimport {\n\ttype Context,\n\tcontext,\n\tpropagation,\n\ttype Span,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from \"@opentelemetry/api\";\nimport {\n\tATTR_RPC_METHOD,\n\tATTR_RPC_SERVICE,\n} from \"@opentelemetry/semantic-conventions/incubating\";\nimport pino, { type Logger } from \"pino\";\n\n/**\n * Use init to create a kmicro instance and directly start (init) it\n */\nexport async function init(\n\tnats: string,\n\tserviceName: string,\n\tversion: string,\n\tdescription?: string,\n\tlogger?: Logger,\n) {\n\tconst kmicro = new Kmicro(\n\t\t{\n\t\t\tname: serviceName,\n\t\t\tversion,\n\t\t\tdescription,\n\t\t},\n\t\tlogger,\n\t);\n\tawait kmicro.init(nats);\n\treturn kmicro;\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface Callable {\n\tcall(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t},\n\t): Promise<Uint8Array>;\n}\n\nexport class Kmicro implements Callable {\n\tprivate service: Service | undefined;\n\tprivate group: ServiceGroup | undefined;\n\tprivate nc: NatsConnection | undefined;\n\tprivate readonly logger: Logger;\n\n\tconstructor(\n\t\tprivate readonly meta: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\tdescription: string | undefined;\n\t\t},\n\t\tlogger?: Logger,\n\t) {\n\t\tthis.logger = logger ?? pino.pino();\n\t}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.logger.child({ module });\n\t}\n\n\tpublic getNc(): NatsConnection {\n\t\tassert(this.nc);\n\t\treturn this.nc;\n\t}\n\n\tpublic async init(natsURI: string) {\n\t\tconst natsUrl = new URL(natsURI);\n\t\tthis.nc = await connect({\n\t\t\tname: this.meta.name,\n\t\t\tuser: natsUrl.username,\n\t\t\tpass: natsUrl.password,\n\t\t\tservers: [natsUrl.host],\n\t\t});\n\t\tconst svc = new Svcm(this.nc);\n\t\tthis.service = await svc.add({\n\t\t\tname: this.meta.name,\n\t\t\tversion: this.meta.version,\n\t\t\tdescription: this.meta.description,\n\t\t});\n\t\tthis.group = this.service.addGroup(this.meta.name);\n\t}\n\n\tpublic async stop() {\n\t\tawait this.service?.stop().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t\tawait this.nc?.close().catch((error: unknown) => {\n\t\t\tconsole.error(error);\n\t\t});\n\t}\n\n\tpublic addEndpoint(\n\t\tname: string,\n\t\thandler: (\n\t\t\tcontext_: RequestContext,\n\t\t\tdata: Uint8Array,\n\t\t) => Promise<Uint8Array>,\n\t) {\n\t\tassert(this.group);\n\n\t\tthis.group.addEndpoint(name, async (error, message) => {\n\t\t\tassert(this.nc);\n\t\t\tif (error) {\n\t\t\t\tconsole.error(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prevent infinite loops\n\t\t\tconst currentCallDepth = Number.parseInt(\n\t\t\t\tmessage.headers?.get(\"kmc-depth\") ?? \"0\",\n\t\t\t\t10,\n\t\t\t);\n\t\t\tif (currentCallDepth >= 20) {\n\t\t\t\tthrow new Error(`max call depth reached: ${currentCallDepth}`);\n\t\t\t}\n\n\t\t\tconst contextWithOtel: Context = propagation.extract(\n\t\t\t\tcontext.active(),\n\t\t\t\tmessage.headers,\n\t\t\t\t{\n\t\t\t\t\tget(carrier, key) {\n\t\t\t\t\t\treturn carrier?.get(key);\n\t\t\t\t\t},\n\t\t\t\t\tkeys(carrier) {\n\t\t\t\t\t\treturn carrier?.keys() ?? [];\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst tracer = trace.getTracer(this.meta.name, this.meta.version);\n\t\t\tconst spanName = `handle: ${this.meta.name}.${name}`;\n\t\t\tawait tracer.startActiveSpan(\n\t\t\t\tspanName,\n\t\t\t\t{\n\t\t\t\t\tkind: SpanKind.SERVER,\n\t\t\t\t},\n\t\t\t\tcontextWithOtel,\n\t\t\t\tasync (span) => {\n\t\t\t\t\tconst spanLogger = this.logger.child({\n\t\t\t\t\t\taction: name,\n\t\t\t\t\t\tspanId: span.spanContext().spanId,\n\t\t\t\t\t\ttraceId: span.spanContext().traceId,\n\t\t\t\t\t});\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst header: Record<string, string> = {};\n\t\t\t\t\t\tfor (const key of message.headers?.keys() ?? []) {\n\t\t\t\t\t\t\tif (message.headers?.has(key)) {\n\t\t\t\t\t\t\t\theader[key] = message.headers?.get(key);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst requestContext = new RequestContext(\n\t\t\t\t\t\t\tcontextWithOtel,\n\t\t\t\t\t\t\tspan,\n\t\t\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: Checked with assert\n\t\t\t\t\t\t\tthis.nc!,\n\t\t\t\t\t\t\tspanLogger,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallDepth: currentCallDepth,\n\t\t\t\t\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst result = await handler(requestContext, message.data);\n\t\t\t\t\t\tmessage.respond(result);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\t\t} catch (error_) {\n\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terr: error_,\n\t\t\t\t\t\t\t\taction: name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t`error in handler: ${(error_ as Error)?.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tspan.recordException(error_ as Error);\n\t\t\t\t\t\tmessage.respondError(500, (error_ as Error).message);\n\t\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tspan.end();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Start a new call\n\t */\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t\tmoleculerTrace?: {\n\t\t\t\ttraceId?: string | undefined;\n\t\t\t\tparentId?: string | undefined;\n\t\t\t};\n\t\t},\n\t): Promise<Uint8Array> {\n\t\tassert(this.nc);\n\n\t\tlet trace:\n\t\t\t| undefined\n\t\t\t| {\n\t\t\t\t\ttraceId: string;\n\t\t\t\t\tparentId: string;\n\t\t\t };\n\t\tif (options?.moleculerTrace) {\n\t\t\t// we have to shorten the moleculer trace id because the jaeger exporter uses only 16 chars\n\t\t\tconst molTraceId = options.moleculerTrace.traceId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\tconst traceId = Array.from({ length: 16 })\n\t\t\t\t.fill(\"0\")\n\t\t\t\t.join(\"\")\n\t\t\t\t.concat(molTraceId ?? \"\");\n\t\t\tconst molParentId = options.moleculerTrace.parentId\n\t\t\t\t?.replaceAll(\"-\", \"\")\n\t\t\t\t.slice(0, 16);\n\t\t\ttrace = {\n\t\t\t\ttraceId,\n\t\t\t\tparentId: molParentId ?? \"\",\n\t\t\t};\n\t\t}\n\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: 0,\n\t\t\t\tcontext: undefined,\n\t\t\t\tcurrentService: this.meta.name,\n\t\t\t\theader: options?.header ?? {},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttimeout: options?.timeout,\n\t\t\t\ttrace,\n\t\t\t},\n\t\t);\n\t}\n}\n\nexport class RequestContext {\n\t// eslint-disable-next-line max-params\n\tconstructor(\n\t\treadonly context: Context,\n\t\treadonly span: Span,\n\t\treadonly nc: NatsConnection,\n\t\tprivate readonly logger: Logger,\n\t\treadonly meta: {\n\t\t\tcallDepth: number;\n\t\t\tcurrentService: string;\n\t\t\theader: Record<string, string>;\n\t\t},\n\t) {}\n\n\tpublic getLogger(module?: string) {\n\t\treturn this.logger.child({\n\t\t\tmodule,\n\t\t});\n\t}\n\n\tpublic async call(\n\t\ttarget: string,\n\t\tpayload: Uint8Array,\n\t\toptions?: {\n\t\t\t/**\n\t\t\t * @default 5000 ms\n\t\t\t */\n\t\t\ttimeout?: number;\n\t\t\theader?: Record<string, string>;\n\t\t},\n\t): Promise<Uint8Array> {\n\t\treturn doCall(\n\t\t\tthis.nc,\n\t\t\ttarget,\n\t\t\tpayload,\n\t\t\t{\n\t\t\t\tcallDepth: this.meta.callDepth,\n\t\t\t\tcontext: this.context,\n\t\t\t\tcurrentService: this.meta.currentService,\n\t\t\t\theader: this.meta.header,\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n}\n\nexport class CallError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tprivate readonly target: string,\n\t\tprivate readonly payload: Uint8Array,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CallError\";\n\t}\n}\n\n// eslint-disable-next-line max-params\nasync function doCall(\n\tnc: NatsConnection,\n\ttarget: string,\n\tpayload: Uint8Array,\n\tmeta: {\n\t\tcallDepth: number;\n\t\t/**\n\t\t * The otel context\n\t\t */\n\t\tcontext: Context | undefined;\n\t\tcurrentService: string;\n\t\t/**\n\t\t * Headers from the parent calls\n\t\t */\n\t\theader: Record<string, string>;\n\t},\n\toptions?: {\n\t\t/**\n\t\t * @default 5000 ms\n\t\t */\n\t\ttimeout?: number;\n\t\theader?: Record<string, string>;\n\t\t/**\n\t\t * Optionally pass an existing trace from the moleculer framework\n\t\t */\n\t\ttrace?: {\n\t\t\t/**\n\t\t\t * This is the ID of the whole trace forest and is used to uniquely identify a distributed trace through a system.\n\t\t\t */\n\t\t\ttraceId: string | undefined;\n\t\t\t/**\n\t\t\t * or span id: This is the ID of this request as known by the caller\n\t\t\t */\n\t\t\tparentId: string | undefined;\n\t\t};\n\t},\n): Promise<Uint8Array> {\n\tif (meta.callDepth >= 20) {\n\t\tthrow new Error(`max call depth reached: ${meta.callDepth}`);\n\t}\n\n\tconst carrierData: Context | { traceparent?: string } = meta.context ?? {};\n\tif (options?.trace && !meta.context) {\n\t\tconst version = Buffer.alloc(1).toString(\"hex\");\n\t\tconst flags = \"01\"; // means sampled\n\t\tconst header = `${version}-${options.trace.traceId}-${options.trace.parentId}-${flags}`;\n\t\t(carrierData as { traceparent?: string | undefined }).traceparent = header;\n\t}\n\n\tconst callingContext: Context = propagation.extract(\n\t\tcontext.active(),\n\t\tcarrierData,\n\t);\n\tconst tracer = trace.getTracer(\"default\");\n\tconst [service, action] = target.split(\".\");\n\treturn tracer.startActiveSpan(\n\t\t`call: ${target}`,\n\t\t{\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: {\n\t\t\t\t[ATTR_RPC_SERVICE]: service,\n\t\t\t\t[ATTR_RPC_METHOD]: action,\n\t\t\t},\n\t\t},\n\t\tcallingContext,\n\t\tasync (span) => {\n\t\t\t// Add kmicro and otel headers to the nats message headers\n\t\t\tconst natsHeadersMap = headers();\n\t\t\tnatsHeadersMap.set(\"kmc-depth\", (meta.callDepth + 1).toFixed(0));\n\t\t\tpropagation.inject(context.active(), natsHeadersMap, {\n\t\t\t\tset(carrier, key, value) {\n\t\t\t\t\tcarrier.set(key, value);\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst mergedHeaders = { ...meta.header, ...options?.header };\n\t\t\tfor (const key in mergedHeaders) {\n\t\t\t\tif (!Object.hasOwn(mergedHeaders, key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mergedHeaders[key]) {\n\t\t\t\t\tnatsHeadersMap.set(key, mergedHeaders[key]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await nc.request(target, payload, {\n\t\t\t\t\theaders: natsHeadersMap,\n\t\t\t\t\ttimeout: options?.timeout ?? 5000,\n\t\t\t\t});\n\t\t\t\tif (result.headers?.get(\"Nats-Service-Error-Code\")) {\n\t\t\t\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\t\t\t\tspan.recordException(result.headers.get(\"Nats-Service-Error\"));\n\t\t\t\t\tthrow new CallError(\n\t\t\t\t\t\t`received error: ${result.headers.get(\"Nats-Service-Error\")}`,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tspan.setStatus({ code: SpanStatusCode.OK });\n\t\t\t\treturn result.data;\n\t\t\t} finally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t},\n\t);\n}\n"],"mappings":"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","names":["trace","context"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kultify/kmicro-js",
3
- "version": "0.0.19",
3
+ "version": "0.1.3",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -52,17 +52,17 @@
52
52
  "@nats-io/services": "3.1.0",
53
53
  "@nats-io/transport-node": "3.1.0",
54
54
  "@opentelemetry/api": "^1.9.0",
55
+ "@opentelemetry/semantic-conventions": "^1.36.0",
56
+ "pino": "^9.9.0"
57
+ },
58
+ "devDependencies": {
59
+ "@biomejs/biome": "2.2.2",
55
60
  "@opentelemetry/core": "^2.0.1",
56
61
  "@opentelemetry/exporter-trace-otlp-proto": "^0.203.0",
57
62
  "@opentelemetry/instrumentation-pino": "^0.50.0",
58
63
  "@opentelemetry/resources": "^2.0.1",
59
64
  "@opentelemetry/sdk-node": "^0.203.0",
60
65
  "@opentelemetry/sdk-trace-node": "^2.0.1",
61
- "@opentelemetry/semantic-conventions": "^1.36.0",
62
- "pino": "^9.9.0"
63
- },
64
- "devDependencies": {
65
- "@biomejs/biome": "2.2.2",
66
66
  "@testcontainers/nats": "^11.5.1",
67
67
  "@tsconfig/node20": "^20.1.6",
68
68
  "@types/node": "^24.3.0",