@ultrst-armada/krnl 1.0.6 → 1.0.8

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"],
@@ -99,7 +70,6 @@ var ServiceInstance = class {
99
70
  this.name = definition.name;
100
71
  this.version = definition.version;
101
72
  this.lifecycle = new LifecycleManager();
102
- this.eventBus = new ServiceEventBus();
103
73
  if (definition.state) {
104
74
  this.stateStore = new ServiceStateStore(definition.state.initial);
105
75
  }
@@ -109,7 +79,6 @@ var ServiceInstance = class {
109
79
  name;
110
80
  version;
111
81
  stateStore;
112
- eventBus;
113
82
  lifecycle;
114
83
  initialized = false;
115
84
  disposed = false;
@@ -185,12 +154,6 @@ var ServiceInstance = class {
185
154
  }
186
155
  this.stateStore.setState(mutation);
187
156
  }
188
- on(event, handler) {
189
- return this.eventBus.on(event, handler);
190
- }
191
- emit(event, payload) {
192
- this.eventBus.emit(event, payload);
193
- }
194
157
  };
195
158
 
196
159
  // src/services/ServiceProxy.ts
@@ -340,12 +303,6 @@ function validateServiceDefinition(definition) {
340
303
  throw new Error("[Service:" + definition.name + "] Operation '" + key + "' must define a handler.");
341
304
  }
342
305
  }
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
306
  for (const [key, schema] of Object.entries(definition.inputs ?? {})) assertRecord(schema, "inputs." + key);
350
307
  for (const [key, schema] of Object.entries(definition.outputs ?? {})) assertRecord(schema, "outputs." + key);
351
308
  if (definition.state?.schema !== void 0) assertRecord(definition.state.schema, "state.schema");
@@ -378,6 +335,137 @@ function createServiceProxy(definition, adapter, endpoint) {
378
335
  return new ServiceProxy(definition, adapter, endpoint);
379
336
  }
380
337
 
338
+ // src/events/EventBus.ts
339
+ var EventBus = class {
340
+ handlers = /* @__PURE__ */ new Map();
341
+ subscribe(event, handler) {
342
+ let listeners = this.handlers.get(event);
343
+ if (!listeners) {
344
+ listeners = /* @__PURE__ */ new Set();
345
+ this.handlers.set(event, listeners);
346
+ }
347
+ listeners.add(handler);
348
+ return {
349
+ unsubscribe: () => {
350
+ listeners?.delete(handler);
351
+ if (listeners && listeners.size === 0) this.handlers.delete(event);
352
+ }
353
+ };
354
+ }
355
+ on(event, handler) {
356
+ return this.subscribe(event, handler).unsubscribe;
357
+ }
358
+ emit(event, payload) {
359
+ const listeners = this.handlers.get(event);
360
+ if (!listeners) return;
361
+ for (const listener of Array.from(listeners)) {
362
+ try {
363
+ listener(payload);
364
+ } catch (error) {
365
+ console.error(`[EventBus] Handler error for '${event}':`, error);
366
+ }
367
+ }
368
+ }
369
+ clear() {
370
+ this.handlers.clear();
371
+ }
372
+ };
373
+ function createEventChannels(bus, names) {
374
+ const channels = {};
375
+ for (const name of names) {
376
+ channels[name] = {
377
+ name,
378
+ subscribe: (handler) => bus.subscribe(name, handler),
379
+ on: (handler) => bus.on(name, handler)
380
+ };
381
+ }
382
+ return channels;
383
+ }
384
+
385
+ // src/functionalities/FunctionalityFacade.ts
386
+ var FunctionalityFacade = class {
387
+ id;
388
+ name;
389
+ description;
390
+ bubbleEvents;
391
+ definition;
392
+ eventBus;
393
+ events;
394
+ constructor(id, definition, options = {}) {
395
+ if (!id || typeof id !== "string") {
396
+ throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
397
+ }
398
+ if (!definition || typeof definition.execute !== "function") {
399
+ throw new Error(`[FunctionalityFacade:${id}] Functionality must define execute().`);
400
+ }
401
+ this.id = id;
402
+ this.name = definition.name || id;
403
+ this.description = definition.description || "";
404
+ this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
405
+ this.definition = definition;
406
+ this.eventBus = new EventBus();
407
+ for (const reserved of ["triggered", "completed", "failed"]) {
408
+ if (definition.events && reserved in definition.events) {
409
+ throw new Error(`[FunctionalityFacade:${id}] Event '${reserved}' is reserved for functionality lifecycle.`);
410
+ }
411
+ }
412
+ const eventNames = [
413
+ "triggered",
414
+ "completed",
415
+ "failed",
416
+ ...Object.keys(definition.events ?? {})
417
+ ];
418
+ this.events = createEventChannels(this.eventBus, eventNames);
419
+ }
420
+ getEventDefinitions() {
421
+ return {
422
+ triggered: { name: "triggered", description: "Functionality execution started." },
423
+ completed: { name: "completed", description: "Functionality execution completed successfully." },
424
+ failed: { name: "failed", description: "Functionality execution failed." },
425
+ ...this.definition.events ?? {}
426
+ };
427
+ }
428
+ subscribe(event, handler) {
429
+ return this.eventBus.on(event, handler);
430
+ }
431
+ emit(event, payload) {
432
+ this.eventBus.emit(event, payload);
433
+ }
434
+ async execute(input, context) {
435
+ const lifecycle = {
436
+ serviceId: context.serviceId,
437
+ functionalityId: this.id,
438
+ functionalityName: this.name,
439
+ correlationId: context.correlationId,
440
+ timestamp: Date.now(),
441
+ input
442
+ };
443
+ this.emit("triggered", lifecycle);
444
+ try {
445
+ const output = await this.definition.execute(input, {
446
+ ...context,
447
+ emit: (event, payload) => this.emit(event, payload)
448
+ });
449
+ this.emit("completed", {
450
+ ...lifecycle,
451
+ timestamp: Date.now(),
452
+ output
453
+ });
454
+ return output;
455
+ } catch (error) {
456
+ this.emit("failed", {
457
+ ...lifecycle,
458
+ timestamp: Date.now(),
459
+ error: error?.message || String(error)
460
+ });
461
+ throw error;
462
+ }
463
+ }
464
+ clearEventSubscriptions() {
465
+ this.eventBus.clear();
466
+ }
467
+ };
468
+
381
469
  // ../../node_modules/.pnpm/p-queue@10.0.0/node_modules/p-queue/dist/lower-bound.js
