@ultrst-armada/krnl 1.0.7 → 1.0.9

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.
@@ -26,35 +26,6 @@ var ServiceStateStore = class {
26
26
  }
27
27
  };
28
28
 
29
- // src/events/ServiceEventBus.ts
30
- var ServiceEventBus = class {
31
- handlers = /* @__PURE__ */ new Map();
32
- on(event, handler) {
33
- if (!this.handlers.has(event)) {
34
- this.handlers.set(event, /* @__PURE__ */ new Set());
35
- }
36
- const set = this.handlers.get(event);
37
- set.add(handler);
38
- return () => {
39
- set.delete(handler);
40
- };
41
- }
42
- emit(event, payload) {
43
- const set = this.handlers.get(event);
44
- if (!set) return;
45
- for (const handler of Array.from(set)) {
46
- try {
47
- handler(payload);
48
- } catch (err) {
49
- console.error(`[ServiceEventBus] Handler error for '${event}':`, err);
50
- }
51
- }
52
- }
53
- clear() {
54
- this.handlers.clear();
55
- }
56
- };
57
-
58
29
  // src/lifecycle/LifecycleManager.ts
59
30
  var TRANSITIONS = {
60
31
  uninitialized: ["initializing"],
@@ -91,6 +62,227 @@ var LifecycleManager = class {
91
62
  }
92
63
  };
93
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
+
94
286
  // src/services/ServiceInstance.ts
