@ultrst-armada/krnl 1.0.8 → 1.0.10

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.
@@ -62,6 +62,227 @@ var LifecycleManager = class {
62
62
  }
63
63
  };
64
64
 
65
+ // src/telemetry/TelemetryController.ts
66
+ import { randomUUID } from "crypto";
67
+
68
+ // src/telemetry/TelemetryResources.ts
69
+ var runtimeProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
70
+ var runtimePerformance = typeof globalThis !== "undefined" ? globalThis.performance : void 0;
71
+ function telemetryNow() {
72
+ return runtimePerformance?.now ? runtimePerformance.now() : Date.now();
73
+ }
74
+ function sampleResources() {
75
+ const memory = runtimeProcess?.memoryUsage?.();
76
+ const cpu = runtimeProcess?.cpuUsage?.();
77
+ const eventLoop = runtimePerformance?.eventLoopUtilization?.();
78
+ return {
79
+ cpuUserMicros: cpu?.user,
80
+ cpuSystemMicros: cpu?.system,
81
+ heapUsedBytes: memory?.heapUsed,
82
+ heapTotalBytes: memory?.heapTotal,
83
+ rssBytes: memory?.rss,
84
+ externalBytes: memory?.external,
85
+ arrayBuffersBytes: memory?.arrayBuffers,
86
+ eventLoopUtilization: eventLoop?.utilization,
87
+ scope: memory || cpu || eventLoop ? "process" : "runtime"
88
+ };
89
+ }
90
+ function deltaResources(start, end) {
91
+ const delta = (a, b) => a === void 0 || b === void 0 ? void 0 : b - a;
92
+ return {
93
+ cpuUserMicros: delta(start.cpuUserMicros, end.cpuUserMicros),
94
+ cpuSystemMicros: delta(start.cpuSystemMicros, end.cpuSystemMicros),
95
+ heapUsedBytes: delta(start.heapUsedBytes, end.heapUsedBytes),
96
+ heapTotalBytes: delta(start.heapTotalBytes, end.heapTotalBytes),
97
+ rssBytes: delta(start.rssBytes, end.rssBytes),
98
+ externalBytes: delta(start.externalBytes, end.externalBytes),
99
+ arrayBuffersBytes: delta(start.arrayBuffersBytes, end.arrayBuffersBytes),
100
+ eventLoopUtilization: delta(start.eventLoopUtilization, end.eventLoopUtilization),
101
+ scope: start.scope
102
+ };
103
+ }
104
+
105
+ // src/telemetry/TelemetryController.ts
106
+ var id = (prefix) => `${prefix}_${randomUUID()}`;
107
+ function percentiles(values) {
108
+ if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
109
+ const sorted = [...values].sort((a, b) => a - b);
110
+ const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
111
+ return {
112
+ min: sorted[0],
113
+ mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
114
+ p50: pick(0.5),
115
+ p90: pick(0.9),
116
+ p95: pick(0.95),
117
+ p99: pick(0.99),
118
+ max: sorted[sorted.length - 1]
119
+ };
120
+ }
121
+ var TelemetryController = class {
122
+ constructor(serviceId, options = {}) {
123
+ this.serviceId = serviceId;
124
+ this.mode = options.mode ?? "off";
125
+ this.maxSamples = Math.max(1, options.maxSamples ?? 2048);
126
+ this.maxRecentInvocations = Math.max(1, options.maxRecentInvocations ?? 100);
127
+ }
128
+ serviceId;
129
+ mode;
130
+ maxSamples;
131
+ maxRecentInvocations;
132
+ samples = [];
133
+ active = /* @__PURE__ */ new Map();
134
+ totalInvocationCount = 0;
135
+ totalSuccessCount = 0;
136
+ totalErrorCount = 0;
137
+ lastInvocationAt;
138
+ enable(mode = "standard") {
139
+ this.mode = mode;
140
+ }
141
+ disable() {
142
+ this.mode = "off";
143
+ this.active.clear();
144
+ }
145
+ setMode(mode) {
146
+ this.mode = mode;
147
+ if (mode === "off") this.active.clear();
148
+ }
149
+ getMode() {
150
+ return this.mode;
151
+ }
152
+ status() {
153
+ return {
154
+ enabled: this.mode !== "off",
155
+ mode: this.mode,
156
+ serviceId: this.serviceId,
157
+ invocationCount: this.totalInvocationCount,
158
+ activeInvocations: this.active.size,
159
+ lastInvocationAt: this.lastInvocationAt
160
+ };
161
+ }
162
+ begin(target, kind, correlationId, parentSpanId) {
163
+ if (this.mode === "off") {
164
+ return {
165
+ invocationId: "",
166
+ traceId: "",
167
+ spanId: "",
168
+ parentSpanId,
169
+ end: () => void 0
170
+ };
171
+ }
172
+ const invocationId = id("inv");
173
+ const spanId = id("span");
174
+ const traceId = parentSpanId ? this.findTraceId(parentSpanId) ?? id("trace") : id("trace");
175
+ const active = {
176
+ invocationId,
177
+ traceId,
178
+ spanId,
179
+ parentSpanId,
180
+ serviceId: this.serviceId,
181
+ target,
182
+ kind,
183
+ correlationId,
184
+ startedAt: telemetryNow(),
185
+ resourcesStart: this.mode === "standard" ? void 0 : sampleResources()
186
+ };
187
+ this.active.set(invocationId, active);
188
+ return {
189
+ invocationId,
190
+ traceId,
191
+ spanId,
192
+ parentSpanId,
193
+ end: (error) => this.finish(active, error)
194
+ };
195
+ }
196
+ reset() {
197
+ this.samples.length = 0;
198
+ this.active.clear();
199
+ this.totalInvocationCount = 0;
200
+ this.totalSuccessCount = 0;
201
+ this.totalErrorCount = 0;
202
+ this.lastInvocationAt = void 0;
203
+ }
204
+ snapshot() {
205
+ const invocations = this.samples.slice();
206
+ const durations = invocations.map((item) => item.durationMs);
207
+ const targetMap = /* @__PURE__ */ new Map();
208
+ for (const invocation of invocations) {
209
+ const key = `${invocation.kind}:${invocation.target}`;
210
+ const group = targetMap.get(key) ?? [];
211
+ group.push(invocation);
212
+ targetMap.set(key, group);
213
+ }
214
+ const targets = [...targetMap.values()].map((group) => ({
215
+ target: group[0].target,
216
+ kind: group[0].kind,
217
+ count: group.length,
218
+ successCount: group.filter((item) => item.status === "completed").length,
219
+ errorCount: group.filter((item) => item.status === "failed").length,
220
+ durationMs: percentiles(group.map((item) => item.durationMs)),
221
+ lastInvocationAt: group[group.length - 1]?.completedAt
222
+ }));
223
+ return {
224
+ serviceId: this.serviceId,
225
+ mode: this.mode,
226
+ capturedAt: Date.now(),
227
+ status: this.status(),
228
+ totals: {
229
+ invocationCount: this.totalInvocationCount,
230
+ successCount: this.totalSuccessCount,
231
+ errorCount: this.totalErrorCount,
232
+ durationMs: percentiles(durations)
233
+ },
234
+ targets,
235
+ activeInvocations: this.active.size,
236
+ recentInvocations: invocations.slice(-this.maxRecentInvocations)
237
+ };
238
+ }
239
+ functionality(name) {
240
+ return this.snapshot().targets.find((target) => target.kind === "functionality" && target.target === name);
241
+ }
242
+ functionalities() {
243
+ return this.snapshot().targets.filter((target) => target.kind === "functionality");
244
+ }
245
+ findTraceId(parentSpanId) {
246
+ for (let index = this.samples.length - 1; index >= 0; index -= 1) {
247
+ if (this.samples[index].spanId === parentSpanId) return this.samples[index].traceId;
248
+ }
249
+ for (const active of this.active.values()) {
250
+ if (active.spanId === parentSpanId) return active.traceId;
251
+ }
252
+ return void 0;
253
+ }
254
+ finish(active, error) {
255
+ if (!this.active.delete(active.invocationId)) return;
256
+ const completedAt = telemetryNow();
257
+ const resourcesEnd = this.mode === "standard" ? void 0 : sampleResources();
258
+ const invocation = {
259
+ invocationId: active.invocationId,
260
+ traceId: active.traceId,
261
+ spanId: active.spanId,
262
+ parentSpanId: active.parentSpanId,
263
+ serviceId: active.serviceId,
264
+ target: active.target,
265
+ kind: active.kind,
266
+ correlationId: active.correlationId,
267
+ startedAt: active.startedAt,
268
+ completedAt,
269
+ durationMs: Math.max(0, completedAt - active.startedAt),
270
+ status: error === void 0 ? "completed" : "failed",
271
+ error: error === void 0 ? void 0 : {
272
+ name: error instanceof Error ? error.name : "Error",
273
+ message: error instanceof Error ? error.message : String(error)
274
+ },
275
+ resources: active.resourcesStart && resourcesEnd ? { start: active.resourcesStart, end: resourcesEnd, delta: deltaResources(active.resourcesStart, resourcesEnd) } : void 0
276
+ };
277
+ this.samples.push(invocation);
278
+ this.totalInvocationCount += 1;
279
+ if (invocation.status === "completed") this.totalSuccessCount += 1;
280
+ else this.totalErrorCount += 1;
281
+ if (this.samples.length > this.maxSamples) this.samples.splice(0, this.samples.length - this.maxSamples);
282
+ this.lastInvocationAt = Date.now();
283
+ }
284
+ };
285
+
65
286
  // src/services/ServiceInstance.ts
