@quazardous/quarkernel 2.2.4 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { M as MachineConfig, a as Machine } from './create-machine-CYsscHPX.cjs';
1
+ import { M as MachineConfig, a as Machine } from './create-machine-SGkCnU0g.js';
2
2
 
3
3
  /**
4
4
  * KernelEvent - Custom event implementation for QuarKernel
@@ -456,9 +456,20 @@ type ContextMergerFunction = (contexts: Record<string, any>) => any;
456
456
  */
457
457
  interface IKernel<Events extends EventMap = EventMap> {
458
458
  on<K extends keyof Events>(event: K | K[], listener: ListenerFunction<Events[K]>, options?: ListenerOptions): () => void;
459
- once<K extends keyof Events>(event: K, listener: ListenerFunction<Events[K]>, options?: Omit<ListenerOptions, 'once'>): () => void;
460
- once<K extends keyof Events>(event: K, predicate: PredicateFunction<Events[K]>, listener: ListenerFunction<Events[K]>, options?: Omit<ListenerOptions, 'once'>): () => void;
461
- once<K extends keyof Events>(event: K): Promise<IKernelEvent<Events[K]>>;
459
+ /**
460
+ * Wait for an event once (Promise-based)
461
+ *
462
+ * For callback style, use: `on(event, listener, { once: true })`
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * const event = await qk.once('user:loaded');
467
+ * const event = await qk.once('user:loaded', { timeout: 5000 });
468
+ * ```
469
+ */
470
+ once<K extends keyof Events>(event: K, options?: {
471
+ timeout?: number;
472
+ }): Promise<IKernelEvent<Events[K]>>;
462
473
  off<K extends keyof Events>(event: K, listener?: ListenerFunction<Events[K]>): void;
463
474
  offAll(event?: keyof Events): void;
464
475
  emit<K extends keyof Events>(event: K, data?: Events[K]): Promise<void>;
@@ -617,6 +628,30 @@ declare class Composition<Events extends EventMap = EventMap> {
617
628
  * @returns Unbind function to remove the listener
618
629
  */
619
630
  onComposed(listener: ListenerFunction<Events[keyof Events]>, options?: ListenerOptions): () => void;
631
+ /**
632
+ * Wait for the next composition completion as a Promise
633
+ *
634
+ * @param options - Optional timeout configuration
635
+ * @returns Promise resolving with composed event data
636
+ *
637
+ * @example
638
+ * ```typescript
639
+ * // .then() receives: { sources, contexts, merged }
640
+ * const result = await composition.once();
641
+ * console.log(result.data.merged); // merged context from all sources
642
+ * console.log(result.data.sources); // ['event1', 'event2']
643
+ *
644
+ * // With timeout
645
+ * const result = await composition.once({ timeout: 5000 });
646
+ * ```
647
+ */
648
+ once(options?: {
649
+ timeout?: number;
650
+ }): Promise<IKernelEvent<{
651
+ sources: EventName$1[];
652
+ contexts: Record<EventName$1, Record<string, any>>;
653
+ merged: Record<string, any>;
654
+ }>>;
620
655
  /**
621
656
  * Remove a listener for composed events
622
657
  */
@@ -748,6 +783,29 @@ declare class Kernel<Events extends EventMap = EventMap> implements ListenerCont
748
783
  * Returns an unbind function for cleanup
749
784
  */
750
785
  on<K extends keyof Events>(eventName: K, listener: ListenerFunction<Events[K]>, options?: ListenerOptions): () => void;
786
+ /**
787
+ * Wait for an event once (Promise-based)
788
+ *
789
+ * For callback style, use: `qk.on(event, listener, { once: true })`
790
+ *
791
+ * @param eventName - Event to wait for
792
+ * @param options - Optional timeout in ms
793
+ * @returns Promise resolving with the event
794
+ *
795
+ * @example
796
+ * ```typescript
797
+ * // .then() receives: IKernelEvent { name, data, context, timestamp }
798
+ * const event = await qk.once('user:loaded');
799
+ * console.log(event.data); // event payload
800
+ * console.log(event.context); // shared context
801
+ *
802
+ * // With timeout (rejects if event doesn't fire)
803
+ * const event = await qk.once('user:loaded', { timeout: 5000 });
804
+ * ```
805
+ */
806
+ once<K extends keyof Events>(eventName: K, options?: {
807
+ timeout?: number;
808
+ }): Promise<KernelEvent<Events[K]>>;
751
809
  /**
752
810
  * Remove an event listener
753
811
  * If no listener provided, removes all listeners for the event
@@ -1,4 +1,4 @@
1
- import { M as MachineConfig, a as Machine } from './create-machine-CYsscHPX.js';
1
+ import { M as MachineConfig, a as Machine } from './create-machine-SGkCnU0g.cjs';
2
2
 
3
3
  /**
4
4
  * KernelEvent - Custom event implementation for QuarKernel
@@ -456,9 +456,20 @@ type ContextMergerFunction = (contexts: Record<string, any>) => any;
456
456
  */
457
457
  interface IKernel<Events extends EventMap = EventMap> {
458
458
  on<K extends keyof Events>(event: K | K[], listener: ListenerFunction<Events[K]>, options?: ListenerOptions): () => void;
459
- once<K extends keyof Events>(event: K, listener: ListenerFunction<Events[K]>, options?: Omit<ListenerOptions, 'once'>): () => void;
460
- once<K extends keyof Events>(event: K, predicate: PredicateFunction<Events[K]>, listener: ListenerFunction<Events[K]>, options?: Omit<ListenerOptions, 'once'>): () => void;
461
- once<K extends keyof Events>(event: K): Promise<IKernelEvent<Events[K]>>;
459
+ /**
460
+ * Wait for an event once (Promise-based)
461
+ *
462
+ * For callback style, use: `on(event, listener, { once: true })`
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * const event = await qk.once('user:loaded');
467
+ * const event = await qk.once('user:loaded', { timeout: 5000 });
468
+ * ```
469
+ */
470
+ once<K extends keyof Events>(event: K, options?: {
471
+ timeout?: number;
472
+ }): Promise<IKernelEvent<Events[K]>>;
462
473
  off<K extends keyof Events>(event: K, listener?: ListenerFunction<Events[K]>): void;
463
474
  offAll(event?: keyof Events): void;
464
475
  emit<K extends keyof Events>(event: K, data?: Events[K]): Promise<void>;
@@ -617,6 +628,30 @@ declare class Composition<Events extends EventMap = EventMap> {
617
628
  * @returns Unbind function to remove the listener
618
629
  */
619
630
  onComposed(listener: ListenerFunction<Events[keyof Events]>, options?: ListenerOptions): () => void;
631
+ /**
632
+ * Wait for the next composition completion as a Promise
633
+ *
634
+ * @param options - Optional timeout configuration
635
+ * @returns Promise resolving with composed event data
636
+ *
637
+ * @example
638
+ * ```typescript
639
+ * // .then() receives: { sources, contexts, merged }
640
+ * const result = await composition.once();
641
+ * console.log(result.data.merged); // merged context from all sources
642
+ * console.log(result.data.sources); // ['event1', 'event2']
643
+ *
644
+ * // With timeout
645
+ * const result = await composition.once({ timeout: 5000 });
646
+ * ```
647
+ */
648
+ once(options?: {
649
+ timeout?: number;
650
+ }): Promise<IKernelEvent<{
651
+ sources: EventName$1[];
652
+ contexts: Record<EventName$1, Record<string, any>>;
653
+ merged: Record<string, any>;
654
+ }>>;
620
655
  /**
621
656
  * Remove a listener for composed events
622
657
  */
@@ -748,6 +783,29 @@ declare class Kernel<Events extends EventMap = EventMap> implements ListenerCont
748
783
  * Returns an unbind function for cleanup
749
784
  */
750
785
  on<K extends keyof Events>(eventName: K, listener: ListenerFunction<Events[K]>, options?: ListenerOptions): () => void;
786
+ /**
787
+ * Wait for an event once (Promise-based)
788
+ *
789
+ * For callback style, use: `qk.on(event, listener, { once: true })`
790
+ *
791
+ * @param eventName - Event to wait for
792
+ * @param options - Optional timeout in ms
793
+ * @returns Promise resolving with the event
794
+ *
795
+ * @example
796
+ * ```typescript
797
+ * // .then() receives: IKernelEvent { name, data, context, timestamp }
798
+ * const event = await qk.once('user:loaded');
799
+ * console.log(event.data); // event payload
800
+ * console.log(event.context); // shared context
801
+ *
802
+ * // With timeout (rejects if event doesn't fire)
803
+ * const event = await qk.once('user:loaded', { timeout: 5000 });
804
+ * ```
805
+ */
806
+ once<K extends keyof Events>(eventName: K, options?: {
807
+ timeout?: number;
808
+ }): Promise<KernelEvent<Events[K]>>;
751
809
  /**
752
810
  * Remove an event listener
753
811
  * If no listener provided, removes all listeners for the event
package/dist/index.cjs CHANGED
@@ -504,6 +504,39 @@ var Composition = class {
504
504
  onComposed(listener, options) {
505
505
  return this.kernel.on(COMPOSED_EVENT, listener, options);
506
506
  }
507
+ /**
508
+ * Wait for the next composition completion as a Promise
509
+ *
510
+ * @param options - Optional timeout configuration
511
+ * @returns Promise resolving with composed event data
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * // .then() receives: { sources, contexts, merged }
516
+ * const result = await composition.once();
517
+ * console.log(result.data.merged); // merged context from all sources
518
+ * console.log(result.data.sources); // ['event1', 'event2']
519
+ *
520
+ * // With timeout
521
+ * const result = await composition.once({ timeout: 5000 });
522
+ * ```
523
+ */
524
+ once(options) {
525
+ return new Promise((resolve, reject) => {
526
+ let timeoutId;
527
+ const listener = (event) => {
528
+ if (timeoutId) clearTimeout(timeoutId);
529
+ resolve(event);
530
+ };
531
+ const unbind = this.kernel.on(COMPOSED_EVENT, listener, { once: true });
532
+ if (options?.timeout) {
533
+ timeoutId = setTimeout(() => {
534
+ unbind();
535
+ reject(new Error(`composition.once() timed out after ${options.timeout}ms`));
536
+ }, options.timeout);
537
+ }
538
+ });
539
+ }
507
540
  /**
508
541
  * Remove a listener for composed events
509
542
  */
@@ -758,6 +791,42 @@ var Kernel = class _Kernel {
758
791
  }
759
792
  return () => this.off(event, listener);
760
793
  }
794
+ /**
795
+ * Wait for an event once (Promise-based)
796
+ *
797
+ * For callback style, use: `qk.on(event, listener, { once: true })`
798
+ *
799
+ * @param eventName - Event to wait for
800
+ * @param options - Optional timeout in ms
801
+ * @returns Promise resolving with the event
802
+ *
803
+ * @example
804
+ * ```typescript
805
+ * // .then() receives: IKernelEvent { name, data, context, timestamp }
806
+ * const event = await qk.once('user:loaded');
807
+ * console.log(event.data); // event payload
808
+ * console.log(event.context); // shared context
809
+ *
810
+ * // With timeout (rejects if event doesn't fire)
811
+ * const event = await qk.once('user:loaded', { timeout: 5000 });
812
+ * ```
813
+ */
814
+ once(eventName, options) {
815
+ return new Promise((resolve, reject) => {
816
+ let timeoutId;
817
+ const listener = (event) => {
818
+ if (timeoutId) clearTimeout(timeoutId);
819
+ resolve(event);
820
+ };
821
+ const unbind = this.on(eventName, listener, { once: true });
822
+ if (options?.timeout) {
823
+ timeoutId = setTimeout(() => {
824
+ unbind();
825
+ reject(new Error(`once('${String(eventName)}') timed out after ${options.timeout}ms`));
826
+ }, options.timeout);
827
+ }
828
+ });
829
+ }
761
830
  /**
762
831
  * Remove an event listener
763
832
  * If no listener provided, removes all listeners for the event
@@ -1414,6 +1483,37 @@ function useMachine(kernel, config) {
1414
1483
  history = [...snapshot2.history];
1415
1484
  }
1416
1485
  },
1486
+ waitFor(targetState, options) {
1487
+ if (currentState === targetState) {
1488
+ return Promise.resolve({
1489
+ state: currentState,
1490
+ context: structuredClone(context)
1491
+ });
1492
+ }
1493
+ return new Promise((resolve, reject) => {
1494
+ let timeoutId;
1495
+ const unbind = kernel.on(
1496
+ `${prefix}:enter:${targetState}`,
1497
+ (event) => {
1498
+ if (timeoutId) clearTimeout(timeoutId);
1499
+ unbind();
1500
+ resolve({
1501
+ state: targetState,
1502
+ from: event.data?.from,
1503
+ event: event.data?.event,
1504
+ context: structuredClone(context)
1505
+ });
1506
+ }
1507
+ );
1508
+ cleanupFns.push(unbind);
1509
+ if (options?.timeout) {
1510
+ timeoutId = setTimeout(() => {
1511
+ unbind();
1512
+ reject(new Error(`waitFor('${targetState}') timed out after ${options.timeout}ms`));
1513
+ }, options.timeout);
1514
+ }
1515
+ });
1516
+ },
1417
1517
  destroy() {
1418
1518
  for (const cleanup of cleanupFns) {
1419
1519
  cleanup();