382
470
  function lowerBound(array, value, comparator) {
383
471
  let first = 0;
@@ -2298,7 +2386,10 @@ var ServiceFacade = class {
2298
2386
  this.name = config.name || config.id;
2299
2387
  this.version = config.version || "1.0.0";
2300
2388
  this.description = config.description || "";
2301
- this.functionalities = config.functionalities ? { ...config.functionalities } : {};
2389
+ this.functionalities = {};
2390
+ for (const [name, functionality] of Object.entries(config.functionalities ?? {})) {
2391
+ this.registerFunctionality(name, functionality);
2392
+ }
2302
2393
  this.functionalityOrchestrations = config.functionalityOrchestrations ? { ...config.functionalityOrchestrations } : config.orchestrations ? { ...config.orchestrations } : {};
2303
2394
  this.libraries = config.libraries ? { ...config.libraries } : {};
2304
2395
  this.dependencies = Object.freeze(config.dependencies ? [...config.dependencies] : []);
@@ -2370,8 +2461,11 @@ var ServiceFacade = class {
2370
2461
  };
2371
2462
  const result = await this.queue.executeCommand(command, async (payload, workerCtx) => {
2372
2463
  WorkerExecutionBoundary.assertWorkerContext(workerCtx);
2373
- if (this.functionalities[op] && typeof this.functionalities[op].execute === "function") {
2374
- return await this.functionalities[op].execute(payload, {
2464
+ const functionality = this.functionalities[op];
2465
+ if (functionality) {
2466
+ return await functionality.execute(payload, {
2467
+ serviceId: this.id,
2468
+ functionalityId: functionality.id,
2375
2469
  correlationId: workerCtx.correlationId,
2376
2470
  state: this.instance.getState()
2377
2471
  });
@@ -2407,6 +2501,13 @@ var ServiceFacade = class {
2407
2501
  idempotencyKey: options.idempotencyKey,
2408
2502
  createdAt: Date.now()
2409
2503
  };
2504
+ orch.events.emit("triggered", {
2505
+ serviceId: this.id,
2506
+ orchestrationId: orch.id,
2507
+ orchestrationName: orch.name,
2508
+ correlationId,
2509
+ timestamp: Date.now()
2510
+ });
2410
2511
  const cmdResult = await this.queue.executeCommand(
2411
2512
  command,
2412
2513
  async (payload, workerCtx) => {
@@ -2496,8 +2597,33 @@ var ServiceFacade = class {
2496
2597
  );
2497
2598
  }
2498
2599
  );
2499
- if (cmdResult.status === "FAILED") {
2500
- throw new Error(cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
2600
+ const orchestrationResult = cmdResult.data;
2601
+ if (cmdResult.status === "COMPLETED" && orchestrationResult) {
2602
+ const lifecycleEvent = orchestrationResult.status === "COMPLETED" ? "completed" : "failed";
2603
+ orch.events.emit(lifecycleEvent, {
2604
+ serviceId: this.id,
2605
+ orchestrationId: orch.id,
2606
+ orchestrationName: orch.name,
2607
+ correlationId,
2608
+ executionId: String(orchestrationResult.executionMetadata.executionId ?? ""),
2609
+ timestamp: Date.now(),
2610
+ status: orchestrationResult.status,
2611
+ output: orchestrationResult.output,
2612
+ error: orchestrationResult.error
2613
+ });
2614
+ } else {
2615
+ orch.events.emit("failed", {
2616
+ serviceId: this.id,
2617
+ orchestrationId: orch.id,
2618
+ orchestrationName: orch.name,
2619
+ correlationId,
2620
+ timestamp: Date.now(),
2621
+ status: cmdResult.status,
2622
+ error: cmdResult.error
2623
+ });
2624
+ }
2625
+ if (cmdResult.status === "FAILED" || orchestrationResult?.status === "FAILED") {
2626
+ throw new Error(orchestrationResult?.error || cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
2501
2627
  }
2502
2628
  return cmdResult.data;
2503
2629
  }
@@ -2525,17 +2651,29 @@ var ServiceFacade = class {
2525
2651
  setState(mutation) {
2526
2652
  this.instance.setState(mutation);
2527
2653
  }
2528
- on(event, handler) {
2529
- return this.instance.on(event, handler);
2530
- }
2531
- emit(event, payload) {
2532
- this.instance.emit(event, payload);
2654
+ getFunctionality(name) {
2655
+ const functionality = this.functionalities[name];
2656
+ if (!functionality) {
2657
+ throw new Error(`[ServiceFacade:${this.id}] Functionality "${name}" not found.`);
2658
+ }
2659
+ return functionality;
2533
2660
  }
2534
- registerFunctionality(name, functionality) {
2661
+ registerFunctionality(name, functionality, options = {}) {
2535
2662
  if (!name || typeof name !== "string") {
2536
2663
  throw new Error("[ServiceFacade] Functionality name must be a non-empty string.");
2537
2664
  }
2538
- this.functionalities[name] = functionality;
2665
+ if (functionality instanceof FunctionalityFacade) {
2666
+ this.functionalities[name] = functionality;
2667
+ return this;
2668
+ }
2669
+ if (!functionality || typeof functionality !== "object" || typeof functionality.execute !== "function") {
2670
+ throw new Error(`[ServiceFacade:${this.id}] Functionality "${name}" must define execute().`);
2671
+ }
2672
+ this.functionalities[name] = new FunctionalityFacade(
2673
+ name,
2674
+ functionality,
2675
+ options
2676
+ );
2539
2677
  return this;
2540
2678
  }
2541
2679
  registerFunctionalityOrchestration(name, orchestration) {
@@ -2573,14 +2711,22 @@ var ServiceFacade = class {
2573
2711
  return this.getNamespace();
2574
2712
  }
2575
2713
  getNamespace() {
2714
+ const bubbledFunctionalities = {};
2715
+ for (const [name, functionality] of Object.entries(this.functionalities)) {
2716
+ if (functionality.bubbleEvents) bubbledFunctionalities[name] = functionality;
2717
+ }
2718
+ const bubbledOrchestrations = {};
2719
+ for (const [name, orchestration] of Object.entries(this.functionalityOrchestrations)) {
2720
+ if (orchestration.bubbleEvents) bubbledOrchestrations[name] = orchestration;
2721
+ }
2576
2722
  return {
2577
2723
  serviceId: this.id,
2578
2724
  serviceName: this.name,
2579
2725
  version: this.version,
2580
2726
  description: this.description,
2581
2727
  libraries: { ...this.libraries },
2582
- functionalities: { ...this.functionalities },
2583
- functionalityOrchestrations: { ...this.functionalityOrchestrations },
2728
+ functionalities: bubbledFunctionalities,
2729
+ functionalityOrchestrations: bubbledOrchestrations,
2584
2730
  capabilities: this.capabilities,
2585
2731
  dependencies: this.dependencies
2586
2732
  };
@@ -3277,6 +3423,34 @@ var KrnlPackageReconciler = class {
3277
3423
  }
3278
3424
  };
3279
3425
 
3426
+ // src/events/ServiceEventBus.ts
3427
+ var ServiceEventBus = class extends EventBus {
3428
+ };
3429
+
3430
+ // src/events/OrchestrationEventFacade.ts
3431
+ var OrchestrationEventFacade = class {
3432
+ eventBus = new EventBus();
3433
+ events;
3434
+ constructor() {
3435
+ this.events = createEventChannels(this.eventBus, ["triggered", "completed", "failed"]);
3436
+ }
3437
+ get triggered() {
3438
+ return this.events.triggered;
3439
+ }
3440
+ get completed() {
3441
+ return this.events.completed;
3442
+ }
3443
+ get failed() {
3444
+ return this.events.failed;
3445
+ }
3446
+ emit(event, payload) {
3447
+ this.eventBus.emit(event, payload);
3448
+ }
3449
+ clear() {
3450
+ this.eventBus.clear();
3451
+ }
3452
+ };
3453
+
3280
3454
  // src/connectivity/ProtocolResolver.ts
3281
3455
  var ProtocolResolver = class {
3282
3456
  static selectProtocol(requiredCapabilities, availableEndpoints) {
@@ -3297,6 +3471,8 @@ var FunctionalityOrchestration = class {
3297
3471
  description;
3298
3472
  timeoutMs;
3299
3473
  scope = "functionality";
3474
+ bubbleEvents;
3475
+ events;
3300
3476
  steps = [];
3301
3477
  flows = /* @__PURE__ */ new Map();
3302
3478
  constructor(descriptor) {
@@ -3308,6 +3484,8 @@ var FunctionalityOrchestration = class {
3308
3484
  this.version = descriptor.version || "1.0.0";
3309
3485
  this.description = descriptor.description || "";
3310
3486
  this.timeoutMs = descriptor.timeoutMs;
3487
+ this.bubbleEvents = descriptor.bubbleEvents ?? true;
3488
+ this.events = new OrchestrationEventFacade();
3311
3489
  }
3312
3490
  /**
3313
3491
  * Adds a sequential functionality step to the DAG.
@@ -3468,6 +3646,7 @@ var FunctionalityOrchestration = class {
3468
3646
  description: this.description,
3469
3647
  timeoutMs: this.timeoutMs,
3470
3648
  scope: "functionality",
3649
+ bubbleEvents: this.bubbleEvents,
3471
3650
  dependencies: [],
3472
3651
  steps: this.steps.map((s) => ({
3473
3652
  id: s.id,
@@ -3571,6 +3750,8 @@ var FunctionalityOrchestration = class {
3571
3750
  // src/index.ts
3572
3751
  import * as gutts from "@dinilmusick/gutts";
3573
3752
  export {
3753
+ EventBus,
3754
+ FunctionalityFacade,
3574
3755
  FunctionalityOrchestration,
3575
3756
  HttpProtocolAdapter,
3576
3757
  KrnlPackageReconciler,
@@ -3578,6 +3759,7 @@ export {
3578
3759
  KrnlWorkerPool,
3579
3760
  LifecycleManager,
3580
3761
  MemoryTransport,
3762
+ OrchestrationEventFacade,
3581
3763
  P2PProtocolAdapter,
3582
3764
  ProtocolResolver,
3583
3765
  ServiceDiscovery,
@@ -3591,6 +3773,7 @@ export {
3591
3773
  UdpProtocolAdapter,
3592
3774
  WebSocketProtocolAdapter,
3593
3775
  WorkerExecutionBoundary,
3776
+ createEventChannels,
3594
3777
  createService,
3595
3778
  createServiceDefinition,
3596
3779
  createServiceFacade,
@@ -23,7 +23,7 @@
23
23
  "typecheck": "tsc --noEmit -p tsconfig.json"
24
24
  },
25
25
  "dependencies": {
26
- "@dinilmusick/gutts": "^0.1.0",
26
+ "@dinilmusick/gutts": "^1.0.0",
27
27
  "esbuild": "^0.25.0",
28
28
  "p-queue": "^10.0.0",
29
29
  "protobufjs": "^8.7.1",