66
287
  var ServiceInstance = class {
67
288
  constructor(definition) {
@@ -69,6 +290,7 @@ var ServiceInstance = class {
69
290
  this.id = definition.id;
70
291
  this.name = definition.name;
71
292
  this.version = definition.version;
293
+ this.telemetry = new TelemetryController(this.id);
72
294
  this.lifecycle = new LifecycleManager();
73
295
  if (definition.state) {
74
296
  this.stateStore = new ServiceStateStore(definition.state.initial);
@@ -78,6 +300,7 @@ var ServiceInstance = class {
78
300
  id;
79
301
  name;
80
302
  version;
303
+ telemetry;
81
304
  stateStore;
82
305
  lifecycle;
83
306
  initialized = false;
@@ -142,7 +365,19 @@ var ServiceInstance = class {
142
365
  if (!operation) {
143
366
  throw new Error("[Service:" + this.name + "] Operation '" + op + "' not found.");
144
367
  }
145
- return await operation.handler(input, ctx);
368
+ if (ctx.metadata?.__krnlTelemetryInternal === true) {
369
+ return await operation.handler(input, ctx);
370
+ }
371
+ const parentSpanId = typeof ctx.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
372
+ const handle = this.telemetry.begin(op, "service", ctx.correlationId, parentSpanId);
373
+ try {
374
+ const output = await operation.handler(input, ctx);
375
+ handle.end();
376
+ return output;
377
+ } catch (error) {
378
+ handle.end(error);
379
+ throw error;
380
+ }
146
381
  }
147
382
  getState() {
148
383
  return this.stateStore?.getState() ?? Object.freeze({});
@@ -174,6 +409,7 @@ var ServiceProxy = class {
174
409
  this.id = definition.id;
175
410
  this.name = definition.name;
176
411
  this.version = definition.version;
412
+ this.telemetry = new TelemetryController(this.id);
177
413
  this.stateCache = { ...definition.state?.initial ?? {} };
178
414
  }
179
415
  definition;
@@ -182,6 +418,7 @@ var ServiceProxy = class {
182
418
  id;
183
419
  name;
184
420
  version;
421
+ telemetry;
185
422
  stateCache;
186
423
  eventHandlers = /* @__PURE__ */ new Map();
187
424
  lifecycle = new LifecycleManager();
@@ -239,11 +476,21 @@ var ServiceProxy = class {
239
476
  payload: input,
240
477
  timestamp: Date.now()
241
478
  };
242
- const response = await this.adapter.send(this.endpoint, envelope);
243
- if (response.error) {
244
- throw new Error("[ServiceProxy:" + this.name + "] Remote error: " + response.error);
479
+ const parentSpanId = typeof ctx.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
480
+ const handle = this.telemetry.begin(op, "service", ctx.correlationId, parentSpanId);
481
+ try {
482
+ const response = await this.adapter.send(this.endpoint, envelope);
483
+ if (response.error) {
484
+ const error = new Error("[ServiceProxy:" + this.name + "] Remote error: " + response.error);
485
+ handle.end(error);
486
+ throw error;
487
+ }
488
+ handle.end();
489
+ return response.payload;
490
+ } catch (error) {
491
+ handle.end(error);
492
+ throw error;
245
493
  }
246
- return response.payload;
247
494
  }
248
495
  getState() {
249
496
  return Object.freeze({ ...this.stateCache });
@@ -391,22 +638,22 @@ var FunctionalityFacade = class {
391
638
  definition;
392
639
  eventBus;
393
640
  events;
394
- constructor(id, definition, options = {}) {
395
- if (!id || typeof id !== "string") {
641
+ constructor(id2, definition, options = {}) {
642
+ if (!id2 || typeof id2 !== "string") {
396
643
  throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
397
644
  }
398
645
  if (!definition || typeof definition.execute !== "function") {
399
- throw new Error(`[FunctionalityFacade:${id}] Functionality must define execute().`);
646
+ throw new Error(`[FunctionalityFacade:${id2}] Functionality must define execute().`);
400
647
  }
401
- this.id = id;
402
- this.name = definition.name || id;
648
+ this.id = id2;
649
+ this.name = definition.name || id2;
403
650
  this.description = definition.description || "";
404
651
  this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
405
652
  this.definition = definition;
406
653
  this.eventBus = new EventBus();
407
654
  for (const reserved of ["triggered", "completed", "failed"]) {
408
655
  if (definition.events && reserved in definition.events) {
409
- throw new Error(`[FunctionalityFacade:${id}] Event '${reserved}' is reserved for functionality lifecycle.`);
656
+ throw new Error(`[FunctionalityFacade:${id2}] Event '${reserved}' is reserved for functionality lifecycle.`);
410
657
  }
411
658
  }
412
659
  const eventNames = [
@@ -520,11 +767,11 @@ var PriorityQueue = class {
520
767
  return item.run;
521
768
  }
522
769
  enqueue(run, options) {
523
- const { priority = 0, id } = options ?? {};
770
+ const { priority = 0, id: id2 } = options ?? {};
524
771
  const { size } = this;
525
772
  const element = {
526
773
  priority,
527
- id,
774
+ id: id2,
528
775
  run
529
776
  };
530
777
  if (size === 0) {
@@ -541,16 +788,16 @@ var PriorityQueue = class {
541
788
  const index = lowerBound(this.#queue, element, (a, b) => a.priority === b.priority ? 0 : b.priority - a.priority);
542
789
  this.#queue.splice(index, 0, element);
543
790
  }
544
- setPriority(id, priority) {
545
- const index = this.#findIndex((element) => element.id === id);
791
+ setPriority(id2, priority) {
792
+ const index = this.#findIndex((element) => element.id === id2);
546
793
  if (index === -1) {
547
- throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
794
+ throw new ReferenceError(`No promise function with the id "${id2}" exists in the queue.`);
548
795
  }
549
796
  if (this.#queue[index].priority === priority) {
550
797
  return;
551
798
  }
552
799
  const [item] = this.#queue.splice(index, 1);
553
- this.enqueue(item.run, { priority, id });
800
+ this.enqueue(item.run, { priority, id: id2 });
554
801
  }
555
802
  remove(idOrRun) {
556
803
  const index = this.#findIndex((element) => (typeof idOrRun === "string" ? element.id : element.run) === idOrRun);
@@ -966,17 +1213,17 @@ var PQueue = class extends EventTarget {
966
1213
  }
967
1214
  }
968
1215
  async #add(function_, options, waitingTask) {
969
- const id = options.id ?? (this.#idAssigner++).toString();
1216
+ const id2 = options.id ?? (this.#idAssigner++).toString();
970
1217
  options = {
971
1218
  timeout: this.#timeout,
972
1219
  ...options,
973
- id
1220
+ id: id2
974
1221
  };
975
1222
  validateTimeout(options.timeout);
976
1223
  if (options.priority !== void 0 && (typeof options.priority !== "number" || Number.isNaN(options.priority))) {
977
1224
  throw new TypeError(`Expected \`priority\` to be a number, got \`${String(options.priority)}\` (${typeof options.priority})`);
978
1225
  }
979
- waitingTask.id = id;
1226
+ waitingTask.id = id2;
980
1227
  waitingTask.priority = options.priority ?? 0;
981
1228
  return new Promise((resolve, reject) => {
982
1229
  if (options.signal?.aborted) {
@@ -993,7 +1240,7 @@ var PQueue = class extends EventTarget {
993
1240
  }
994
1241
  this.#pending++;
995
1242
  const runningTask = {
996
- id,
1243
+ id: id2,
997
1244
  priority: waitingTask.priority,
998
1245
  startTime: Date.now(),
999
1246
  timeout: options.timeout
@@ -1060,7 +1307,7 @@ var PQueue = class extends EventTarget {
1060
1307
  if (this.#queue instanceof PriorityQueue) {
1061
1308
  this.#queue.remove(run);
1062
1309
  } else {
1063
- this.#queue.remove(id);
1310
+ this.#queue.remove(id2);
1064
1311
  }
1065
1312
  reject(signal.reason);
1066
1313
  this.#processQueue();
@@ -1136,18 +1383,18 @@ var PQueue = class extends EventTarget {
1136
1383
  // '🦀' runs last
1137
1384
  ```
1138
1385
  */
1139
- setPriority(id, priority) {
1386
+ setPriority(id2, priority) {
1140
1387
  if (typeof priority !== "number" || !Number.isFinite(priority)) {
1141
1388
  throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
1142
1389
  }
1143
1390
  for (const waitingTask of this.#waitingTasks) {
1144
- if (waitingTask.id === id) {
1145
- this.#queue.setPriority(id, priority);
1391
+ if (waitingTask.id === id2) {
1392
+ this.#queue.setPriority(id2, priority);
1146
1393
  waitingTask.priority = priority;
1147
1394
  return;
1148
1395
  }
1149
1396
  }
1150
- throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
1397
+ throw new ReferenceError(`No promise function with the id "${id2}" exists in the queue.`);
1151
1398
  }
1152
1399
  /**
1153
1400
  Adds a sync or async task to the queue.
@@ -1490,7 +1737,7 @@ var TimeoutError = class extends DOMException {
1490
1737
  };
1491
1738
 
1492
1739
  // src/orchestration/canonical/KrnlQ.ts
1493
- import { randomUUID } from "crypto";
1740
+ import { randomUUID as randomUUID2 } from "crypto";
1494
1741
 
1495
1742
  // src/orchestration/canonical/model.ts
1496
1743
  function validateOrchestrationDAG(steps) {
@@ -1557,8 +1804,8 @@ function validateOrchestrationDAG(steps) {
1557
1804
  }
1558
1805
  }
1559
1806
  const queue = [];
1560
- for (const [id, deg] of inDegree.entries()) {
1561
- if (deg === 0) queue.push(id);
1807
+ for (const [id2, deg] of inDegree.entries()) {
1808
+ if (deg === 0) queue.push(id2);
1562
1809
  }
1563
1810
  const order = [];
1564
1811
  while (queue.length > 0) {
@@ -1694,7 +1941,7 @@ var KrnlWorkerPool = class {
1694
1941
  // src/orchestration/canonical/KrnlQ.ts
1695
1942
  function generateSecureId(prefix) {
1696
1943
  try {
1697
- return `${prefix}_${randomUUID()}`;
1944
+ return `${prefix}_${randomUUID2()}`;
1698
1945
  } catch {
1699
1946
  return `${prefix}_${Math.random().toString(36).substring(2, 11)}_${Date.now()}`;
1700
1947
  }
@@ -1762,9 +2009,9 @@ var KrnlQueue = class {
1762
2009
  if (this.jobs.size <= this.maxRetainedJobs) return;
1763
2010
  const excess = this.jobs.size - this.maxRetainedJobs;
1764
2011
  let pruned = 0;
1765
- for (const [id, record] of this.jobs.entries()) {
2012
+ for (const [id2, record] of this.jobs.entries()) {
1766
2013
  if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
1767
- this.jobs.delete(id);
2014
+ this.jobs.delete(id2);
1768
2015
  pruned++;
1769
2016
  if (pruned >= excess) break;
1770
2017
  }
@@ -2378,6 +2625,7 @@ var ServiceFacade = class {
2378
2625
  defaultFrontend;
2379
2626
  instance;
2380
2627
  queue;
2628
+ telemetry;
2381
2629
  constructor(config) {
2382
2630
  if (!config || !config.id || typeof config.id !== "string") {
2383
2631
  throw new Error("[ServiceFacade] ServiceFacade requires a valid id.");
@@ -2407,6 +2655,7 @@ var ServiceFacade = class {
2407
2655
  operations: {}
2408
2656
  });
2409
2657
  }
2658
+ this.telemetry = this.instance.telemetry;
2410
2659
  this.queue = new KrnlQueue({
2411
2660
  queueName: `krnl_queue_${this.id}`,
2412
2661
  concurrency: config.concurrency ?? config.queueOptions?.concurrency ?? 10,
@@ -2450,6 +2699,8 @@ var ServiceFacade = class {
2450
2699
  */
2451
2700
  async call(op, input, ctx) {
2452
2701
  const correlationId = ctx?.correlationId || `corr_${Math.random().toString(36).substring(2, 11)}`;
2702
+ const telemetryParent = typeof ctx?.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
2703
+ const telemetryHandle = this.telemetry.begin(op, "service", correlationId, telemetryParent);
2453
2704
  const commandId = `cmd_${this.id}_${op}_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
2454
2705
  const command = {
2455
2706
  id: commandId,
@@ -2459,26 +2710,48 @@ var ServiceFacade = class {
2459
2710
  idempotencyKey: ctx?.idempotencyKey,
2460
2711
  createdAt: Date.now()
2461
2712
  };
2462
- const result = await this.queue.executeCommand(command, async (payload, workerCtx) => {
2463
- WorkerExecutionBoundary.assertWorkerContext(workerCtx);
2464
- const functionality = this.functionalities[op];
2465
- if (functionality) {
2466
- return await functionality.execute(payload, {
2467
- serviceId: this.id,
2468
- functionalityId: functionality.id,
2713
+ try {
2714
+ const result = await this.queue.executeCommand(command, async (payload, workerCtx) => {
2715
+ WorkerExecutionBoundary.assertWorkerContext(workerCtx);
2716
+ const functionality = this.functionalities[op];
2717
+ if (functionality) {
2718
+ const functionalityTelemetry = this.telemetry.begin(
2719
+ functionality.name,
2720
+ "functionality",
2721
+ workerCtx.correlationId,
2722
+ telemetryHandle.spanId
2723
+ );
2724
+ try {
2725
+ return await functionality.execute(payload, {
2726
+ serviceId: this.id,
2727
+ functionalityId: functionality.id,
2728
+ correlationId: workerCtx.correlationId,
2729
+ state: this.instance.getState()
2730
+ });
2731
+ } catch (error) {
2732
+ functionalityTelemetry.end(error);
2733
+ throw error;
2734
+ } finally {
2735
+ functionalityTelemetry.end();
2736
+ }
2737
+ }
2738
+ return await this.instance.call(op, payload, {
2469
2739
  correlationId: workerCtx.correlationId,
2470
- state: this.instance.getState()
2740
+ idempotencyKey: command.idempotencyKey,
2741
+ metadata: { __krnlTelemetryInternal: true }
2471
2742
  });
2472
- }
2473
- return await this.instance.call(op, payload, {
2474
- correlationId: workerCtx.correlationId,
2475
- idempotencyKey: command.idempotencyKey
2476
2743
  });
2477
- });
2478
- if (result.status === "FAILED") {
2479
- throw new Error(result.error || `[ServiceFacade:${this.id}] Operation '${op}' execution failed.`);
2744
+ if (result.status === "FAILED") {
2745
+ const error = new Error(result.error || `[ServiceFacade:${this.id}] Operation '${op}' execution failed.`);
2746
+ telemetryHandle.end(error);
2747
+ throw error;
2748
+ }
2749
+ telemetryHandle.end();
2750
+ return result.data;
2751
+ } catch (error) {
2752
+ telemetryHandle.end(error);
2753
+ throw error;
2480
2754
  }
2481
- return result.data;
2482
2755
  }
2483
2756
  /**
2484
2757
  * External caller callable boundary for functionality orchestration execution.
@@ -2492,6 +2765,18 @@ var ServiceFacade = class {
2492
2765
  );
2493
2766
  }
2494
2767
  const correlationId = options.correlationId || `corr_${Math.random().toString(36).substring(2, 11)}`;
2768
+ const serviceTelemetryHandle = this.telemetry.begin(
2769
+ `orchestrate:${orchestrationName}`,
2770
+ "service",
2771
+ correlationId,
2772
+ typeof options.metadata?.__krnlTelemetryParentSpanId === "string" ? options.metadata.__krnlTelemetryParentSpanId : void 0
2773
+ );
2774
+ const telemetryHandle = this.telemetry.begin(
2775
+ orchestrationName,
2776
+ "orchestration",
2777
+ correlationId,
2778
+ serviceTelemetryHandle.spanId
2779
+ );
2495
2780
  const commandId = `cmd_orch_${this.id}_${orchestrationName}_${Date.now()}`;
2496
2781
  const command = {
2497
2782
  id: commandId,
@@ -2539,7 +2824,8 @@ var ServiceFacade = class {
2539
2824
  ...s.compensation,
2540
2825
  handler: async (compCtx) => {
2541
2826
  await this.call(s.compensation.target, compCtx.results[s.id], {
2542
- correlationId: compCtx.correlationId
2827
+ correlationId: compCtx.correlationId,
2828
+ metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
2543
2829
  });
2544
2830
  }
2545
2831
  };
@@ -2555,7 +2841,8 @@ var ServiceFacade = class {
2555
2841
  stepPayload.input = stepCtx.results.input;
2556
2842
  }
2557
2843
  return await this.call(s.target, stepPayload, {
2558
- correlationId: stepCtx.correlationId
2844
+ correlationId: stepCtx.correlationId,
2845
+ metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
2559
2846
  });
2560
2847
  }
2561
2848
  };
@@ -2575,7 +2862,8 @@ var ServiceFacade = class {
2575
2862
  const nestedResult = await this.orchestrate(childOrchId, childInput, {
2576
2863
  correlationId: childCtx.correlationId,
2577
2864
  timeoutMs: childOrch.timeoutMs,
2578
- abortSignal: options.abortSignal
2865
+ abortSignal: options.abortSignal,
2866
+ metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
2579
2867
  });
2580
2868
  if (nestedResult.status !== "COMPLETED") {
2581
2869
  throw new Error(nestedResult.error || `Nested orchestration "${childOrchId}" failed.`);
@@ -2623,8 +2911,13 @@ var ServiceFacade = class {
2623
2911
  });
2624
2912
  }
2625
2913
  if (cmdResult.status === "FAILED" || orchestrationResult?.status === "FAILED") {
2626
- throw new Error(orchestrationResult?.error || cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
2914
+ const error = new Error(orchestrationResult?.error || cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
2915
+ telemetryHandle.end(error);
2916
+ serviceTelemetryHandle.end(error);
2917
+ throw error;
2627
2918
  }
2919
+ telemetryHandle.end();
2920
+ serviceTelemetryHandle.end();
2628
2921
  return cmdResult.data;
2629
2922
  }
2630
2923
  /**
@@ -3283,9 +3576,9 @@ var ServiceRuntime = class {
3283
3576
  // src/discovery/ServiceDiscovery.ts
3284
3577
  var ServiceDiscovery = class {
3285
3578
  peers = /* @__PURE__ */ new Map();
3286
- registerPeer(id, name, endpoints) {
3287
- this.peers.set(id, {
3288
- id,
3579
+ registerPeer(id2, name, endpoints) {
3580
+ this.peers.set(id2, {
3581
+ id: id2,
3289
3582
  name,
3290
3583
  endpoints,
3291
3584
  lastSeen: Date.now()
@@ -3294,8 +3587,8 @@ var ServiceDiscovery = class {
3294
3587
  getPeers() {
3295
3588
  return Array.from(this.peers.values());
3296
3589
  }
3297
- findPeer(id) {
3298
- return this.peers.get(id);
3590
+ findPeer(id2) {
3591
+ return this.peers.get(id2);
3299
3592
  }
3300
3593
  };
3301
3594
 
@@ -3749,7 +4042,30 @@ var FunctionalityOrchestration = class {
3749
4042
 
3750
4043
  // src/index.ts
3751
4044
  import * as gutts from "@dinilmusick/gutts";
4045
+
4046
+ // src/execution/execution-controller.ts
4047
+ var DefaultExecutionController = class {
4048
+ providers = /* @__PURE__ */ new Map();
4049
+ executions = /* @__PURE__ */ new Map();
4050
+ register(provider) {
4051
+ this.providers.set(provider.id, provider);
4052
+ }
4053
+ async execute(request, providerId) {
4054
+ const provider = providerId ? this.providers.get(providerId) : this.providers.values().next().value;
4055
+ if (!provider) throw new Error("No execution provider is registered.");
4056
+ const result = await provider.execute(request);
4057
+ this.executions.set(result.executionId, provider);
4058
+ return result;
4059
+ }
4060
+ async cancel(executionId) {
4061
+ const provider = this.executions.get(executionId);
4062
+ if (!provider) throw new Error(`Unknown execution: ${executionId}`);
4063
+ await provider.cancel(executionId);
4064
+ this.executions.delete(executionId);
4065
+ }
4066
+ };
3752
4067
  export {
4068
+ DefaultExecutionController,
3753
4069
  EventBus,
3754
4070
  FunctionalityFacade,
3755
4071
  FunctionalityOrchestration,
@@ -3770,6 +4086,7 @@ export {
3770
4086
  ServiceRegistry,
3771
4087
  ServiceRuntime,
3772
4088
  ServiceStateStore,
4089
+ TelemetryController,
3773
4090
  UdpProtocolAdapter,
3774
4091
  WebSocketProtocolAdapter,
3775
4092
  WorkerExecutionBoundary,
@@ -3778,7 +4095,10 @@ export {
3778
4095
  createServiceDefinition,
3779
4096
  createServiceFacade,
3780
4097
  createServiceProxy,
4098
+ deltaResources,
3781
4099
  gutts,
4100
+ sampleResources,
4101
+ telemetryNow,
3782
4102
  validateOrchestrationDAG,
3783
4103
  validateServiceDefinition
3784
4104
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultrst-armada/krnl-core",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Core runtime engine, Service facades, Protocols, Transports, and Execution flows for Krnl backend services",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",