@triggery/core 0.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # @triggery/core
2
+
3
+ ## 0.1.0
4
+
5
+ First public preview release.
6
+
7
+ Declarative business-logic orchestration for React — core runtime
8
+
9
+ See the [repository-level CHANGELOG](../../CHANGELOG.md#010--2026-05-16) for the full set of packages and the umbrella feature list. Future entries on this file are appended automatically by changesets.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aleksey Skhomenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # @triggery/core
2
+
3
+ Core runtime for [Triggery](https://github.com/triggeryjs/triggery) — a declarative orchestration layer for React business logic.
4
+
5
+ This package contains:
6
+
7
+ - `createTrigger<Schema>(config)` — define a trigger.
8
+ - `createRuntime()` — isolated runtime (registry + scheduler + inspector).
9
+ - `getDefaultRuntime()` / `setDefaultRuntime()` — global singleton.
10
+ - Lifecycle middleware chain.
11
+ - Public types and helpers.
12
+
13
+ You usually do not consume this package directly — use [`@triggery/react`](../react).
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pnpm add @triggery/core
19
+ ```
20
+
21
+ ## License
22
+
23
+ MIT &copy; Aleksey Skhomenko
@@ -0,0 +1,461 @@
1
+ /**
2
+ * Public types of Triggery Core.
3
+ *
4
+ * Convention:
5
+ * `S` — trigger schema (`TriggerSchema`).
6
+ * `R` — tuple/union of required condition keys (`required`).
7
+ */
8
+ /** Fallback "empty map" type used when part of the schema is omitted. */
9
+ type EmptyRecord = Record<string, never>;
10
+ type TriggerSchema = {
11
+ events?: Record<string, unknown>;
12
+ conditions?: Record<string, unknown>;
13
+ actions?: Record<string, unknown>;
14
+ };
15
+ type EventMap<S extends TriggerSchema> = S['events'] extends Record<string, unknown> ? S['events'] : EmptyRecord;
16
+ type ConditionMap<S extends TriggerSchema> = S['conditions'] extends Record<string, unknown> ? S['conditions'] : EmptyRecord;
17
+ type ActionMap<S extends TriggerSchema> = S['actions'] extends Record<string, unknown> ? S['actions'] : EmptyRecord;
18
+ type EventKey<S extends TriggerSchema> = Extract<keyof EventMap<S>, string>;
19
+ type ConditionKey<S extends TriggerSchema> = Extract<keyof ConditionMap<S>, string>;
20
+ type ActionKey<S extends TriggerSchema> = Extract<keyof ActionMap<S>, string>;
21
+ /**
22
+ * Discriminated union over all events in the schema.
23
+ * Used in `TriggerCtx.event` — handlers can branch on `event.name`.
24
+ */
25
+ type EventOf<S extends TriggerSchema> = {
26
+ [K in EventKey<S>]: {
27
+ readonly name: K;
28
+ readonly payload: EventMap<S>[K];
29
+ };
30
+ }[EventKey<S>];
31
+ /**
32
+ * Conditions: required keys are non-optional, the rest are optional.
33
+ */
34
+ type ConditionsCtx<C extends Record<string, unknown>, R extends keyof C = never> = {
35
+ readonly [K in R]: C[K];
36
+ } & {
37
+ readonly [K in Exclude<keyof C, R>]?: C[K];
38
+ };
39
+ type ActionFn<P> = [P] extends [void] ? () => void : (payload: P) => void;
40
+ /**
41
+ * Actions: all entries are optional (they may not be registered) plus
42
+ * chainable `debounce/throttle/defer` (V1: stubs, full implementation in V1.1+).
43
+ */
44
+ type ActionsCtx<A extends Record<string, unknown>> = {
45
+ readonly [K in keyof A]?: ActionFn<A[K]>;
46
+ } & {
47
+ debounce(ms: number): ActionsCtx<A>;
48
+ throttle(ms: number): ActionsCtx<A>;
49
+ defer(ms: number): ActionsCtx<A>;
50
+ };
51
+ /**
52
+ * `check` helpers — DSL for condition checks inside a handler.
53
+ * - `is(key, predicate)` — true when the condition exists and the predicate matches.
54
+ * - `all({ key: predicate, ... })` — every listed condition must exist and match.
55
+ * - `any({ key: predicate, ... })` — at least one must match.
56
+ */
57
+ type CheckCtx<C extends Record<string, unknown>> = {
58
+ is<K extends keyof C>(key: K, predicate: (value: NonNullable<C[K]>) => boolean): boolean;
59
+ all<M extends Partial<{
60
+ [K in keyof C]: (value: NonNullable<C[K]>) => boolean;
61
+ }>>(map: M): boolean;
62
+ any<M extends Partial<{
63
+ [K in keyof C]: (value: NonNullable<C[K]>) => boolean;
64
+ }>>(map: M): boolean;
65
+ };
66
+ /**
67
+ * `meta` — runtime metadata about the current run (runId, parentRunId for cascade, etc.).
68
+ */
69
+ type MetaCtx = {
70
+ readonly runId: string;
71
+ readonly triggerId: string;
72
+ readonly scheduledAt: number;
73
+ readonly cascadeDepth: number;
74
+ readonly parentRunId?: string;
75
+ readonly parentTriggerId?: string;
76
+ };
77
+ /**
78
+ * The context object passed to a handler on every run.
79
+ */
80
+ type TriggerCtx<S extends TriggerSchema, R extends ConditionKey<S> = never> = {
81
+ readonly event: EventOf<S>;
82
+ readonly conditions: ConditionsCtx<ConditionMap<S>, R>;
83
+ readonly actions: ActionsCtx<ActionMap<S>>;
84
+ readonly check: CheckCtx<ConditionMap<S>>;
85
+ readonly meta: MetaCtx;
86
+ readonly signal: AbortSignal;
87
+ };
88
+ type TriggerHandler<S extends TriggerSchema, R extends ConditionKey<S> = never> = (ctx: TriggerCtx<S, R>) => void | Promise<void>;
89
+ type SchedulerStrategy = 'sync' | 'microtask';
90
+ type ConcurrencyStrategy = 'sync' | 'take-latest' | 'take-every' | 'take-first' | 'queue' | 'exhaust';
91
+ type TriggerConfig<S extends TriggerSchema, R extends ConditionKey<S> = never> = {
92
+ /** Unique trigger id within a runtime. */
93
+ id: string;
94
+ /** Required condition keys. The handler will not run unless all of them are registered. */
95
+ required?: readonly R[];
96
+ /** Dispatch scheduling strategy (default: `'microtask'`). */
97
+ schedule?: SchedulerStrategy;
98
+ /** Default concurrency for async actions inside the handler. */
99
+ concurrency?: ConcurrencyStrategy;
100
+ /** Scope id (for `<TriggerScope>` isolation; ignored in V1). */
101
+ scope?: string;
102
+ /** Trigger body. */
103
+ handler: TriggerHandler<S, R>;
104
+ };
105
+ /**
106
+ * Capitalize the first character of a string. Used to build named hook identifiers.
107
+ * @internal
108
+ */
109
+ type CapFirst<S extends string> = S extends `${infer A}${infer B}` ? `${Uppercase<A>}${B}` : S;
110
+ /**
111
+ * Convert a kebab-case key to camelCase: `'new-message'` → `'newMessage'`.
112
+ * @internal
113
+ */
114
+ type KebabToCamel<S extends string> = S extends `${infer A}-${infer B}` ? `${A}${CapFirst<KebabToCamel<B>>}` : S;
115
+ /** kebab-case or camelCase → PascalCase, for substitution into `use<Name>...`. */
116
+ type ToPascal<S extends string> = CapFirst<KebabToCamel<S>>;
117
+ /**
118
+ * Event hook signature — returns an emitter with a correctly typed payload.
119
+ */
120
+ type EventHook<P> = () => [P] extends [void] ? () => void : (payload: P) => void;
121
+ /**
122
+ * Condition hook signature.
123
+ */
124
+ type ConditionHook<V> = (getter: () => V, deps?: readonly unknown[], options?: {
125
+ readonly subscribe?: boolean;
126
+ }) => void;
127
+ /**
128
+ * Action hook signature — registers an executor.
129
+ */
130
+ type ActionHook<P> = (handler: [P] extends [void] ? () => void : (payload: P) => void) => void;
131
+ /**
132
+ * Generated named hooks. Returned by `trigger.namedHooks()`.
133
+ */
134
+ type NamedHooks<S extends TriggerSchema> = {
135
+ readonly [K in EventKey<S> as `use${ToPascal<K>}Event`]: EventHook<EventMap<S>[K]>;
136
+ } & {
137
+ readonly [K in ConditionKey<S> as `use${ToPascal<K>}Condition`]: ConditionHook<ConditionMap<S>[K]>;
138
+ } & {
139
+ readonly [K in ActionKey<S> as `use${ToPascal<K>}Action`]: ActionHook<ActionMap<S>[K]>;
140
+ };
141
+ /**
142
+ * The public trigger object returned by `createTrigger`.
143
+ */
144
+ type Trigger<S extends TriggerSchema> = {
145
+ readonly id: string;
146
+ readonly schedule: SchedulerStrategy;
147
+ /** Enable / disable the trigger at runtime. */
148
+ enable(): void;
149
+ disable(): void;
150
+ isEnabled(): boolean;
151
+ /** Get the named hooks proxy (typed via template literal types). */
152
+ namedHooks(): NamedHooks<S>;
153
+ /** Snapshot of the most recent run (for devtools / `useInspect`). */
154
+ inspect(): TriggerInspectSnapshot | undefined;
155
+ /** Remove the trigger from its runtime permanently. */
156
+ dispose(): void;
157
+ };
158
+ type TriggerInspectSnapshot = {
159
+ readonly triggerId: string;
160
+ readonly runId: string;
161
+ readonly eventName: string;
162
+ readonly status: 'fired' | 'skipped' | 'errored' | 'aborted';
163
+ readonly reason?: string;
164
+ readonly durationMs: number;
165
+ readonly executedActions: readonly string[];
166
+ readonly snapshotKeys: readonly string[];
167
+ };
168
+ type ConditionGetter<V = unknown> = () => V;
169
+ type UntypedActionFn = (payload: unknown) => void | Promise<void>;
170
+ type RegistrationToken = {
171
+ /** Idempotent unregister. */
172
+ unregister(): void;
173
+ };
174
+ /**
175
+ * Per-environment override for the inspector flag. Either field may be omitted,
176
+ * in which case the auto default applies (DEV on, PROD off).
177
+ */
178
+ type InspectorEnvOverride = {
179
+ readonly dev?: boolean;
180
+ readonly prod?: boolean;
181
+ };
182
+ /**
183
+ * Inspector configuration for `createRuntime`.
184
+ *
185
+ * - `undefined` (default) — auto: on in DEV (`process.env.NODE_ENV !== 'production'`), off in PROD.
186
+ * - `true` — always on regardless of env.
187
+ * - `false` — always off regardless of env.
188
+ * - `{ dev?, prod? }` — per-env override; unset fields fall back to the auto default.
189
+ *
190
+ * When off, the runtime skips the per-run buffer write, `subscribe()` callbacks
191
+ * never fire, `getInspectorBuffer()` returns `[]`, and the hot path drops the
192
+ * snapshot allocation entirely (~30-40% extra throughput on a simple dispatch).
193
+ * Devtools — `@triggery/devtools-redux`, `@triggery/devtools-bridge`, the React
194
+ * `useInspectHistory` hook — require the inspector to be on.
195
+ */
196
+ type InspectorOption = boolean | InspectorEnvOverride;
197
+ type RuntimeOptions = {
198
+ /** Global middleware applied to every trigger in this runtime. */
199
+ middleware?: readonly Middleware[];
200
+ /** Maximum cascade depth (action → fireEvent → ...). Default: 3. */
201
+ maxCascadeDepth?: number;
202
+ /** Inspector ring buffer size (default: 50). Ignored when the inspector is disabled. */
203
+ inspectorBufferSize?: number;
204
+ /** Enable / disable the per-run inspector. See {@link InspectorOption}. */
205
+ inspector?: InspectorOption;
206
+ };
207
+ type FireContext = {
208
+ readonly eventName: string;
209
+ readonly payload: unknown;
210
+ readonly cascadeDepth: number;
211
+ readonly parentRunId?: string;
212
+ readonly parentTriggerId?: string;
213
+ /**
214
+ * Linked-list reference to the parent dispatch context (the trigger
215
+ * currently running whose handler/action called this `fire`). The
216
+ * dispatcher walks this chain to detect cycles without ever allocating a
217
+ * `Set` of visited ids on the hot path. `undefined` on top-level fires.
218
+ *
219
+ * The full `DispatchContext` shape is internal — middleware should treat
220
+ * this field as opaque.
221
+ */
222
+ readonly parentContext?: {
223
+ readonly triggerId: string;
224
+ readonly parent: unknown;
225
+ } | undefined;
226
+ };
227
+ type SkipContext = {
228
+ readonly triggerId: string;
229
+ readonly eventName: string;
230
+ readonly reason: string;
231
+ };
232
+ type MatchContext = {
233
+ readonly triggerId: string;
234
+ readonly eventName: string;
235
+ readonly payload: unknown;
236
+ readonly cascadeDepth: number;
237
+ };
238
+ type ActionContext = {
239
+ readonly triggerId: string;
240
+ readonly runId: string;
241
+ readonly actionName: string;
242
+ readonly payload: unknown;
243
+ };
244
+ type CascadeContext = {
245
+ readonly parentTriggerId: string;
246
+ readonly parentRunId: string;
247
+ readonly newEventName: string;
248
+ readonly cascadeDepth: number;
249
+ readonly kind: 'overflow' | 'cycle';
250
+ };
251
+ type Middleware = {
252
+ readonly name: string;
253
+ onFire?(ctx: FireContext): void | {
254
+ cancel: true;
255
+ reason: string;
256
+ };
257
+ /**
258
+ * Called once per (event, trigger) pair right after dispatch picks the
259
+ * trigger out of `eventIndex[eventName]`, before any concurrency gate /
260
+ * required-check / handler invocation. Useful for tracing "which triggers
261
+ * were considered for this event" without instrumenting `onSkip` and
262
+ * `onActionStart` separately. Purely observational — there is no `cancel`
263
+ * here, use `onFire` if you need to short-circuit a fire entirely.
264
+ */
265
+ onBeforeMatch?(ctx: MatchContext): void;
266
+ onSkip?(ctx: SkipContext): void;
267
+ onActionStart?(ctx: ActionContext): void;
268
+ onActionEnd?(ctx: ActionContext & {
269
+ durationMs: number;
270
+ result?: unknown;
271
+ }): void;
272
+ onError?(ctx: ActionContext & {
273
+ error: unknown;
274
+ }): void;
275
+ onCascade?(ctx: CascadeContext): void;
276
+ };
277
+ /**
278
+ * Optional scoping for `registerCondition` / `registerAction`. A scope is just
279
+ * a string id — registrations live in their own bucket per scope. A trigger
280
+ * whose `scope` matches receives that bucket; triggers without scope see the
281
+ * global bucket (scope `''`).
282
+ *
283
+ * @see `<TriggerScope id="…">` in `@triggery/react`.
284
+ */
285
+ type RegisterScopeOptions = {
286
+ readonly scope?: string;
287
+ };
288
+ /**
289
+ * Static, serializable description of a trigger — used by `runtime.graph()`,
290
+ * devtools panels, the CLI and any code that wants to introspect the registry
291
+ * without holding a reference to the live runtime objects.
292
+ */
293
+ type TriggerGraphNode = {
294
+ readonly id: string;
295
+ readonly scope: string;
296
+ readonly events: readonly string[];
297
+ readonly required: readonly string[];
298
+ readonly schedule: SchedulerStrategy;
299
+ readonly concurrency: ConcurrencyStrategy;
300
+ readonly enabled: boolean;
301
+ };
302
+ /**
303
+ * JSON-friendly snapshot of the runtime's trigger registry. Stable shape —
304
+ * safe to log, send over a postMessage bridge, or render in devtools.
305
+ */
306
+ type RuntimeGraph = {
307
+ readonly triggers: readonly TriggerGraphNode[];
308
+ /** Map of `eventName → triggerId[]`. Empty events are not included. */
309
+ readonly eventIndex: Readonly<Record<string, readonly string[]>>;
310
+ };
311
+ type Runtime = {
312
+ readonly id: string;
313
+ /**
314
+ * Whether the per-run inspector is active on this runtime. Devtools bridges
315
+ * can use this to detect "you mounted me but the runtime won't emit anything"
316
+ * and surface a one-time DEV warning.
317
+ */
318
+ readonly inspectorEnabled: boolean;
319
+ /** Register a trigger. Returns a token for later disposal. */
320
+ registerTrigger(config: InternalTriggerConfig): RegistrationToken;
321
+ /** Register a condition getter for a trigger. */
322
+ registerCondition(triggerId: string, name: string, getter: ConditionGetter, options?: RegisterScopeOptions): RegistrationToken;
323
+ /** Register an action handler for a trigger. */
324
+ registerAction(triggerId: string, name: string, handler: UntypedActionFn, options?: RegisterScopeOptions): RegistrationToken;
325
+ /** Fire an event asynchronously (through the scheduler). */
326
+ fire(eventName: string, payload?: unknown): void;
327
+ /** Run dispatch synchronously (for tests and benchmarks). */
328
+ fireSync(eventName: string, payload?: unknown): void;
329
+ /** Subscribe to all runtime events (read-only). */
330
+ subscribe(listener: (snapshot: TriggerInspectSnapshot) => void): RegistrationToken;
331
+ /** Get the most recent N runs (newest first). */
332
+ getInspectorBuffer(): readonly TriggerInspectSnapshot[];
333
+ /** Look up a trigger by id (for `useInspect` and CLI tools). */
334
+ getTrigger(triggerId: string): Trigger<TriggerSchema> | undefined;
335
+ /**
336
+ * JSON-friendly snapshot of the trigger registry — for devtools, the CLI's
337
+ * `triggery graph` command, and tooling that introspects connections.
338
+ */
339
+ graph(): RuntimeGraph;
340
+ /** Tear down the runtime completely. */
341
+ dispose(): void;
342
+ };
343
+ /** Internal (non-public for end users) shape consumed by the runtime. */
344
+ type InternalTriggerConfig = {
345
+ readonly id: string;
346
+ readonly schedule: SchedulerStrategy;
347
+ readonly concurrency: ConcurrencyStrategy;
348
+ readonly required: readonly string[];
349
+ readonly events: readonly string[];
350
+ /** Scope key — `undefined`/`''` means global. See `RegisterScopeOptions`. */
351
+ readonly scope: string;
352
+ readonly handler: (ctx: InternalHandlerCtx) => void | Promise<void>;
353
+ };
354
+ type InternalHandlerCtx = {
355
+ readonly event: {
356
+ readonly name: string;
357
+ readonly payload: unknown;
358
+ };
359
+ readonly conditions: Record<string, unknown>;
360
+ readonly actions: Record<string, ((payload: unknown) => void) | undefined> & {
361
+ debounce(ms: number): InternalHandlerCtx['actions'];
362
+ throttle(ms: number): InternalHandlerCtx['actions'];
363
+ defer(ms: number): InternalHandlerCtx['actions'];
364
+ };
365
+ readonly check: CheckCtx<Record<string, unknown>>;
366
+ readonly meta: MetaCtx;
367
+ readonly signal: AbortSignal;
368
+ };
369
+
370
+ /**
371
+ * Builds the `check` helper bound to a specific conditions snapshot.
372
+ *
373
+ * `is`, `all` and `any` accept predicates over `NonNullable<C[K]>`: if a condition is
374
+ * absent (`undefined` or `null`), the predicate is not invoked and the result is `false`
375
+ * for that key.
376
+ */
377
+ declare function createCheck<C extends Record<string, unknown>>(conditions: C): CheckCtx<C>;
378
+
379
+ /**
380
+ * Public trigger configuration.
381
+ *
382
+ * @remarks
383
+ * **V1 type limitation:** `required` is enforced at runtime only — it does not narrow
384
+ * the types of `conditions.*` inside the handler. Every condition is `T | undefined` in
385
+ * the handler (even when listed in `required`). Use an early return:
386
+ * `if (!conditions.user) return;` — TS narrows `conditions.user` to `User` after that.
387
+ *
388
+ * Alternative: `check.is('user', (u) => u.isActive)` — typesafe predicate with NonNullable narrowing.
389
+ *
390
+ * **V1.1+** will introduce a builder API (`createTrigger<S>().require(['user']).handle(...)`)
391
+ * that automatically narrows required conditions.
392
+ */
393
+ type CreateTriggerConfig<S extends TriggerSchema> = {
394
+ readonly id: string;
395
+ readonly events: readonly EventKey<S>[];
396
+ /** Required condition keys. The trigger will not run unless all of them are registered. */
397
+ readonly required?: readonly ConditionKey<S>[];
398
+ readonly schedule?: SchedulerStrategy;
399
+ /**
400
+ * Concurrency strategy applied across handler runs (default: `'take-latest'`).
401
+ *
402
+ * - `take-latest` — new run aborts the previous (`signal.aborted` becomes true).
403
+ * - `take-every` — every run proceeds independently, no aborts.
404
+ * - `take-first` / `exhaust` — new runs are skipped while one is still in flight.
405
+ * - `queue` — new runs wait for the previous to finish (serialized).
406
+ * - `sync` — like `take-every`; provided as a documentation marker.
407
+ */
408
+ readonly concurrency?: ConcurrencyStrategy;
409
+ readonly scope?: string;
410
+ readonly handler: TriggerHandler<S, never>;
411
+ };
412
+ /**
413
+ * Create a trigger and register it in a runtime (the default runtime if none is passed).
414
+ *
415
+ * @example
416
+ * ```ts
417
+ * const messageTrigger = createTrigger<{
418
+ * events: { 'new-message': { author: string; text: string } };
419
+ * conditions: { user: { id: string }; settings: { sound: boolean } };
420
+ * actions: { showToast: { title: string }; playSound: void };
421
+ * }>({
422
+ * id: 'message-received',
423
+ * events: ['new-message'],
424
+ * required: ['user', 'settings'],
425
+ * handler({ event, conditions, actions, check }) {
426
+ * if (!conditions.user || !conditions.settings) return; // V1: manual narrowing
427
+ * if (check.is('settings', (s) => s.sound)) actions.playSound?.();
428
+ * actions.showToast?.({ title: event.payload.author });
429
+ * },
430
+ * });
431
+ * ```
432
+ */
433
+ declare function createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>;
434
+
435
+ type InspectorImpl = {
436
+ record(snapshot: TriggerInspectSnapshot): void;
437
+ getBuffer(): readonly TriggerInspectSnapshot[];
438
+ getLastForTrigger(triggerId: string): TriggerInspectSnapshot | undefined;
439
+ subscribe(listener: (snapshot: TriggerInspectSnapshot) => void): () => void;
440
+ clear(): void;
441
+ };
442
+ /**
443
+ * Ring-buffer inspector. `record` is O(1) — writes into a fixed-size slot array
444
+ * with a wrap-around index, no `unshift`/`shift` allocations. `getBuffer`
445
+ * materializes a newest-first array on demand (rare relative to fires).
446
+ */
447
+ declare function createInspector(bufferSize: number): InspectorImpl;
448
+
449
+ declare function createRuntime(options?: RuntimeOptions): Runtime;
450
+ declare function getDefaultRuntime(): Runtime;
451
+ declare function setDefaultRuntime(runtime: Runtime): void;
452
+
453
+ type Task = () => void;
454
+ type SchedulerImpl = {
455
+ enqueue(task: Task): void;
456
+ /** Drain all pending tasks synchronously (for tests and `fireSync`). */
457
+ flush(): void;
458
+ };
459
+ declare function createScheduler(strategy: SchedulerStrategy): SchedulerImpl;
460
+
461
+ export { type ActionContext, type ActionFn, type ActionHook, type ActionKey, type ActionMap, type ActionsCtx, type CascadeContext, type CheckCtx, type ConcurrencyStrategy, type ConditionGetter, type ConditionHook, type ConditionKey, type ConditionMap, type ConditionsCtx, type CreateTriggerConfig, type EmptyRecord, type EventHook, type EventKey, type EventMap, type EventOf, type FireContext, type InspectorImpl, type InternalHandlerCtx, type InternalTriggerConfig, type MatchContext, type MetaCtx, type Middleware, type NamedHooks, type RegisterScopeOptions, type RegistrationToken, type Runtime, type RuntimeGraph, type RuntimeOptions, type SchedulerImpl, type SchedulerStrategy, type SkipContext, type Task, type ToPascal, type Trigger, type TriggerConfig, type TriggerCtx, type TriggerGraphNode, type TriggerHandler, type TriggerInspectSnapshot, type TriggerSchema, type UntypedActionFn, createCheck, createInspector, createRuntime, createScheduler, createTrigger, getDefaultRuntime, setDefaultRuntime };