95
287
  var ServiceInstance = class {
96
288
  constructor(definition) {
@@ -98,8 +290,8 @@ var ServiceInstance = class {
98
290
  this.id = definition.id;
99
291
  this.name = definition.name;
100
292
  this.version = definition.version;
293
+ this.telemetry = new TelemetryController(this.id);
101
294
  this.lifecycle = new LifecycleManager();
102
- this.eventBus = new ServiceEventBus();
103
295
  if (definition.state) {
104
296
  this.stateStore = new ServiceStateStore(definition.state.initial);
105
297
  }
@@ -108,8 +300,8 @@ var ServiceInstance = class {
108
300
  id;
109
301
  name;
110
302
  version;
303
+ telemetry;
111
304
  stateStore;
112
- eventBus;
113
305
  lifecycle;
114
306
  initialized = false;
115
307
  disposed = false;
@@ -173,7 +365,19 @@ var ServiceInstance = class {
173
365
  if (!operation) {
174
366
  throw new Error("[Service:" + this.name + "] Operation '" + op + "' not found.");
175
367
  }
176
- 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
+ }
177
381
  }
178
382
  getState() {
179
383
  return this.stateStore?.getState() ?? Object.freeze({});
@@ -185,12 +389,6 @@ var ServiceInstance = class {
185
389
  }
186
390
  this.stateStore.setState(mutation);
187
391
  }
188
- on(event, handler) {
189
- return this.eventBus.on(event, handler);
190
- }
191
- emit(event, payload) {
192
- this.eventBus.emit(event, payload);
193
- }
194
392
  };
195
393
 
196
394
  // src/services/ServiceProxy.ts
@@ -211,6 +409,7 @@ var ServiceProxy = class {
211
409
  this.id = definition.id;
212
410
  this.name = definition.name;
213
411
  this.version = definition.version;
412
+ this.telemetry = new TelemetryController(this.id);
214
413
  this.stateCache = { ...definition.state?.initial ?? {} };
215
414
  }
216
415
  definition;
@@ -219,6 +418,7 @@ var ServiceProxy = class {
219
418
  id;
220
419
  name;
221
420
  version;
421
+ telemetry;
222
422
  stateCache;
223
423
  eventHandlers = /* @__PURE__ */ new Map();
224
424
  lifecycle = new LifecycleManager();
@@ -276,11 +476,21 @@ var ServiceProxy = class {
276
476
  payload: input,
277
477
  timestamp: Date.now()
278
478
  };
279
- const response = await this.adapter.send(this.endpoint, envelope);
280
- if (response.error) {
281
- 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;
282
493
  }
283
- return response.payload;
284
494
  }
285
495
  getState() {
286
496
  return Object.freeze({ ...this.stateCache });
@@ -340,12 +550,6 @@ function validateServiceDefinition(definition) {
340
550
  throw new Error("[Service:" + definition.name + "] Operation '" + key + "' must define a handler.");
341
551
  }
342
552
  }
343
- for (const [key, event] of Object.entries(definition.events ?? {})) {
344
- if (!event || typeof event !== "object") {
345
- throw new Error("[Service:" + definition.name + "] Invalid event '" + key + "'.");
346
- }
347
- assertNonEmptyString(event.name, "events." + key + ".name");
348
- }
349
553
  for (const [key, schema] of Object.entries(definition.inputs ?? {})) assertRecord(schema, "inputs." + key);
350
554
  for (const [key, schema] of Object.entries(definition.outputs ?? {})) assertRecord(schema, "outputs." + key);
351
555
  if (definition.state?.schema !== void 0) assertRecord(definition.state.schema, "state.schema");
@@ -378,6 +582,137 @@ function createServiceProxy(definition, adapter, endpoint) {
378
582
  return new ServiceProxy(definition, adapter, endpoint);
379
583
  }
380
584
 
585
+ // src/events/EventBus.ts
586
+ var EventBus = class {
587
+ handlers = /* @__PURE__ */ new Map();
588
+ subscribe(event, handler) {
589
+ let listeners = this.handlers.get(event);
590
+ if (!listeners) {
591
+ listeners = /* @__PURE__ */ new Set();
592
+ this.handlers.set(event, listeners);
593
+ }
594
+ listeners.add(handler);
595
+ return {
596
+ unsubscribe: () => {
597
+ listeners?.delete(handler);
598
+ if (listeners && listeners.size === 0) this.handlers.delete(event);
599
+ }
600
+ };
601
+ }
602
+ on(event, handler) {
603
+ return this.subscribe(event, handler).unsubscribe;
604
+ }
605
+ emit(event, payload) {
606
+ const listeners = this.handlers.get(event);
607
+ if (!listeners) return;
608
+ for (const listener of Array.from(listeners)) {
609
+ try {
610
+ listener(payload);
611
+ } catch (error) {
612
+ console.error(`[EventBus] Handler error for '${event}':`, error);
613
+ }
614
+ }
615
+ }
616
+ clear() {
617
+ this.handlers.clear();
618
+ }
619
+ };
620
+ function createEventChannels(bus, names) {
621
+ const channels = {};
622
+ for (const name of names) {
623
+ channels[name] = {
624
+ name,
625
+ subscribe: (handler) => bus.subscribe(name, handler),
626
+ on: (handler) => bus.on(name, handler)
627
+ };
628
+ }
629
+ return channels;
630
+ }
631
+
632
+ // src/functionalities/FunctionalityFacade.ts
633
+ var FunctionalityFacade = class {
634
+ id;
635
+ name;
636
+ description;
637
+ bubbleEvents;
638
+ definition;
639
+ eventBus;
640
+ events;
641
+ constructor(id2, definition, options = {}) {
642
+ if (!id2 || typeof id2 !== "string") {
643
+ throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
644
+ }
645
+ if (!definition || typeof definition.execute !== "function") {
646
+ throw new Error(`[FunctionalityFacade:${id2}] Functionality must define execute().`);
647
+ }
648
+ this.id = id2;
649
+ this.name = definition.name || id2;
650
+ this.description = definition.description || "";
651
+ this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
652
+ this.definition = definition;
653
+ this.eventBus = new EventBus();
654
+ for (const reserved of ["triggered", "completed", "failed"]) {
655
+ if (definition.events && reserved in definition.events) {
656
+ throw new Error(`[FunctionalityFacade:${id2}] Event '${reserved}' is reserved for functionality lifecycle.`);
657
+ }
658
+ }
659
+ const eventNames = [
660
+ "triggered",
661
+ "completed",
662
+ "failed",
663
+ ...Object.keys(definition.events ?? {})
664
+ ];
665
+ this.events = createEventChannels(this.eventBus, eventNames);
666
+ }
667
+ getEventDefinitions() {
668
+ return {
669
+ triggered: { name: "triggered", description: "Functionality execution started." },
670
+ completed: { name: "completed", description: "Functionality execution completed successfully." },
671
+ failed: { name: "failed", description: "Functionality execution failed." },
672
+ ...this.definition.events ?? {}
673
+ };
674
+ }
675
+ subscribe(event, handler) {
676
+ return this.eventBus.on(event, handler);
677
+ }
678
+ emit(event, payload) {
679
+ this.eventBus.emit(event, payload);
680
+ }
681
+ async execute(input, context) {
682
+ const lifecycle = {
683
+ serviceId: context.serviceId,
684
+ functionalityId: this.id,
685
+ functionalityName: this.name,
686
+ correlationId: context.correlationId,
687
+ timestamp: Date.now(),
688
+ input
689
+ };
690
+ this.emit("triggered", lifecycle);
691
+ try {
692
+ const output = await this.definition.execute(input, {
693
+ ...context,
694
+ emit: (event, payload) => this.emit(event, payload)
695
+ });
696
+ this.emit("completed", {
697
+ ...lifecycle,
698
+ timestamp: Date.now(),
699
+ output
700
+ });
701
+ return output;
702
+ } catch (error) {
703
+ this.emit("failed", {
704
+ ...lifecycle,
705
+ timestamp: Date.now(),
706
+ error: error?.message || String(error)
707
+ });
708
+ throw error;
709
+ }
710
+ }
711
+ clearEventSubscriptions() {
712
+ this.eventBus.clear();
713
+ }
714
+ };
715
+
381
716
  // ../../node_modules/.pnpm/p-queue@10.0.0/node_modules/p-queue/dist/lower-bound.js
382
717
  function lowerBound(array, value, comparator) {
383
718
  let first = 0;
@@ -432,11 +767,11 @@ var PriorityQueue = class {
432
767
  return item.run;
433
768
  }
434
769
  enqueue(run, options) {
435
- const { priority = 0, id } = options ?? {};
770
+ const { priority = 0, id: id2 } = options ?? {};
436
771
  const { size } = this;
437
772
  const element = {
438
773
  priority,
439
- id,
774
+ id: id2,
440
775
  run
441
776
  };
442
777
  if (size === 0) {
@@ -453,16 +788,16 @@ var PriorityQueue = class {
453
788
  const index = lowerBound(this.#queue, element, (a, b) => a.priority === b.priority ? 0 : b.priority - a.priority);
454
789
  this.#queue.splice(index, 0, element);
455
790
  }
456
- setPriority(id, priority) {
457
- const index = this.#findIndex((element) => element.id === id);
791
+ setPriority(id2, priority) {
792
+ const index = this.#findIndex((element) => element.id === id2);
458
793
  if (index === -1) {
459
- 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.`);
460
795
  }
461
796
  if (this.#queue[index].priority === priority) {
462
797
  return;
463
798
  }
464
799
  const [item] = this.#queue.splice(index, 1);
465
- this.enqueue(item.run, { priority, id });
800
+ this.enqueue(item.run, { priority, id: id2 });
466
801
  }
467
802
  remove(idOrRun) {
468
803
  const index = this.#findIndex((element) => (typeof idOrRun === "string" ? element.id : element.run) === idOrRun);
@@ -878,17 +1213,17 @@ var PQueue = class extends EventTarget {
878
1213
  }
879
1214
  }
880
1215
  async #add(function_, options, waitingTask) {
881
- const id = options.id ?? (this.#idAssigner++).toString();
1216
+ const id2 = options.id ?? (this.#idAssigner++).toString();
882
1217
  options = {
883
1218
  timeout: this.#timeout,
884
1219
  ...options,
885
- id
1220
+ id: id2
886
1221
  };
887
1222
  validateTimeout(options.timeout);
888
1223
  if (options.priority !== void 0 && (typeof options.priority !== "number" || Number.isNaN(options.priority))) {
889
1224
  throw new TypeError(`Expected \`priority\` to be a number, got \`${String(options.priority)}\` (${typeof options.priority})`);
890
1225
  }
891
- waitingTask.id = id;
1226
+ waitingTask.id = id2;
892
1227
  waitingTask.priority = options.priority ?? 0;
893
1228
  return new Promise((resolve, reject) => {
894
1229
  if (options.signal?.aborted) {
@@ -905,7 +1240,7 @@ var PQueue = class extends EventTarget {
905
1240
  }
906
1241
  this.#pending++;
907
1242
  const runningTask = {
908
- id,
1243
+ id: id2,
909
1244
  priority: waitingTask.priority,
910
1245
  startTime: Date.now(),
911
1246
  timeout: options.timeout
@@ -972,7 +1307,7 @@ var PQueue = class extends EventTarget {
972
1307
  if (this.#queue instanceof PriorityQueue) {
973
1308
  this.#queue.remove(run);
974
1309
  } else {
975
- this.#queue.remove(id);
1310
+ this.#queue.remove(id2);
976
1311
  }
977
1312
  reject(signal.reason);
978
1313
  this.#processQueue();
@@ -1048,18 +1383,18 @@ var PQueue = class extends EventTarget {
1048
1383
  // '🦀' runs last
1049
1384
  ```
1050
1385
  */
1051
- setPriority(id, priority) {
1386
+ setPriority(id2, priority) {
1052
1387
  if (typeof priority !== "number" || !Number.isFinite(priority)) {
1053
1388
  throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
1054
1389
  }
1055
1390
  for (const waitingTask of this.#waitingTasks) {
1056
- if (waitingTask.id === id) {
1057
- this.#queue.setPriority(id, priority);
1391
+ if (waitingTask.id === id2) {
1392
+ this.#queue.setPriority(id2, priority);
1058
1393
  waitingTask.priority = priority;
1059
1394
  return;
1060
1395
  }
1061
1396
  }
1062
- 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.`);
1063
1398
  }
1064
1399
  /**
1065
1400
  Adds a sync or async task to the queue.
@@ -1402,7 +1737,7 @@ var TimeoutError = class extends DOMException {
1402
1737
  };
1403
1738
 
1404
1739
  // src/orchestration/canonical/KrnlQ.ts
1405
- import { randomUUID } from "crypto";
1740
+ import { randomUUID as randomUUID2 } from "crypto";
1406
1741
 
1407
1742
  // src/orchestration/canonical/model.ts
1408
1743
  function validateOrchestrationDAG(steps) {
@@ -1469,8 +1804,8 @@ function validateOrchestrationDAG(steps) {
1469
1804
  }
1470
1805
  }
1471
1806
  const queue = [];
1472
- for (const [id, deg] of inDegree.entries()) {
1473
- if (deg === 0) queue.push(id);
1807
+ for (const [id2, deg] of inDegree.entries()) {
1808
+ if (deg === 0) queue.push(id2);
1474
1809
  }
1475
1810
  const order = [];
1476
1811
  while (queue.length > 0) {
@@ -1606,7 +1941,7 @@ var KrnlWorkerPool = class {
1606
1941
  // src/orchestration/canonical/KrnlQ.ts
1607
1942
  function generateSecureId(prefix) {
1608
1943
  try {
1609
- return `${prefix}_${randomUUID()}`;
1944
+ return `${prefix}_${randomUUID2()}`;
1610
1945
  } catch {
1611
1946
  return `${prefix}_${Math.random().toString(36).substring(2, 11)}_${Date.now()}`;
1612
1947
  }
@@ -1674,9 +2009,9 @@ var KrnlQueue = class {
1674
2009
  if (this.jobs.size <= this.maxRetainedJobs) return;
1675
2010
  const excess = this.jobs.size - this.maxRetainedJobs;
1676
2011
  let pruned = 0;
1677
- for (const [id, record] of this.jobs.entries()) {
2012
+ for (const [id2, record] of this.jobs.entries()) {
1678
2013
  if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
1679
- this.jobs.delete(id);
2014
+ this.jobs.delete(id2);
1680
2015
  pruned++;
1681
2016
  if (pruned >= excess) break;
1682
2017
  }
@@ -2290,6 +2625,7 @@ var ServiceFacade = class {
2290
2625
  defaultFrontend;
2291
2626
  instance;
2292
2627
  queue;
2628
+ telemetry;
2293
2629
  constructor(config) {
2294
2630
  if (!config || !config.id || typeof config.id !== "string") {
2295
2631
  throw new Error("[ServiceFacade] ServiceFacade requires a valid id.");
@@ -2298,7 +2634,10 @@ var ServiceFacade = class {
2298
2634
  this.name = config.name || config.id;
2299
2635
  this.version = config.version || "1.0.0";
2300
2636
  this.description = config.description || "";
2301
- this.functionalities = config.functionalities ? { ...config.functionalities } : {};
2637
+ this.functionalities = {};
2638
+ for (const [name, functionality] of Object.entries(config.functionalities ?? {})) {
2639
+ this.registerFunctionality(name, functionality);
2640
+ }
2302
2641
  this.functionalityOrchestrations = config.functionalityOrchestrations ? { ...config.functionalityOrchestrations } : config.orchestrations ? { ...config.orchestrations } : {};
2303
2642
  this.libraries = config.libraries ? { ...config.libraries } : {};
2304
2643
  this.dependencies = Object.freeze(config.dependencies ? [...config.dependencies] : []);
@@ -2316,6 +2655,7 @@ var ServiceFacade = class {
2316
2655
  operations: {}
2317
2656
  });
2318
2657
  }
2658
+ this.telemetry = this.instance.telemetry;
2319
2659
  this.queue = new KrnlQueue({
2320
2660
  queueName: `krnl_queue_${this.id}`,
2321
2661
  concurrency: config.concurrency ?? config.queueOptions?.concurrency ?? 10,
@@ -2359,6 +2699,8 @@ var ServiceFacade = class {
2359
2699
  */
2360
2700
  async call(op, input, ctx) {
2361
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);
2362
2704
  const commandId = `cmd_${this.id}_${op}_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
2363
2705
  const command = {
2364
2706
  id: commandId,
@@ -2368,23 +2710,48 @@ var ServiceFacade = class {
2368
2710
  idempotencyKey: ctx?.idempotencyKey,
2369
2711
  createdAt: Date.now()
2370
2712
  };
2371
- const result = await this.queue.executeCommand(command, async (payload, workerCtx) => {
2372
- WorkerExecutionBoundary.assertWorkerContext(workerCtx);
2373
- if (this.functionalities[op] && typeof this.functionalities[op].execute === "function") {
2374
- return await this.functionalities[op].execute(payload, {
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, {
2375
2739
  correlationId: workerCtx.correlationId,
2376
- state: this.instance.getState()
2740
+ idempotencyKey: command.idempotencyKey,
2741
+ metadata: { __krnlTelemetryInternal: true }
2377
2742
  });
2378
- }
2379
- return await this.instance.call(op, payload, {
2380
- correlationId: workerCtx.correlationId,
2381
- idempotencyKey: command.idempotencyKey
2382
2743
  });
2383
- });
2384
- if (result.status === "FAILED") {
2385
- 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;
2386
2754
  }
2387
- return result.data;
2388
2755
  }
2389
2756
  /**
2390
2757
  * External caller callable boundary for functionality orchestration execution.
@@ -2398,6 +2765,18 @@ var ServiceFacade = class {
2398
2765
  );
2399
2766
  }
2400
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
+ );
2401
2780
  const commandId = `cmd_orch_${this.id}_${orchestrationName}_${Date.now()}`;
2402
2781
  const command = {
2403
2782
  id: commandId,
@@ -2407,6 +2786,13 @@ var ServiceFacade = class {
2407
2786
  idempotencyKey: options.idempotencyKey,
2408
2787
  createdAt: Date.now()
2409
2788
  };
2789
+ orch.events.emit("triggered", {
2790
+ serviceId: this.id,
2791
+ orchestrationId: orch.id,
2792
+ orchestrationName: orch.name,
2793
+ correlationId,
2794
+ timestamp: Date.now()
2795
+ });
2410
2796
  const cmdResult = await this.queue.executeCommand(
2411
2797
  command,
2412
2798
  async (payload, workerCtx) => {
@@ -2438,7 +2824,8 @@ var ServiceFacade = class {
2438
2824
  ...s.compensation,
2439
2825
  handler: async (compCtx) => {
2440
2826
  await this.call(s.compensation.target, compCtx.results[s.id], {
2441
- correlationId: compCtx.correlationId
2827
+ correlationId: compCtx.correlationId,
2828
+ metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
2442
2829
  });
2443
2830
  }
2444
2831
  };
@@ -2454,7 +2841,8 @@ var ServiceFacade = class {
2454
2841
  stepPayload.input = stepCtx.results.input;
2455
2842
  }
2456
2843
  return await this.call(s.target, stepPayload, {
2457
- correlationId: stepCtx.correlationId
2844
+ correlationId: stepCtx.correlationId,
2845
+ metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
2458
2846
  });
2459
2847
  }
2460
2848
  };
@@ -2474,7 +2862,8 @@ var ServiceFacade = class {
2474
2862
  const nestedResult = await this.orchestrate(childOrchId, childInput, {
2475
2863
  correlationId: childCtx.correlationId,
2476
2864
  timeoutMs: childOrch.timeoutMs,
2477
- abortSignal: options.abortSignal
2865
+ abortSignal: options.abortSignal,
2866
+ metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
2478
2867
  });
2479
2868
  if (nestedResult.status !== "COMPLETED") {
2480
2869
  throw new Error(nestedResult.error || `Nested orchestration "${childOrchId}" failed.`);
@@ -2496,9 +2885,39 @@ var ServiceFacade = class {
2496
2885
  );
2497
2886
  }
2498
2887
  );
2499
- if (cmdResult.status === "FAILED") {
2500
- throw new Error(cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
2888
+ const orchestrationResult = cmdResult.data;
2889
+ if (cmdResult.status === "COMPLETED" && orchestrationResult) {
2890
+ const lifecycleEvent = orchestrationResult.status === "COMPLETED" ? "completed" : "failed";
2891
+ orch.events.emit(lifecycleEvent, {
2892
+ serviceId: this.id,
2893
+ orchestrationId: orch.id,
2894
+ orchestrationName: orch.name,
2895
+ correlationId,
2896
+ executionId: String(orchestrationResult.executionMetadata.executionId ?? ""),
2897
+ timestamp: Date.now(),
2898
+ status: orchestrationResult.status,
2899
+ output: orchestrationResult.output,
2900
+ error: orchestrationResult.error
2901
+ });
2902
+ } else {
2903
+ orch.events.emit("failed", {
2904
+ serviceId: this.id,
2905
+ orchestrationId: orch.id,
2906
+ orchestrationName: orch.name,
2907
+ correlationId,
2908
+ timestamp: Date.now(),
2909
+ status: cmdResult.status,
2910
+ error: cmdResult.error
2911
+ });
2501
2912
  }
2913
+ if (cmdResult.status === "FAILED" || orchestrationResult?.status === "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;
2918
+ }
2919
+ telemetryHandle.end();
2920
+ serviceTelemetryHandle.end();
2502
2921
  return cmdResult.data;
2503
2922
  }
2504
2923
  /**
@@ -2525,17 +2944,29 @@ var ServiceFacade = class {
2525
2944
  setState(mutation) {
2526
2945
  this.instance.setState(mutation);
2527
2946
  }
2528
- on(event, handler) {
2529
- return this.instance.on(event, handler);
2530
- }
2531
- emit(event, payload) {
2532
- this.instance.emit(event, payload);
2947
+ getFunctionality(name) {
2948
+ const functionality = this.functionalities[name];
2949
+ if (!functionality) {
2950
+ throw new Error(`[ServiceFacade:${this.id}] Functionality "${name}" not found.`);
2951
+ }
2952
+ return functionality;
2533
2953
  }
2534
- registerFunctionality(name, functionality) {
2954
+ registerFunctionality(name, functionality, options = {}) {
2535
2955
  if (!name || typeof name !== "string") {
2536
2956
  throw new Error("[ServiceFacade] Functionality name must be a non-empty string.");
2537
2957
  }
2538
- this.functionalities[name] = functionality;
2958
+ if (functionality instanceof FunctionalityFacade) {
2959
+ this.functionalities[name] = functionality;
2960
+ return this;
2961
+ }
2962
+ if (!functionality || typeof functionality !== "object" || typeof functionality.execute !== "function") {
2963
+ throw new Error(`[ServiceFacade:${this.id}] Functionality "${name}" must define execute().`);
2964
+ }
2965
+ this.functionalities[name] = new FunctionalityFacade(
2966
+ name,
2967
+ functionality,
2968
+ options
2969
+ );
2539
2970
  return this;
2540
2971
  }
2541
2972
  registerFunctionalityOrchestration(name, orchestration) {
@@ -2573,14 +3004,22 @@ var ServiceFacade = class {
2573
3004
  return this.getNamespace();
2574
3005
  }
2575
3006
  getNamespace() {
3007
+ const bubbledFunctionalities = {};
3008
+ for (const [name, functionality] of Object.entries(this.functionalities)) {
3009
+ if (functionality.bubbleEvents) bubbledFunctionalities[name] = functionality;
3010
+ }
3011
+ const bubbledOrchestrations = {};
3012
+ for (const [name, orchestration] of Object.entries(this.functionalityOrchestrations)) {
3013
+ if (orchestration.bubbleEvents) bubbledOrchestrations[name] = orchestration;
3014
+ }
2576
3015
  return {
2577
3016
  serviceId: this.id,
2578
3017
  serviceName: this.name,
2579
3018
  version: this.version,
2580
3019
  description: this.description,
2581
3020
  libraries: { ...this.libraries },
2582
- functionalities: { ...this.functionalities },
2583
- functionalityOrchestrations: { ...this.functionalityOrchestrations },
3021
+ functionalities: bubbledFunctionalities,
3022
+ functionalityOrchestrations: bubbledOrchestrations,
2584
3023
  capabilities: this.capabilities,
2585
3024
  dependencies: this.dependencies
2586
3025
  };
@@ -3137,9 +3576,9 @@ var ServiceRuntime = class {
3137
3576
  // src/discovery/ServiceDiscovery.ts
3138
3577
  var ServiceDiscovery = class {
3139
3578
  peers = /* @__PURE__ */ new Map();
3140
- registerPeer(id, name, endpoints) {
3141
- this.peers.set(id, {
3142
- id,
3579
+ registerPeer(id2, name, endpoints) {
3580
+ this.peers.set(id2, {
3581
+ id: id2,
3143
3582
  name,
3144
3583
  endpoints,
3145
3584
  lastSeen: Date.now()
@@ -3148,8 +3587,8 @@ var ServiceDiscovery = class {
3148
3587
  getPeers() {
3149
3588
  return Array.from(this.peers.values());
3150
3589
  }
3151
- findPeer(id) {
3152
- return this.peers.get(id);
3590
+ findPeer(id2) {
3591
+ return this.peers.get(id2);
3153
3592
  }
3154
3593
  };
3155
3594
 
@@ -3277,6 +3716,34 @@ var KrnlPackageReconciler = class {
3277
3716
  }
3278
3717
  };
3279
3718
 
3719
+ // src/events/ServiceEventBus.ts
3720
+ var ServiceEventBus = class extends EventBus {
3721
+ };
3722
+
3723
+ // src/events/OrchestrationEventFacade.ts
3724
+ var OrchestrationEventFacade = class {
3725
+ eventBus = new EventBus();
3726
+ events;
3727
+ constructor() {
3728
+ this.events = createEventChannels(this.eventBus, ["triggered", "completed", "failed"]);
3729
+ }
3730
+ get triggered() {
3731
+ return this.events.triggered;
3732
+ }
3733
+ get completed() {
3734
+ return this.events.completed;
3735
+ }
3736
+ get failed() {
3737
+ return this.events.failed;
3738
+ }
3739
+ emit(event, payload) {
3740
+ this.eventBus.emit(event, payload);
3741
+ }
3742
+ clear() {
3743
+ this.eventBus.clear();
3744
+ }
3745
+ };
3746
+
3280
3747
  // src/connectivity/ProtocolResolver.ts
3281
3748
  var ProtocolResolver = class {
3282
3749
  static selectProtocol(requiredCapabilities, availableEndpoints) {
@@ -3297,6 +3764,8 @@ var FunctionalityOrchestration = class {
3297
3764
  description;
3298
3765
  timeoutMs;
3299
3766
  scope = "functionality";
3767
+ bubbleEvents;
3768
+ events;
3300
3769
  steps = [];
3301
3770
  flows = /* @__PURE__ */ new Map();
3302
3771
  constructor(descriptor) {
@@ -3308,6 +3777,8 @@ var FunctionalityOrchestration = class {
3308
3777
  this.version = descriptor.version || "1.0.0";
3309
3778
  this.description = descriptor.description || "";
3310
3779
  this.timeoutMs = descriptor.timeoutMs;
3780
+ this.bubbleEvents = descriptor.bubbleEvents ?? true;
3781
+ this.events = new OrchestrationEventFacade();
3311
3782
  }
3312
3783
  /**
3313
3784
  * Adds a sequential functionality step to the DAG.
@@ -3468,6 +3939,7 @@ var FunctionalityOrchestration = class {
3468
3939
  description: this.description,
3469
3940
  timeoutMs: this.timeoutMs,
3470
3941
  scope: "functionality",
3942
+ bubbleEvents: this.bubbleEvents,
3471
3943
  dependencies: [],
3472
3944
  steps: this.steps.map((s) => ({
3473
3945
  id: s.id,
@@ -3571,6 +4043,8 @@ var FunctionalityOrchestration = class {
3571
4043
  // src/index.ts
3572
4044
  import * as gutts from "@dinilmusick/gutts";
3573
4045
  export {
4046
+ EventBus,
4047
+ FunctionalityFacade,
3574
4048
  FunctionalityOrchestration,
3575
4049
  HttpProtocolAdapter,
3576
4050
  KrnlPackageReconciler,
@@ -3578,6 +4052,7 @@ export {
3578
4052
  KrnlWorkerPool,
3579
4053
  LifecycleManager,
3580
4054
  MemoryTransport,
4055
+ OrchestrationEventFacade,
3581
4056
  P2PProtocolAdapter,
3582
4057
  ProtocolResolver,
3583
4058
  ServiceDiscovery,
@@ -3588,14 +4063,19 @@ export {
3588
4063
  ServiceRegistry,
3589
4064
  ServiceRuntime,
3590
4065
  ServiceStateStore,
4066
+ TelemetryController,
3591
4067
  UdpProtocolAdapter,
3592
4068
  WebSocketProtocolAdapter,
3593
4069
  WorkerExecutionBoundary,
4070
+ createEventChannels,
3594
4071
  createService,
3595
4072
  createServiceDefinition,
3596
4073
  createServiceFacade,
3597
4074
  createServiceProxy,
4075
+ deltaResources,
3598
4076
  gutts,
4077
+ sampleResources,
4078
+ telemetryNow,
3599
4079
  validateOrchestrationDAG,
3600
4080
  validateServiceDefinition
3601
4081
  };