@quazardous/quarkernel 1.0.12 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,74 +1,195 @@
1
1
  # QuarKernel
2
2
 
3
- Micro Custom Event Kernel.
3
+ [![npm version](https://img.shields.io/npm/v/@quazardous/quarkernel.svg?style=flat-square)](https://www.npmjs.com/package/@quazardous/quarkernel)
4
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/@quazardous/quarkernel?style=flat-square)](https://bundlephobia.com/package/@quazardous/quarkernel)
5
+ [![license](https://img.shields.io/npm/l/@quazardous/quarkernel.svg?style=flat-square)](https://github.com/quazardous/quarkernel/blob/main/LICENSE)
4
6
 
5
- ## Features
7
+ **Event orchestration with dependency ordering, shared context, and state machines.**
6
8
 
7
- Helps structuring your app with events.
9
+ TypeScript-first. Zero dependencies. < 2KB gzipped.
8
10
 
9
- - Modern: ES6, Async() support with Promise
10
- - Dependency support: easily handle async resource dependencies
11
- - Composite event: handle complex logic with a common event pipe
12
- - Shared context: use event data to share variable
11
+ [![Try QK Studio](https://img.shields.io/badge/Try_it_live-QK_Studio-blue?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBvbHlnb24gcG9pbnRzPSI1IDMgMTkgMTIgNSAyMSA1IDMiPjwvcG9seWdvbj48L3N2Zz4=)](https://quazardous.github.io/quarkernel/qk-studio/)
12
+ [![Try FSM Studio](https://img.shields.io/badge/Try_it_live-FSM_Studio-purple?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiPjxjaXJjbGUgY3g9IjYiIGN5PSIxMiIgcj0iMyIvPjxjaXJjbGUgY3g9IjE4IiBjeT0iMTIiIHI9IjMiLz48bGluZSB4MT0iOSIgeTE9IjEyIiB4Mj0iMTUiIHkyPSIxMiIvPjwvc3ZnPg==)](https://quazardous.github.io/quarkernel/fsm-studio/)
13
+
14
+ ---
15
+
16
+ ## Why QuarKernel?
17
+
18
+ ```typescript
19
+ // Other event libs: fire and pray
20
+ emitter.emit('user:login', data);
21
+
22
+ // QuarKernel: orchestrate with confidence
23
+ qk.on('user:login', fetchUser, { id: 'fetch' });
24
+ qk.on('user:login', logAnalytics, { after: ['fetch'] }); // Guaranteed order
25
+ qk.on('user:login', (e) => greet(e.context.user)); // Shared context
26
+ ```
27
+
28
+ **What makes it different:**
29
+
30
+ | Feature | mitt | emittery | **QuarKernel** |
31
+ |---------|:----:|:--------:|:--------------:|
32
+ | Dependency ordering | - | - | **Yes** |
33
+ | Shared context | - | - | **Yes** |
34
+ | Composite events | - | - | **Yes** |
35
+ | Wildcards | - | - | **Yes** |
36
+ | Async/await | - | Yes | **Yes** |
37
+ | TypeScript | Yes | Yes | **Yes** |
38
+ | < 2KB | Yes | Yes | **Yes** |
39
+
40
+ ---
13
41
 
14
42
  ## Install
15
43
 
16
44
  ```bash
17
- npm i "@quazardous/quarkernel"
45
+ npm install @quazardous/quarkernel
46
+ ```
47
+
48
+ ```html
49
+ <!-- CDN -->
50
+ <script src="https://unpkg.com/@quazardous/quarkernel@2/dist/index.umd.js"></script>
18
51
  ```
19
52
 
20
- ## Basic usage
53
+ ---
21
54
 
22
- Define event listeners across your app modules with dependency support.
23
- Share context between components.
55
+ ## Quick Start
24
56
 
25
- ```js
26
- import { QuarKernel, QuarKernelEvent as QKE } from '@quazardous/quarkernel';
57
+ ```typescript
58
+ import { createKernel } from '@quazardous/quarkernel';
27
59
 
28
- // singleton
29
- const qk = new QuarKernel();
60
+ const qk = createKernel();
30
61
 
31
- qk.addEventListener('my_event', (e) => {
32
- // something
33
- notNeeded();
62
+ // 1. Dependency ordering - control execution sequence
63
+ qk.on('checkout', async (e) => {
64
+ e.context.inventory = await checkStock(e.data.items);
65
+ }, { id: 'stock' });
66
+
67
+ qk.on('checkout', async (e) => {
68
+ // Runs AFTER stock check - guaranteed
69
+ await processPayment(e.data.card, e.context.inventory);
70
+ }, { after: ['stock'] });
71
+
72
+ await qk.emit('checkout', { items: ['sku-123'], card: 'tok_visa' });
73
+ ```
74
+
75
+ ```typescript
76
+ // 2. Composite events - react to event combinations
77
+ import { Composition } from '@quazardous/quarkernel';
78
+
79
+ const checkout = new Composition([
80
+ [qk, 'cart:ready'],
81
+ [qk, 'payment:confirmed']
82
+ ]);
83
+
84
+ checkout.onComposed(() => {
85
+ console.log('Both events fired - proceed to shipping!');
34
86
  });
87
+ ```
35
88
 
36
- // your module foo does some init stuff
37
- qk.addEventListener('my_event', async (e) => {
38
- // something async
39
- e.context.needed = await needed();
40
- }, 'foo');
41
-
42
- // somewhere else in your app your module bar is waiting after foo to set a specific context
43
- qk.addEventListener('my_event', (e) => {
44
- // something after the async callback
45
- needing(e.context.needed);
46
- }, 'bar', 'foo');
47
-
48
- // call everything
49
- qk.dispatchEvent(new QKE('my_event')).then((e) => {
50
- // event my_event fully dispatched
51
- happyEnd();
89
+ ```typescript
90
+ // 3. Wildcards - catch event patterns
91
+ qk.on('user:*', (e) => console.log('User action:', e.name));
92
+ // Matches: user:login, user:logout, user:signup...
93
+ ```
94
+
95
+ ---
96
+
97
+ ## State Machines (FSM)
98
+
99
+ Built-in finite state machine support with XState-compatible format:
100
+
101
+ ```typescript
102
+ import { createMachine } from '@quazardous/quarkernel/fsm';
103
+
104
+ const order = createMachine({
105
+ id: 'order',
106
+ initial: 'draft',
107
+ context: { items: 0 },
108
+ states: {
109
+ draft: { on: { SUBMIT: 'pending' } },
110
+ pending: { on: { APPROVE: 'confirmed', REJECT: 'draft' } },
111
+ confirmed: { on: { SHIP: 'shipped' } },
112
+ shipped: {}
113
+ },
114
+ onEnter: {
115
+ confirmed: (ctx, { log }) => log('Order confirmed!')
116
+ },
117
+ on: {
118
+ SUBMIT: (ctx, { set }) => set({ submittedAt: Date.now() })
119
+ }
52
120
  });
53
- // or await qk.dispatchEvent(new QKE('my_event'));
121
+
122
+ order.send('SUBMIT');
123
+ console.log(order.state); // 'pending'
54
124
  ```
55
125
 
56
- ## Composite event
126
+ **Features:**
127
+ - XState import/export (`fromXState`, `toXState`)
128
+ - Behavior helpers: `set()`, `send()`, `log()`
129
+ - Auto-timers for delayed transitions
130
+ - Visual debugging with [FSM Studio](https://quazardous.github.io/quarkernel/fsm-studio/)
57
131
 
58
- Composite event are auto dispatched when a specific list of events are dispatched.
132
+ ---
59
133
 
60
- ie. You set a composite event C on A+B. Your code dispatches A, then B. C is auto dispatched after B.
134
+ ## Framework Adapters
61
135
 
62
- ```js
63
- ...
64
- // init
65
- qk.addCompositeEvent(['A','B'], (stack) => new QKE('C'));
66
- ...
67
- qk.dispatchEvent(new QKE('A'));
68
- ...
69
- // this will auto dispatch C
70
- qk.dispatchEvent(new QKE('B'));
136
+ Official bindings with auto-cleanup on unmount:
71
137
 
138
+ | Package | Framework | Docs |
139
+ |---------|-----------|------|
140
+ | `@quazardous/quarkernel-vue` | Vue 3 | [README](https://github.com/quazardous/quarkernel/blob/main/packages/vue/README.md) |
141
+ | `@quazardous/quarkernel-react` | React 18+ | [README](https://github.com/quazardous/quarkernel/blob/main/packages/react/README.md) |
142
+ | `@quazardous/quarkernel-svelte` | Svelte 5 | [README](https://github.com/quazardous/quarkernel/blob/main/packages/svelte/README.md) |
143
+
144
+ ```bash
145
+ # Vue
146
+ npm install @quazardous/quarkernel @quazardous/quarkernel-vue
147
+
148
+ # React
149
+ npm install @quazardous/quarkernel @quazardous/quarkernel-react
150
+
151
+ # Svelte
152
+ npm install @quazardous/quarkernel @quazardous/quarkernel-svelte
72
153
  ```
73
154
 
155
+ ---
156
+
157
+ ## Documentation
158
+
159
+ **Guides:**
160
+ - [Getting Started](https://github.com/quazardous/quarkernel/blob/main/docs/getting-started.md) - Installation, first event, basic usage
161
+ - [API Reference](https://github.com/quazardous/quarkernel/blob/main/docs/api-reference.md) - Complete API documentation
162
+ - [Advanced Patterns](https://github.com/quazardous/quarkernel/blob/main/docs/advanced-qk.md) - Multi-machine, composition, sagas
163
+ - [Async Integration](https://github.com/quazardous/quarkernel/blob/main/docs/async-patterns.md) - QK + FSM + Promises synergies
164
+ - [Migration v1 to v2](https://github.com/quazardous/quarkernel/blob/main/docs/migration-v1-to-v2.md) - Upgrade guide
165
+
166
+ **Packages:**
167
+ - [Core package](https://github.com/quazardous/quarkernel/blob/main/packages/quarkernel/README.md) - Main QuarKernel library
168
+
169
+ **Resources:**
170
+ - [Benchmarks](https://github.com/quazardous/quarkernel/blob/main/benchmarks/README.md) - Performance comparisons
171
+ - [Demos](https://github.com/quazardous/quarkernel/blob/main/demos/README.md) - Live examples
172
+
173
+ ---
174
+
175
+ ## Use Cases
176
+
177
+ **Request pipeline** - Auth, validate, transform, respond in guaranteed order
178
+
179
+ **Game events** - Combo detection with composite events
180
+
181
+ **Form wizards** - Step dependencies with shared validation context
182
+
183
+ **Order workflows** - State machines for order lifecycle (draft → pending → confirmed → shipped)
184
+
185
+ **Analytics** - Wildcard listeners for all `track:*` events
186
+
187
+ **Microservices** - Event choreography with dependency graphs
188
+
189
+ **UI flows** - FSM-driven modals, wizards, and multi-step forms
190
+
191
+ ---
192
+
193
+ ## License
74
194
 
195
+ [MIT](https://github.com/quazardous/quarkernel/blob/main/LICENSE) - Made by [quazardous](https://github.com/quazardous)
@@ -0,0 +1,275 @@
1
+ /**
2
+ * FSM Types for QuarKernel
3
+ *
4
+ * Flexible state machine layer built on quarkernel events.
5
+ * Prefixed events allow loose coupling and multi-machine orchestration.
6
+ */
7
+ /**
8
+ * State name type
9
+ */
10
+ type StateName = string;
11
+ /**
12
+ * Transition event name type
13
+ */
14
+ type TransitionEvent = string;
15
+ /**
16
+ * Guard function - returns true to allow transition
17
+ */
18
+ type GuardFunction<TContext = any> = (context: TContext, event: TransitionEvent, payload?: any) => boolean;
19
+ /**
20
+ * Action function - side effect on transition
21
+ */
22
+ type ActionFunction<TContext = any> = (context: TContext, event: TransitionEvent, payload?: any) => void | Promise<void>;
23
+ /**
24
+ * Transition definition
25
+ */
26
+ interface TransitionDef<TContext = any> {
27
+ /** Target state */
28
+ target: StateName;
29
+ /** Guard condition (optional) */
30
+ guard?: GuardFunction<TContext>;
31
+ /** Actions to run on transition (optional) */
32
+ actions?: ActionFunction<TContext> | ActionFunction<TContext>[];
33
+ }
34
+ /**
35
+ * Timer/after definition for auto-transitions
36
+ */
37
+ interface AfterDef$1 {
38
+ /** Delay in milliseconds */
39
+ delay: number;
40
+ /** Event to send after delay */
41
+ send: string;
42
+ }
43
+ /**
44
+ * State node definition (state-centric format)
45
+ */
46
+ interface StateNode<TContext = any> {
47
+ /** Transitions from this state: event -> target or TransitionDef */
48
+ on?: Record<TransitionEvent, StateName | TransitionDef<TContext>>;
49
+ /** Action on entering this state */
50
+ entry?: ActionFunction<TContext>;
51
+ /** Action on exiting this state */
52
+ exit?: ActionFunction<TContext>;
53
+ /** Auto-transition after delay: { delay: 3000, send: 'TIMER' } */
54
+ after?: AfterDef$1;
55
+ }
56
+ /**
57
+ * Machine configuration
58
+ */
59
+ interface MachineConfig<TContext = any> {
60
+ /** Event prefix for this machine (e.g., 'order', 'player') */
61
+ prefix: string;
62
+ /** Initial state */
63
+ initial: StateName;
64
+ /** State definitions */
65
+ states: Record<StateName, StateNode<TContext>>;
66
+ /** Initial context (optional) */
67
+ context?: TContext;
68
+ /** Allow force transitions that bypass guards */
69
+ allowForce?: boolean;
70
+ /** Restore from snapshot (overrides initial/context) */
71
+ snapshot?: MachineSnapshot<TContext>;
72
+ /** Track transition history */
73
+ trackHistory?: boolean;
74
+ /** Max history entries (default: 100) */
75
+ maxHistory?: number;
76
+ }
77
+ /**
78
+ * Send options
79
+ */
80
+ interface SendOptions<TContext = any> {
81
+ /** Force transition (bypass guards and undefined transitions) */
82
+ force?: boolean;
83
+ /** Target state for force transitions */
84
+ target?: StateName;
85
+ /** Inline guard (overrides state guard) */
86
+ guard?: GuardFunction<TContext>;
87
+ /** Fallback state if guard fails */
88
+ fallback?: StateName;
89
+ }
90
+ /**
91
+ * Serialized machine state (for persistence)
92
+ */
93
+ interface MachineSnapshot<TContext = any> {
94
+ /** Current state */
95
+ state: StateName;
96
+ /** Machine context */
97
+ context: TContext;
98
+ /** Transition history (optional) */
99
+ history?: Array<{
100
+ from: StateName;
101
+ to: StateName;
102
+ event: TransitionEvent;
103
+ timestamp: number;
104
+ }>;
105
+ }
106
+ /**
107
+ * Machine instance returned by useMachine()
108
+ */
109
+ interface Machine<TContext = any> {
110
+ /** Current state */
111
+ getState(): StateName;
112
+ /** Machine context */
113
+ getContext(): TContext;
114
+ /** Update context */
115
+ setContext(updater: Partial<TContext> | ((ctx: TContext) => TContext)): void;
116
+ /** Send transition event */
117
+ send(event: TransitionEvent, payload?: any, options?: SendOptions<TContext>): Promise<boolean>;
118
+ /** Check if transition is valid from current state */
119
+ can(event: TransitionEvent): boolean;
120
+ /** Get available transitions from current state */
121
+ transitions(): TransitionEvent[];
122
+ /** Machine prefix */
123
+ readonly prefix: string;
124
+ /** Serialize machine state to JSON */
125
+ toJSON(): MachineSnapshot<TContext>;
126
+ /** Restore machine state from snapshot */
127
+ restore(snapshot: MachineSnapshot<TContext>): void;
128
+ /** Cleanup listeners */
129
+ destroy(): void;
130
+ }
131
+ /**
132
+ * FSM event data emitted on kernel
133
+ */
134
+ interface FSMEventData {
135
+ /** Machine prefix */
136
+ machine: string;
137
+ /** Current/new state */
138
+ state: StateName;
139
+ /** Previous state (for transition events) */
140
+ from?: StateName;
141
+ /** Target state (for transition events) */
142
+ to?: StateName;
143
+ /** Transition event name */
144
+ event?: TransitionEvent;
145
+ /** Event payload */
146
+ payload?: any;
147
+ /** Whether this was a forced transition */
148
+ forced?: boolean;
149
+ }
150
+
151
+ /**
152
+ * createMachine - High-level FSM factory
153
+ *
154
+ * Standalone state machine with declarative behaviors.
155
+ * Can work independently or connect to a kernel.
156
+ */
157
+
158
+ /**
159
+ * Built-in helpers (always available)
160
+ */
161
+ interface BuiltInHelpers<TContext = Record<string, unknown>> {
162
+ /** Merge into context */
163
+ set: (partial: Partial<TContext>) => void;
164
+ /** Trigger transition */
165
+ send: (event: string, payload?: unknown) => void;
166
+ /** Log message (default: console.log) */
167
+ log: (message: string) => void;
168
+ }
169
+ /**
170
+ * Behavior helpers passed to callbacks (built-ins + custom)
171
+ */
172
+ type BehaviorHelpers<TContext = Record<string, unknown>, TCustom = Record<string, unknown>> = BuiltInHelpers<TContext> & TCustom;
173
+ /**
174
+ * Behavior callback
175
+ */
176
+ type BehaviorFn<TContext = Record<string, unknown>> = (ctx: TContext, helpers: BehaviorHelpers<TContext>) => void | Promise<void>;
177
+ /**
178
+ * Timer/after definition
179
+ */
180
+ interface AfterDef {
181
+ /** Event to send */
182
+ send: string;
183
+ /** Delay in ms */
184
+ delay: number;
185
+ }
186
+ /**
187
+ * State-centric state definition
188
+ */
189
+ interface StateConfig<TContext = Record<string, unknown>> {
190
+ /** Transitions: { EVENT: 'target' } or { EVENT: { target: 'x', cond: 'guard' } } */
191
+ on?: Record<string, string | {
192
+ target: string;
193
+ cond?: string;
194
+ }>;
195
+ /** Action on entering this state */
196
+ entry?: BehaviorFn<TContext>;
197
+ /** Action on exiting this state */
198
+ exit?: BehaviorFn<TContext>;
199
+ /** Auto-transition after delay: { delay: 3000, send: 'TIMER' } */
200
+ after?: AfterDef;
201
+ }
202
+ /**
203
+ * High-level machine config (state-centric)
204
+ */
205
+ interface CreateMachineConfig<TContext = Record<string, unknown>, THelpers = Record<string, unknown>> {
206
+ /** Machine identifier */
207
+ id: string;
208
+ /** Initial state */
209
+ initial: string;
210
+ /** Initial context */
211
+ context?: TContext;
212
+ /** State definitions with entry/exit/after inline */
213
+ states: Record<string, StateConfig<TContext>>;
214
+ /** Global event handlers: { EVENT_NAME: (ctx, helpers) => ... } */
215
+ on?: Record<string, BehaviorFn<TContext>>;
216
+ /** Custom helpers merged with built-ins (set, send) */
217
+ helpers?: THelpers;
218
+ }
219
+ /**
220
+ * Extended machine interface with behaviors
221
+ */
222
+ interface BehaviorMachine<TContext = Record<string, unknown>> extends Machine<TContext> {
223
+ /** Machine ID */
224
+ readonly id: string;
225
+ /** Current state (getter) */
226
+ readonly state: string;
227
+ /** Current context (getter) */
228
+ readonly context: TContext;
229
+ }
230
+ /**
231
+ * Create a standalone state machine with behaviors (state-centric)
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * const order = createMachine({
236
+ * id: 'order',
237
+ * initial: 'draft',
238
+ * context: { items: 0, total: 0 },
239
+ *
240
+ * states: {
241
+ * draft: {
242
+ * on: { ADD_ITEM: 'draft', SUBMIT: 'pending' }
243
+ * },
244
+ * pending: {
245
+ * entry: (ctx, { log }) => log('Order pending...'),
246
+ * on: { APPROVE: 'confirmed', REJECT: 'draft' }
247
+ * },
248
+ * confirmed: {
249
+ * entry: (ctx, { log }) => log(`Order confirmed: ${ctx.items} items`),
250
+ * on: { SHIP: 'shipped' }
251
+ * },
252
+ * processing: {
253
+ * after: { delay: 2000, send: 'COMPLETE' },
254
+ * on: { COMPLETE: 'done' }
255
+ * },
256
+ * shipped: {},
257
+ * },
258
+ *
259
+ * // Global event handlers (optional)
260
+ * on: {
261
+ * ADD_ITEM: (ctx, { set }) => {
262
+ * set({ items: ctx.items + 1, total: ctx.total + 29.99 });
263
+ * },
264
+ * },
265
+ * });
266
+ *
267
+ * order.send('ADD_ITEM');
268
+ * order.send('SUBMIT');
269
+ * console.log(order.state); // 'pending'
270
+ * console.log(order.context); // { items: 1, total: 29.99 }
271
+ * ```
272
+ */
273
+ declare function createMachine<TContext = Record<string, unknown>>(config: CreateMachineConfig<TContext>): BehaviorMachine<TContext>;
274
+
275
+ export { type ActionFunction as A, type BehaviorMachine as B, type CreateMachineConfig as C, type FSMEventData as F, type GuardFunction as G, type MachineConfig as M, type StateNode as S, type TransitionDef as T, type Machine as a, type MachineSnapshot as b, createMachine as c, type SendOptions as d, type StateName as e, type TransitionEvent as f, type StateConfig as g, type BehaviorFn as h, type BehaviorHelpers as i, type BuiltInHelpers as j, type AfterDef as k, type AfterDef$1 as l };