@directive-run/core 0.4.0 → 0.4.2
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/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +833 -187
- package/dist/index.d.ts +833 -187
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/migration.cjs.map +1 -1
- package/dist/migration.js.map +1 -1
- package/dist/plugins/index.cjs.map +1 -1
- package/dist/plugins/index.d.cts +85 -18
- package/dist/plugins/index.d.ts +85 -18
- package/dist/plugins/index.js.map +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +142 -26
- package/dist/testing.d.ts +142 -26
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -252,6 +252,11 @@ interface ChainableSchemaType<T> extends ExtendedSchemaType<T> {
|
|
|
252
252
|
/**
|
|
253
253
|
* Schema type builders for defining fact types.
|
|
254
254
|
*
|
|
255
|
+
* @remarks
|
|
256
|
+
* Each builder returns a chainable {@link ExtendedSchemaType} with validation
|
|
257
|
+
* methods (`.min()`, `.max()`, `.pattern()`, etc.) and dev-mode runtime
|
|
258
|
+
* type checking. Validators are tree-shaken in production builds.
|
|
259
|
+
*
|
|
255
260
|
* @example
|
|
256
261
|
* ```typescript
|
|
257
262
|
* const module = createModule("example", {
|
|
@@ -264,6 +269,8 @@ interface ChainableSchemaType<T> extends ExtendedSchemaType<T> {
|
|
|
264
269
|
* },
|
|
265
270
|
* });
|
|
266
271
|
* ```
|
|
272
|
+
*
|
|
273
|
+
* @public
|
|
267
274
|
*/
|
|
268
275
|
declare const t: {
|
|
269
276
|
/**
|
|
@@ -339,12 +346,14 @@ declare const t: {
|
|
|
339
346
|
_lastFailedIndex?: number;
|
|
340
347
|
};
|
|
341
348
|
/**
|
|
342
|
-
* Create an object schema type.
|
|
349
|
+
* Create an object schema type for any complex value.
|
|
343
350
|
* Can be used with or without shape validation:
|
|
344
351
|
* - `t.object<User>()` - Type-only, no property validation
|
|
345
352
|
* - `t.object<User>().shape({ name: t.string(), age: t.number() })` - With property validation
|
|
353
|
+
*
|
|
354
|
+
* For arrays, prefer `t.array<T>()` which adds `Array.isArray` validation.
|
|
346
355
|
*/
|
|
347
|
-
object<T
|
|
356
|
+
object<T>(): ChainableSchemaType<T> & {
|
|
348
357
|
shape(schema: { [K in keyof T]?: SchemaType<T[K]>; }): ChainableSchemaType<T> & /*elided*/ any;
|
|
349
358
|
nonNull(): ChainableSchemaType<T> & /*elided*/ any;
|
|
350
359
|
hasKeys(...keys: string[]): ChainableSchemaType<T> & /*elided*/ any;
|
|
@@ -511,11 +520,12 @@ interface CreateFactsStoreOptions<S extends Schema> {
|
|
|
511
520
|
* Create a reactive facts store backed by a Map with schema validation,
|
|
512
521
|
* batched mutations, and granular key-level subscriptions.
|
|
513
522
|
*
|
|
523
|
+
* @remarks
|
|
514
524
|
* The store is the low-level primitive that powers the `facts` proxy.
|
|
515
525
|
* Most users should use {@link createFacts} or `createModule` instead.
|
|
516
526
|
*
|
|
517
527
|
* @param options - Store configuration including schema, validation settings, and change callbacks
|
|
518
|
-
* @returns A
|
|
528
|
+
* @returns A {@link FactsStore} with get/set/batch/subscribe methods and automatic schema validation
|
|
519
529
|
*
|
|
520
530
|
* @example
|
|
521
531
|
* ```ts
|
|
@@ -531,26 +541,41 @@ interface CreateFactsStoreOptions<S extends Schema> {
|
|
|
531
541
|
* store.set("name", "hello");
|
|
532
542
|
* }); // listeners fire once after batch completes
|
|
533
543
|
* ```
|
|
544
|
+
*
|
|
545
|
+
* @internal
|
|
534
546
|
*/
|
|
535
547
|
declare function createFactsStore<S extends Schema>(options: CreateFactsStoreOptions<S>): FactsStore<S>;
|
|
536
548
|
/**
|
|
537
549
|
* Create a Proxy wrapper around a {@link FactsStore} for clean property-style
|
|
538
550
|
* access (`facts.phase`) with automatic dependency tracking.
|
|
539
551
|
*
|
|
552
|
+
* @remarks
|
|
540
553
|
* Reading a property calls `store.get()` (which tracks the access for
|
|
541
554
|
* auto-tracked derivations). Writing a property calls `store.set()` (which
|
|
542
555
|
* validates against the schema). The proxy also exposes `$store` for direct
|
|
543
556
|
* store access and `$snapshot()` for untracked reads.
|
|
544
557
|
*
|
|
545
558
|
* @param store - The underlying facts store to wrap
|
|
546
|
-
* @param schema - The schema definition
|
|
547
|
-
* @returns A
|
|
559
|
+
* @param schema - The schema definition used for `ownKeys` enumeration
|
|
560
|
+
* @returns A {@link Facts} proxy with property-style get/set and prototype pollution guards
|
|
561
|
+
*
|
|
562
|
+
* @example
|
|
563
|
+
* ```ts
|
|
564
|
+
* const store = createFactsStore({ schema: { phase: t.string() } });
|
|
565
|
+
* const facts = createFactsProxy(store, { phase: t.string() });
|
|
566
|
+
*
|
|
567
|
+
* facts.phase = "red";
|
|
568
|
+
* console.log(facts.phase); // "red"
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* @internal
|
|
548
572
|
*/
|
|
549
573
|
declare function createFactsProxy<S extends Schema>(store: FactsStore<S>, schema: S): Facts<S>;
|
|
550
574
|
/**
|
|
551
575
|
* Convenience factory that creates both a {@link FactsStore} and its
|
|
552
576
|
* {@link createFactsProxy | proxy wrapper} in a single call.
|
|
553
577
|
*
|
|
578
|
+
* @remarks
|
|
554
579
|
* This is the recommended entry point when you need low-level store access
|
|
555
580
|
* outside of `createModule` / `createSystem`.
|
|
556
581
|
*
|
|
@@ -567,6 +592,8 @@ declare function createFactsProxy<S extends Schema>(store: FactsStore<S>, schema
|
|
|
567
592
|
* console.log(facts.phase); // "red"
|
|
568
593
|
* store.subscribe(["phase"], () => console.log("phase changed"));
|
|
569
594
|
* ```
|
|
595
|
+
*
|
|
596
|
+
* @internal
|
|
570
597
|
*/
|
|
571
598
|
declare function createFacts<S extends Schema>(options: CreateFactsStoreOptions<S>): {
|
|
572
599
|
store: FactsStore<S>;
|
|
@@ -675,6 +702,10 @@ interface ModuleConfigWithDeps<M extends ModuleSchema, Deps extends CrossModuleD
|
|
|
675
702
|
* - Event dispatch (`system.dispatch({ type: "..." })` has autocomplete)
|
|
676
703
|
* - Resolver requirements (`req.payload` is typed based on requirement type)
|
|
677
704
|
*
|
|
705
|
+
* @param id - Unique module identifier (kebab-case recommended)
|
|
706
|
+
* @param config - Module configuration including schema, init, derive, constraints, resolvers, etc.
|
|
707
|
+
* @returns A frozen module definition ready for use with `createSystem`
|
|
708
|
+
*
|
|
678
709
|
* @example
|
|
679
710
|
* ```ts
|
|
680
711
|
* const trafficLight = createModule("traffic-light", {
|
|
@@ -749,6 +780,8 @@ interface ModuleConfigWithDeps<M extends ModuleSchema, Deps extends CrossModuleD
|
|
|
749
780
|
* },
|
|
750
781
|
* });
|
|
751
782
|
* ```
|
|
783
|
+
*
|
|
784
|
+
* @public
|
|
752
785
|
*/
|
|
753
786
|
declare function createModule<const M extends ModuleSchema, const Deps extends CrossModuleDeps>(id: string, config: ModuleConfigWithDeps<M, Deps>): ModuleDef<M>;
|
|
754
787
|
declare function createModule<const M extends ModuleSchema>(id: string, config: ModuleConfig<M>): ModuleDef<M>;
|
|
@@ -758,6 +791,9 @@ declare function createModule<const M extends ModuleSchema>(id: string, config:
|
|
|
758
791
|
* Useful for multi-instance UIs (tabs, panels, multi-tenant) where you need
|
|
759
792
|
* isolated state from the same schema.
|
|
760
793
|
*
|
|
794
|
+
* @param config - Module configuration (same shape as `createModule` minus the `id`)
|
|
795
|
+
* @returns A factory function that accepts a name and returns a `ModuleDef`
|
|
796
|
+
*
|
|
761
797
|
* @example
|
|
762
798
|
* ```typescript
|
|
763
799
|
* const chatRoom = createModuleFactory({
|
|
@@ -776,6 +812,8 @@ declare function createModule<const M extends ModuleSchema>(id: string, config:
|
|
|
776
812
|
* },
|
|
777
813
|
* });
|
|
778
814
|
* ```
|
|
815
|
+
*
|
|
816
|
+
* @public
|
|
779
817
|
*/
|
|
780
818
|
declare function createModuleFactory<const M extends ModuleSchema>(config: ModuleConfig<M>): (name: string) => ModuleDef<M>;
|
|
781
819
|
declare function createModuleFactory<const M extends ModuleSchema, const Deps extends CrossModuleDeps>(config: ModuleConfigWithDeps<M, Deps>): (name: string) => ModuleDef<M>;
|
|
@@ -805,6 +843,14 @@ declare function createModuleFactory<const M extends ModuleSchema, const Deps ex
|
|
|
805
843
|
* - **Single module**: Use `module` prop for direct access without namespace
|
|
806
844
|
* - **Multiple modules**: Use `modules` prop for namespaced access
|
|
807
845
|
*
|
|
846
|
+
* @remarks
|
|
847
|
+
* The system is the top-level runtime object. It owns the reconciliation loop,
|
|
848
|
+
* manages plugins, and exposes reactive accessors for facts, derivations, and events.
|
|
849
|
+
* Call `system.start()` to begin the lifecycle (init → ready → running → settled).
|
|
850
|
+
*
|
|
851
|
+
* @param options - System configuration with either `module` (single) or `modules` (namespaced)
|
|
852
|
+
* @returns A fully-typed {@link System} instance with reactive accessors
|
|
853
|
+
*
|
|
808
854
|
* @example Single module (direct access)
|
|
809
855
|
* ```ts
|
|
810
856
|
* const system = createSystem({ module: counterModule });
|
|
@@ -820,6 +866,8 @@ declare function createModuleFactory<const M extends ModuleSchema, const Deps ex
|
|
|
820
866
|
* system.facts.auth.token // Namespaced access
|
|
821
867
|
* system.events.auth.login() // Namespaced events
|
|
822
868
|
* ```
|
|
869
|
+
*
|
|
870
|
+
* @public
|
|
823
871
|
*/
|
|
824
872
|
declare function createSystem<S extends ModuleSchema>(options: CreateSystemOptionsSingle<S>): SingleModuleSystem<S>;
|
|
825
873
|
declare function createSystem<const Modules extends ModulesMap>(options: CreateSystemOptionsNamed<Modules>): NamespacedSystem<Modules>;
|
|
@@ -864,9 +912,15 @@ declare function createSystem<const Modules extends ModulesMap>(options: CreateS
|
|
|
864
912
|
*/
|
|
865
913
|
|
|
866
914
|
/**
|
|
867
|
-
*
|
|
915
|
+
* Fluent builder interface for constructing {@link ModuleDef} instances step by step.
|
|
916
|
+
*
|
|
917
|
+
* Chain methods like `.schema()`, `.init()`, `.derive()`, `.events()`, and others
|
|
918
|
+
* to configure the module, then call `.build()` to produce the final definition.
|
|
919
|
+
* The builder validates that all schema-declared derivations and events have
|
|
920
|
+
* corresponding implementations before returning.
|
|
868
921
|
*
|
|
869
|
-
* @typeParam M - The module schema type
|
|
922
|
+
* @typeParam M - The module schema type, narrowed after calling `.schema()`.
|
|
923
|
+
* @public
|
|
870
924
|
*/
|
|
871
925
|
interface ModuleBuilder<M extends ModuleSchema = ModuleSchema> {
|
|
872
926
|
/**
|
|
@@ -961,10 +1015,47 @@ interface ResolverDef<M extends ModuleSchema> {
|
|
|
961
1015
|
}) => string;
|
|
962
1016
|
}
|
|
963
1017
|
/**
|
|
964
|
-
* Create a new module builder.
|
|
1018
|
+
* Create a new module using the fluent builder pattern.
|
|
965
1019
|
*
|
|
966
|
-
* @
|
|
967
|
-
*
|
|
1020
|
+
* Returns a {@link ModuleBuilder} that lets you declaratively define a module's
|
|
1021
|
+
* schema, initialization, derivations, events, effects, constraints, resolvers,
|
|
1022
|
+
* and lifecycle hooks via method chaining. Call `.build()` at the end to produce
|
|
1023
|
+
* the final {@link ModuleDef}.
|
|
1024
|
+
*
|
|
1025
|
+
* @remarks
|
|
1026
|
+
* The builder validates at build time that every derivation and event declared
|
|
1027
|
+
* in the schema has a corresponding implementation. Missing implementations
|
|
1028
|
+
* cause a descriptive error.
|
|
1029
|
+
*
|
|
1030
|
+
* @param id - Unique identifier for this module, used for namespacing in multi-module systems.
|
|
1031
|
+
* @returns A {@link ModuleBuilder} ready for configuration via method chaining.
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* ```typescript
|
|
1035
|
+
* import { module, t } from '@directive-run/core';
|
|
1036
|
+
*
|
|
1037
|
+
* const counter = module("counter")
|
|
1038
|
+
* .schema({
|
|
1039
|
+
* facts: { count: t.number() },
|
|
1040
|
+
* derivations: { doubled: t.number() },
|
|
1041
|
+
* events: { increment: {} },
|
|
1042
|
+
* requirements: {},
|
|
1043
|
+
* })
|
|
1044
|
+
* .init((facts) => {
|
|
1045
|
+
* facts.count = 0;
|
|
1046
|
+
* })
|
|
1047
|
+
* .derive({
|
|
1048
|
+
* doubled: (facts) => facts.count * 2,
|
|
1049
|
+
* })
|
|
1050
|
+
* .events({
|
|
1051
|
+
* increment: (facts) => {
|
|
1052
|
+
* facts.count += 1;
|
|
1053
|
+
* },
|
|
1054
|
+
* })
|
|
1055
|
+
* .build();
|
|
1056
|
+
* ```
|
|
1057
|
+
*
|
|
1058
|
+
* @public
|
|
968
1059
|
*/
|
|
969
1060
|
declare function module$1(id: string): ModuleBuilder<ModuleSchema>;
|
|
970
1061
|
|
|
@@ -1082,45 +1173,127 @@ declare function when<M extends ModuleSchema>(condition: WhenFn<M>): WhenBuilder
|
|
|
1082
1173
|
* ```
|
|
1083
1174
|
*/
|
|
1084
1175
|
|
|
1085
|
-
/**
|
|
1176
|
+
/**
|
|
1177
|
+
* Entry point of the system builder, returned by {@link system}.
|
|
1178
|
+
*
|
|
1179
|
+
* Choose `.module()` for a single-module {@link SingleModuleSystem} with direct
|
|
1180
|
+
* fact/derivation access, or `.modules()` for a namespaced {@link NamespacedSystem}
|
|
1181
|
+
* that composes multiple modules.
|
|
1182
|
+
*
|
|
1183
|
+
* @public
|
|
1184
|
+
*/
|
|
1086
1185
|
interface SystemBuilderStart {
|
|
1186
|
+
/**
|
|
1187
|
+
* Configure the system with a single module definition.
|
|
1188
|
+
*
|
|
1189
|
+
* @param mod - The module definition to use as the system's sole module.
|
|
1190
|
+
* @returns A {@link SingleModuleSystemBuilder} for further configuration.
|
|
1191
|
+
*/
|
|
1087
1192
|
module<S extends ModuleSchema>(mod: ModuleDef<S>): SingleModuleSystemBuilder<S>;
|
|
1193
|
+
/**
|
|
1194
|
+
* Configure the system with multiple named modules.
|
|
1195
|
+
*
|
|
1196
|
+
* @param mods - A map of namespace keys to module definitions.
|
|
1197
|
+
* @returns A {@link NamespacedSystemBuilder} for further configuration.
|
|
1198
|
+
*/
|
|
1088
1199
|
modules<const Modules extends ModulesMap>(mods: Modules): NamespacedSystemBuilder<Modules>;
|
|
1089
1200
|
}
|
|
1090
|
-
/**
|
|
1201
|
+
/**
|
|
1202
|
+
* Builder for a single-module system with direct access to facts, derivations, and events.
|
|
1203
|
+
*
|
|
1204
|
+
* @remarks
|
|
1205
|
+
* Use this builder when your system contains exactly one module. The resulting
|
|
1206
|
+
* {@link SingleModuleSystem} exposes facts, derivations, and dispatch without
|
|
1207
|
+
* namespace prefixes.
|
|
1208
|
+
*
|
|
1209
|
+
* @typeParam S - The module schema type.
|
|
1210
|
+
* @public
|
|
1211
|
+
*/
|
|
1091
1212
|
interface SingleModuleSystemBuilder<S extends ModuleSchema> {
|
|
1213
|
+
/** Register plugins that hook into system lifecycle events. */
|
|
1092
1214
|
plugins(plugins: Array<Plugin<ModuleSchema>>): SingleModuleSystemBuilder<S>;
|
|
1215
|
+
/** Enable debug features such as time-travel debugging and snapshot limits. */
|
|
1093
1216
|
debug(config: DebugConfig): SingleModuleSystemBuilder<S>;
|
|
1217
|
+
/** Configure error boundary behavior including recovery strategies. */
|
|
1094
1218
|
errorBoundary(config: ErrorBoundaryConfig): SingleModuleSystemBuilder<S>;
|
|
1219
|
+
/** Set the reconciliation tick interval in milliseconds. */
|
|
1095
1220
|
tickMs(ms: number): SingleModuleSystemBuilder<S>;
|
|
1221
|
+
/** Enable zero-config mode which auto-generates constraints from schema metadata. */
|
|
1096
1222
|
zeroConfig(enabled?: boolean): SingleModuleSystemBuilder<S>;
|
|
1223
|
+
/** Provide initial fact values to hydrate the system on startup. */
|
|
1097
1224
|
initialFacts(facts: Partial<InferFacts<S>>): SingleModuleSystemBuilder<S>;
|
|
1225
|
+
/** Finalize configuration and create the running {@link SingleModuleSystem}. */
|
|
1098
1226
|
build(): SingleModuleSystem<S>;
|
|
1099
1227
|
}
|
|
1100
|
-
/**
|
|
1228
|
+
/**
|
|
1229
|
+
* Builder for a namespaced multi-module system.
|
|
1230
|
+
*
|
|
1231
|
+
* @remarks
|
|
1232
|
+
* Use this builder when composing multiple modules. The resulting
|
|
1233
|
+
* {@link NamespacedSystem} prefixes facts and derivations with the module
|
|
1234
|
+
* namespace key (e.g., `system.facts.auth.token`).
|
|
1235
|
+
*
|
|
1236
|
+
* @typeParam Modules - The modules map type mapping namespace keys to module definitions.
|
|
1237
|
+
* @public
|
|
1238
|
+
*/
|
|
1101
1239
|
interface NamespacedSystemBuilder<Modules extends ModulesMap> {
|
|
1240
|
+
/** Register plugins that hook into system lifecycle events. */
|
|
1102
1241
|
plugins(plugins: Array<Plugin<ModuleSchema>>): NamespacedSystemBuilder<Modules>;
|
|
1242
|
+
/** Enable debug features such as time-travel debugging and snapshot limits. */
|
|
1103
1243
|
debug(config: DebugConfig): NamespacedSystemBuilder<Modules>;
|
|
1244
|
+
/** Configure error boundary behavior including recovery strategies. */
|
|
1104
1245
|
errorBoundary(config: ErrorBoundaryConfig): NamespacedSystemBuilder<Modules>;
|
|
1246
|
+
/** Set the reconciliation tick interval in milliseconds. */
|
|
1105
1247
|
tickMs(ms: number): NamespacedSystemBuilder<Modules>;
|
|
1248
|
+
/** Enable zero-config mode which auto-generates constraints from schema metadata. */
|
|
1106
1249
|
zeroConfig(enabled?: boolean): NamespacedSystemBuilder<Modules>;
|
|
1250
|
+
/** Provide initial fact values keyed by module namespace for hydration on startup. */
|
|
1107
1251
|
initialFacts(facts: Partial<{
|
|
1108
1252
|
[K in keyof Modules]: Partial<InferFacts<ExtractSchema<Modules[K]>>>;
|
|
1109
1253
|
}>): NamespacedSystemBuilder<Modules>;
|
|
1254
|
+
/** Control the order in which modules are initialized: automatic, declaration order, or explicit. */
|
|
1110
1255
|
initOrder(order: "auto" | "declaration" | Array<keyof Modules & string>): NamespacedSystemBuilder<Modules>;
|
|
1256
|
+
/** Finalize configuration and create the running {@link NamespacedSystem}. */
|
|
1111
1257
|
build(): NamespacedSystem<Modules>;
|
|
1112
1258
|
}
|
|
1113
1259
|
/**
|
|
1114
|
-
* Create a system using the fluent builder pattern.
|
|
1115
|
-
* Choose `.module()` for single-module or `.modules()` for namespaced.
|
|
1260
|
+
* Create a Directive system using the fluent builder pattern.
|
|
1116
1261
|
*
|
|
1117
|
-
* @
|
|
1262
|
+
* Returns a {@link SystemBuilderStart} that branches into either a
|
|
1263
|
+
* single-module path (`.module()`) or a namespaced multi-module path
|
|
1264
|
+
* (`.modules()`). Chain configuration methods like `.plugins()`, `.debug()`,
|
|
1265
|
+
* and `.errorBoundary()`, then call `.build()` to produce the running system.
|
|
1266
|
+
*
|
|
1267
|
+
* @remarks
|
|
1268
|
+
* This is a convenience wrapper around {@link createSystem}. Both produce
|
|
1269
|
+
* identical systems; the builder simply offers a more discoverable,
|
|
1270
|
+
* chainable API.
|
|
1271
|
+
*
|
|
1272
|
+
* @returns A {@link SystemBuilderStart} ready to receive a module or modules map.
|
|
1273
|
+
*
|
|
1274
|
+
* @example Single-module system
|
|
1118
1275
|
* ```typescript
|
|
1276
|
+
* import { system } from '@directive-run/core';
|
|
1277
|
+
*
|
|
1119
1278
|
* const sys = system()
|
|
1120
1279
|
* .module(counterModule)
|
|
1121
1280
|
* .plugins([loggingPlugin()])
|
|
1281
|
+
* .debug({ timeTravel: true })
|
|
1282
|
+
* .build();
|
|
1283
|
+
* ```
|
|
1284
|
+
*
|
|
1285
|
+
* @example Multi-module namespaced system
|
|
1286
|
+
* ```typescript
|
|
1287
|
+
* import { system } from '@directive-run/core';
|
|
1288
|
+
*
|
|
1289
|
+
* const sys = system()
|
|
1290
|
+
* .modules({ auth: authModule, cart: cartModule })
|
|
1291
|
+
* .plugins([loggingPlugin()])
|
|
1292
|
+
* .initOrder(["auth", "cart"])
|
|
1122
1293
|
* .build();
|
|
1123
1294
|
* ```
|
|
1295
|
+
*
|
|
1296
|
+
* @public
|
|
1124
1297
|
*/
|
|
1125
1298
|
declare function system(): SystemBuilderStart;
|
|
1126
1299
|
|
|
@@ -1278,25 +1451,37 @@ declare function createSystemWithStatus<M extends ModuleSchema>(options: CreateS
|
|
|
1278
1451
|
*/
|
|
1279
1452
|
|
|
1280
1453
|
/**
|
|
1281
|
-
* Generate a stable
|
|
1282
|
-
*
|
|
1454
|
+
* Generate a stable identity string for a requirement.
|
|
1455
|
+
*
|
|
1456
|
+
* When no custom key function is provided, the ID is formed from the
|
|
1457
|
+
* requirement's `type` plus a deterministic JSON serialization of its
|
|
1458
|
+
* remaining properties. A custom {@link RequirementKeyFn} can override
|
|
1459
|
+
* this to control deduplication granularity.
|
|
1460
|
+
*
|
|
1461
|
+
* @param req - The requirement to generate an ID for.
|
|
1462
|
+
* @param keyFn - Optional custom key function that overrides the default identity logic.
|
|
1463
|
+
* @returns A stable string that uniquely identifies this requirement for deduplication.
|
|
1464
|
+
*
|
|
1465
|
+
* @public
|
|
1283
1466
|
*/
|
|
1284
1467
|
declare function generateRequirementId(req: Requirement, keyFn?: RequirementKeyFn): string;
|
|
1285
1468
|
/**
|
|
1286
|
-
*
|
|
1469
|
+
* Create a typed requirement factory for a given requirement type string.
|
|
1287
1470
|
*
|
|
1288
|
-
*
|
|
1289
|
-
*
|
|
1471
|
+
* Returns a function that, when called with a properties object, produces a
|
|
1472
|
+
* fully-typed {@link Requirement} whose `type` field is the literal `T`.
|
|
1473
|
+
* This is the recommended way to build requirements inside constraint
|
|
1474
|
+
* definitions because it keeps the type string in one place and gives you
|
|
1475
|
+
* full TypeScript inference on the payload.
|
|
1290
1476
|
*
|
|
1291
|
-
* @param type - The requirement type string
|
|
1292
|
-
* @returns A factory
|
|
1477
|
+
* @param type - The requirement type string (e.g. `"FETCH_USER"`).
|
|
1478
|
+
* @returns A factory that merges `type` with arbitrary properties into a typed requirement.
|
|
1293
1479
|
*
|
|
1294
1480
|
* @example
|
|
1295
1481
|
* ```typescript
|
|
1296
|
-
* // Create a requirement factory
|
|
1297
1482
|
* const fetchUser = req("FETCH_USER");
|
|
1298
1483
|
*
|
|
1299
|
-
* // Use
|
|
1484
|
+
* // Use inside a module's constraint definition
|
|
1300
1485
|
* constraints: {
|
|
1301
1486
|
* needsUser: {
|
|
1302
1487
|
* when: (facts) => facts.userId && !facts.user,
|
|
@@ -1304,89 +1489,149 @@ declare function generateRequirementId(req: Requirement, keyFn?: RequirementKeyF
|
|
|
1304
1489
|
* },
|
|
1305
1490
|
* }
|
|
1306
1491
|
*
|
|
1307
|
-
* //
|
|
1492
|
+
* // Produces: { type: "FETCH_USER", userId: 123, priority: "high" }
|
|
1308
1493
|
* ```
|
|
1494
|
+
*
|
|
1495
|
+
* @public
|
|
1309
1496
|
*/
|
|
1310
1497
|
declare function req<T extends string>(type: T): <P extends Record<string, unknown>>(props: P) => Requirement & {
|
|
1311
1498
|
type: T;
|
|
1312
1499
|
} & P;
|
|
1313
1500
|
/**
|
|
1314
|
-
*
|
|
1501
|
+
* Type-narrowing guard that checks whether a requirement's `type` matches the
|
|
1502
|
+
* given string literal.
|
|
1503
|
+
*
|
|
1504
|
+
* After this guard returns `true`, TypeScript narrows `req` to
|
|
1505
|
+
* `Requirement & { type: T }`, giving you access to type-specific fields.
|
|
1506
|
+
*
|
|
1507
|
+
* @param req - The requirement to test.
|
|
1508
|
+
* @param type - The expected type string to match against.
|
|
1509
|
+
* @returns `true` when `req.type === type`.
|
|
1510
|
+
*
|
|
1511
|
+
* @public
|
|
1315
1512
|
*/
|
|
1316
1513
|
declare function isRequirementType<T extends string>(req: Requirement, type: T): req is Requirement & {
|
|
1317
1514
|
type: T;
|
|
1318
1515
|
};
|
|
1319
1516
|
/**
|
|
1320
|
-
* Create a type
|
|
1321
|
-
*
|
|
1517
|
+
* Create a type-guard function suitable for a resolver's `requirement`
|
|
1518
|
+
* predicate field.
|
|
1519
|
+
*
|
|
1520
|
+
* @remarks
|
|
1521
|
+
* The returned predicate narrows any {@link Requirement} to the concrete
|
|
1522
|
+
* type `R` (or `Requirement & { type: T }` when no explicit generic is
|
|
1523
|
+
* provided). This is a cleaner alternative to writing verbose inline type
|
|
1524
|
+
* guards in every resolver definition.
|
|
1525
|
+
*
|
|
1526
|
+
* @param type - The requirement type string to match.
|
|
1527
|
+
* @returns A predicate that returns `true` for requirements whose `type` matches, narrowing the value for downstream callbacks like `key` and `resolve`.
|
|
1322
1528
|
*
|
|
1323
1529
|
* @example
|
|
1324
1530
|
* ```typescript
|
|
1325
|
-
* // With explicit requirement
|
|
1326
|
-
* interface
|
|
1327
|
-
* requirement: forType<
|
|
1328
|
-
* key: (req) => req.userId, // req is
|
|
1531
|
+
* // With an explicit requirement interface (recommended for complex payloads)
|
|
1532
|
+
* interface FetchUserReq { type: "FETCH_USER"; userId: string }
|
|
1533
|
+
* requirement: forType<FetchUserReq>("FETCH_USER"),
|
|
1534
|
+
* key: (req) => req.userId, // req is FetchUserReq
|
|
1329
1535
|
*
|
|
1330
|
-
* //
|
|
1536
|
+
* // With a simple string literal
|
|
1331
1537
|
* requirement: forType("FETCH_USER"),
|
|
1332
1538
|
* key: (req) => req.type, // req is Requirement & { type: "FETCH_USER" }
|
|
1333
1539
|
* ```
|
|
1540
|
+
*
|
|
1541
|
+
* @public
|
|
1334
1542
|
*/
|
|
1335
1543
|
declare function forType<R extends Requirement>(type: R["type"]): (req: Requirement) => req is R;
|
|
1336
1544
|
declare function forType<T extends string>(type: T): (req: Requirement) => req is Requirement & {
|
|
1337
1545
|
type: T;
|
|
1338
1546
|
};
|
|
1339
1547
|
/**
|
|
1340
|
-
* A
|
|
1548
|
+
* A deduplicated collection of {@link RequirementWithId} entries keyed by
|
|
1549
|
+
* their identity string.
|
|
1341
1550
|
*
|
|
1342
|
-
*
|
|
1343
|
-
*
|
|
1551
|
+
* @remarks
|
|
1552
|
+
* Requirements are uniquely identified by their ID (generated from type +
|
|
1553
|
+
* properties via {@link generateRequirementId}). When adding a requirement
|
|
1554
|
+
* whose ID already exists, the first entry wins and the duplicate is
|
|
1555
|
+
* silently ignored. The {@link RequirementSet.diff | diff} method computes
|
|
1556
|
+
* added, removed, and unchanged entries relative to another set, which the
|
|
1557
|
+
* engine uses during reconciliation.
|
|
1344
1558
|
*
|
|
1345
1559
|
* @example
|
|
1346
1560
|
* ```typescript
|
|
1347
1561
|
* const set = new RequirementSet();
|
|
1348
|
-
*
|
|
1349
|
-
* //
|
|
1350
|
-
* set.add(createRequirementWithId({ type: "FETCH_USER", userId: 1 }, "constraint1"));
|
|
1351
|
-
* set.add(createRequirementWithId({ type: "FETCH_USER", userId: 1 }, "constraint2")); // Ignored (duplicate)
|
|
1352
|
-
*
|
|
1353
|
-
* // Check and retrieve
|
|
1562
|
+
* set.add(createRequirementWithId({ type: "FETCH_USER", userId: 1 }, "c1"));
|
|
1563
|
+
* set.add(createRequirementWithId({ type: "FETCH_USER", userId: 1 }, "c2")); // ignored
|
|
1354
1564
|
* console.log(set.size); // 1
|
|
1355
|
-
*
|
|
1356
|
-
*
|
|
1357
|
-
*
|
|
1358
|
-
* const
|
|
1359
|
-
*
|
|
1360
|
-
* const { added, removed } = newSet.diff(set);
|
|
1361
|
-
* // added: [{ type: "FETCH_USER", userId: 2 }]
|
|
1362
|
-
* // removed: [{ type: "FETCH_USER", userId: 1 }]
|
|
1565
|
+
*
|
|
1566
|
+
* const next = new RequirementSet();
|
|
1567
|
+
* next.add(createRequirementWithId({ type: "FETCH_USER", userId: 2 }, "c1"));
|
|
1568
|
+
* const { added, removed } = next.diff(set);
|
|
1569
|
+
* // added has userId: 2, removed has userId: 1
|
|
1363
1570
|
* ```
|
|
1571
|
+
*
|
|
1572
|
+
* @public
|
|
1364
1573
|
*/
|
|
1365
1574
|
declare class RequirementSet {
|
|
1366
1575
|
private map;
|
|
1367
1576
|
/**
|
|
1368
|
-
* Add a requirement to the set.
|
|
1369
|
-
*
|
|
1370
|
-
* @param req - The requirement with its computed ID
|
|
1577
|
+
* Add a requirement to the set (first-wins deduplication).
|
|
1578
|
+
*
|
|
1579
|
+
* @param req - The requirement with its computed ID to insert.
|
|
1371
1580
|
*/
|
|
1372
1581
|
add(req: RequirementWithId): void;
|
|
1373
|
-
/**
|
|
1582
|
+
/**
|
|
1583
|
+
* Remove a requirement by its identity string.
|
|
1584
|
+
*
|
|
1585
|
+
* @param id - The requirement identity string to remove.
|
|
1586
|
+
* @returns `true` if the requirement existed and was removed.
|
|
1587
|
+
*/
|
|
1374
1588
|
remove(id: string): boolean;
|
|
1375
|
-
/**
|
|
1589
|
+
/**
|
|
1590
|
+
* Check whether a requirement with the given ID is in the set.
|
|
1591
|
+
*
|
|
1592
|
+
* @param id - The requirement identity string to look up.
|
|
1593
|
+
* @returns `true` if the set contains a requirement with this ID.
|
|
1594
|
+
*/
|
|
1376
1595
|
has(id: string): boolean;
|
|
1377
|
-
/**
|
|
1596
|
+
/**
|
|
1597
|
+
* Retrieve a requirement by its identity string.
|
|
1598
|
+
*
|
|
1599
|
+
* @param id - The requirement identity string to look up.
|
|
1600
|
+
* @returns The matching requirement, or `undefined` if not found.
|
|
1601
|
+
*/
|
|
1378
1602
|
get(id: string): RequirementWithId | undefined;
|
|
1379
|
-
/**
|
|
1603
|
+
/**
|
|
1604
|
+
* Return a snapshot array of all requirements in the set.
|
|
1605
|
+
*
|
|
1606
|
+
* @returns A new array containing every {@link RequirementWithId} in insertion order.
|
|
1607
|
+
*/
|
|
1380
1608
|
all(): RequirementWithId[];
|
|
1381
|
-
/**
|
|
1609
|
+
/**
|
|
1610
|
+
* Return a snapshot array of all requirement identity strings.
|
|
1611
|
+
*
|
|
1612
|
+
* @returns A new array of ID strings in insertion order.
|
|
1613
|
+
*/
|
|
1382
1614
|
ids(): string[];
|
|
1383
|
-
/**
|
|
1615
|
+
/**
|
|
1616
|
+
* The number of requirements currently in the set.
|
|
1617
|
+
*/
|
|
1384
1618
|
get size(): number;
|
|
1385
|
-
/**
|
|
1619
|
+
/**
|
|
1620
|
+
* Remove all requirements from the set.
|
|
1621
|
+
*/
|
|
1386
1622
|
clear(): void;
|
|
1387
|
-
/**
|
|
1623
|
+
/**
|
|
1624
|
+
* Create a shallow copy of this set.
|
|
1625
|
+
*
|
|
1626
|
+
* @returns A new {@link RequirementSet} containing the same entries.
|
|
1627
|
+
*/
|
|
1388
1628
|
clone(): RequirementSet;
|
|
1389
|
-
/**
|
|
1629
|
+
/**
|
|
1630
|
+
* Compute the difference between this set and another.
|
|
1631
|
+
*
|
|
1632
|
+
* @param other - The previous set to compare against.
|
|
1633
|
+
* @returns An object with `added` (in this but not other), `removed` (in other but not this), and `unchanged` arrays.
|
|
1634
|
+
*/
|
|
1390
1635
|
diff(other: RequirementSet): {
|
|
1391
1636
|
added: RequirementWithId[];
|
|
1392
1637
|
removed: RequirementWithId[];
|
|
@@ -1491,44 +1736,126 @@ declare function createDerivationsManager<S extends Schema, D extends Derivation
|
|
|
1491
1736
|
* ```
|
|
1492
1737
|
*/
|
|
1493
1738
|
|
|
1739
|
+
/**
|
|
1740
|
+
* Manager returned by {@link createEffectsManager} that runs fire-and-forget
|
|
1741
|
+
* side effects after facts stabilize.
|
|
1742
|
+
*
|
|
1743
|
+
* @internal
|
|
1744
|
+
*/
|
|
1494
1745
|
interface EffectsManager<_S extends Schema = Schema> {
|
|
1495
|
-
/**
|
|
1746
|
+
/**
|
|
1747
|
+
* Run all effects whose tracked dependencies overlap with `changedKeys`.
|
|
1748
|
+
*
|
|
1749
|
+
* @remarks
|
|
1750
|
+
* Effects with no recorded dependencies (first run or auto-tracked with no
|
|
1751
|
+
* reads) run on any change. After execution, a snapshot of current facts is
|
|
1752
|
+
* stored for the `prev` parameter on the next invocation.
|
|
1753
|
+
*
|
|
1754
|
+
* @param changedKeys - Fact keys that changed since the last run.
|
|
1755
|
+
*/
|
|
1496
1756
|
runEffects(changedKeys: Set<string>): Promise<void>;
|
|
1497
|
-
/**
|
|
1757
|
+
/**
|
|
1758
|
+
* Run every enabled effect unconditionally, regardless of dependencies.
|
|
1759
|
+
*/
|
|
1498
1760
|
runAll(): Promise<void>;
|
|
1499
|
-
/**
|
|
1761
|
+
/**
|
|
1762
|
+
* Disable an effect so it is skipped during subsequent runs.
|
|
1763
|
+
*
|
|
1764
|
+
* @param id - The effect definition ID.
|
|
1765
|
+
*/
|
|
1500
1766
|
disable(id: string): void;
|
|
1501
|
-
/**
|
|
1767
|
+
/**
|
|
1768
|
+
* Re-enable a previously disabled effect.
|
|
1769
|
+
*
|
|
1770
|
+
* @param id - The effect definition ID.
|
|
1771
|
+
*/
|
|
1502
1772
|
enable(id: string): void;
|
|
1503
|
-
/**
|
|
1773
|
+
/**
|
|
1774
|
+
* Check whether an effect is currently enabled.
|
|
1775
|
+
*
|
|
1776
|
+
* @param id - The effect definition ID.
|
|
1777
|
+
* @returns `true` if the effect has not been disabled.
|
|
1778
|
+
*/
|
|
1504
1779
|
isEnabled(id: string): boolean;
|
|
1505
|
-
/**
|
|
1780
|
+
/**
|
|
1781
|
+
* Invoke every stored cleanup function and mark the manager as stopped.
|
|
1782
|
+
*
|
|
1783
|
+
* @remarks
|
|
1784
|
+
* After this call, any cleanup functions returned by in-flight async effects
|
|
1785
|
+
* will be invoked immediately rather than stored.
|
|
1786
|
+
*/
|
|
1506
1787
|
cleanupAll(): void;
|
|
1507
|
-
/**
|
|
1788
|
+
/**
|
|
1789
|
+
* Register additional effect definitions at runtime (used for dynamic
|
|
1790
|
+
* module registration).
|
|
1791
|
+
*
|
|
1792
|
+
* @param newDefs - New effect definitions to merge into the manager.
|
|
1793
|
+
*/
|
|
1508
1794
|
registerDefinitions(newDefs: EffectsDef<Schema>): void;
|
|
1509
1795
|
}
|
|
1510
|
-
/**
|
|
1796
|
+
/**
|
|
1797
|
+
* Configuration options accepted by {@link createEffectsManager}.
|
|
1798
|
+
*
|
|
1799
|
+
* @internal
|
|
1800
|
+
*/
|
|
1511
1801
|
interface CreateEffectsOptions<S extends Schema> {
|
|
1802
|
+
/** Effect definitions keyed by ID. */
|
|
1512
1803
|
definitions: EffectsDef<S>;
|
|
1804
|
+
/** Proxy-based facts object passed to effect `run()` functions. */
|
|
1513
1805
|
facts: Facts<S>;
|
|
1806
|
+
/** Underlying fact store used for `batch()` coalescing of mutations. */
|
|
1514
1807
|
store: FactsStore<S>;
|
|
1515
|
-
/**
|
|
1808
|
+
/** Called when an effect executes, with the fact keys that triggered it. */
|
|
1516
1809
|
onRun?: (id: string, deps: string[]) => void;
|
|
1517
|
-
/**
|
|
1810
|
+
/** Called when an effect's `run()` or cleanup function throws. */
|
|
1518
1811
|
onError?: (id: string, error: unknown) => void;
|
|
1519
1812
|
}
|
|
1520
1813
|
/**
|
|
1521
1814
|
* Create a manager for fire-and-forget side effects that run after facts
|
|
1522
1815
|
* stabilize.
|
|
1523
1816
|
*
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
1528
|
-
*
|
|
1817
|
+
* @remarks
|
|
1818
|
+
* Effects support two dependency modes:
|
|
1819
|
+
*
|
|
1820
|
+
* - **Auto-tracked** (no `deps`): Dependencies are re-tracked on every run
|
|
1821
|
+
* via {@link withTracking}, so conditional fact reads are always captured.
|
|
1822
|
+
* Only synchronous reads are tracked; reads after an `await` are invisible.
|
|
1823
|
+
*
|
|
1824
|
+
* - **Explicit `deps`**: A fixed array of fact keys declared on the definition.
|
|
1825
|
+
* Preferred for async effects where auto-tracking cannot cross `await`
|
|
1826
|
+
* boundaries.
|
|
1827
|
+
*
|
|
1828
|
+
* Each effect can return a cleanup function that runs before the next
|
|
1829
|
+
* execution or when {@link EffectsManager.cleanupAll | cleanupAll} is called.
|
|
1830
|
+
* Errors in effects are isolated via try-catch and never break the
|
|
1831
|
+
* reconciliation loop. Synchronous fact mutations inside effects are
|
|
1832
|
+
* coalesced with `store.batch()`.
|
|
1833
|
+
*
|
|
1834
|
+
* @param options - Configuration including effect definitions, facts proxy,
|
|
1835
|
+
* store, and lifecycle callbacks.
|
|
1836
|
+
* @returns An {@link EffectsManager} for running, enabling/disabling, and
|
|
1837
|
+
* cleaning up effects.
|
|
1838
|
+
*
|
|
1839
|
+
* @example
|
|
1840
|
+
* ```typescript
|
|
1841
|
+
* const effects = createEffectsManager({
|
|
1842
|
+
* definitions: {
|
|
1843
|
+
* logPhase: {
|
|
1844
|
+
* run: (facts, prev) => {
|
|
1845
|
+
* if (prev?.phase !== facts.phase) {
|
|
1846
|
+
* console.log(`Phase changed to ${facts.phase}`);
|
|
1847
|
+
* }
|
|
1848
|
+
* },
|
|
1849
|
+
* },
|
|
1850
|
+
* },
|
|
1851
|
+
* facts: factsProxy,
|
|
1852
|
+
* store: factsStore,
|
|
1853
|
+
* });
|
|
1854
|
+
*
|
|
1855
|
+
* await effects.runEffects(new Set(["phase"]));
|
|
1856
|
+
* ```
|
|
1529
1857
|
*
|
|
1530
|
-
* @
|
|
1531
|
-
* @returns An `EffectsManager` with runEffects/runAll/enable/disable/cleanupAll methods
|
|
1858
|
+
* @internal
|
|
1532
1859
|
*/
|
|
1533
1860
|
declare function createEffectsManager<S extends Schema>(options: CreateEffectsOptions<S>): EffectsManager<S>;
|
|
1534
1861
|
|
|
@@ -1542,54 +1869,155 @@ declare function createEffectsManager<S extends Schema>(options: CreateEffectsOp
|
|
|
1542
1869
|
* - Error isolation
|
|
1543
1870
|
*/
|
|
1544
1871
|
|
|
1872
|
+
/**
|
|
1873
|
+
* Manager returned by {@link createConstraintsManager} that evaluates
|
|
1874
|
+
* constraint rules against the current facts and produces unmet
|
|
1875
|
+
* {@link RequirementWithId | requirements}.
|
|
1876
|
+
*
|
|
1877
|
+
* @internal
|
|
1878
|
+
*/
|
|
1545
1879
|
interface ConstraintsManager<_S extends Schema> {
|
|
1546
|
-
/**
|
|
1880
|
+
/**
|
|
1881
|
+
* Evaluate all enabled constraints and return unmet requirements.
|
|
1882
|
+
*
|
|
1883
|
+
* @remarks
|
|
1884
|
+
* On the first call (or when `changedKeys` is empty), every enabled
|
|
1885
|
+
* constraint is evaluated. On subsequent calls, only constraints whose
|
|
1886
|
+
* tracked dependencies overlap with `changedKeys` are re-evaluated.
|
|
1887
|
+
* Sync constraints run first, async constraints run in parallel, and
|
|
1888
|
+
* `after` ordering is respected across multiple passes.
|
|
1889
|
+
*
|
|
1890
|
+
* @param changedKeys - Fact keys that changed since the last evaluation.
|
|
1891
|
+
* When omitted or empty, all constraints are evaluated.
|
|
1892
|
+
* @returns An array of {@link RequirementWithId} representing unmet requirements.
|
|
1893
|
+
*/
|
|
1547
1894
|
evaluate(changedKeys?: Set<string>): Promise<RequirementWithId[]>;
|
|
1548
|
-
/**
|
|
1895
|
+
/**
|
|
1896
|
+
* Get the current state of a constraint by its definition ID.
|
|
1897
|
+
*
|
|
1898
|
+
* @param id - The constraint definition ID.
|
|
1899
|
+
* @returns The {@link ConstraintState}, or `undefined` if the ID is unknown.
|
|
1900
|
+
*/
|
|
1549
1901
|
getState(id: string): ConstraintState | undefined;
|
|
1550
|
-
/**
|
|
1902
|
+
/**
|
|
1903
|
+
* Get the state of every registered constraint.
|
|
1904
|
+
*
|
|
1905
|
+
* @returns An array of all {@link ConstraintState} objects.
|
|
1906
|
+
*/
|
|
1551
1907
|
getAllStates(): ConstraintState[];
|
|
1552
|
-
/**
|
|
1908
|
+
/**
|
|
1909
|
+
* Disable a constraint so it is skipped during evaluation.
|
|
1910
|
+
*
|
|
1911
|
+
* @param id - The constraint definition ID.
|
|
1912
|
+
*/
|
|
1553
1913
|
disable(id: string): void;
|
|
1554
|
-
/**
|
|
1914
|
+
/**
|
|
1915
|
+
* Re-enable a previously disabled constraint.
|
|
1916
|
+
*
|
|
1917
|
+
* @param id - The constraint definition ID.
|
|
1918
|
+
*/
|
|
1555
1919
|
enable(id: string): void;
|
|
1556
|
-
/**
|
|
1920
|
+
/**
|
|
1921
|
+
* Mark all constraints that depend on `factKey` as dirty so they are
|
|
1922
|
+
* re-evaluated on the next {@link ConstraintsManager.evaluate | evaluate} call.
|
|
1923
|
+
*
|
|
1924
|
+
* @param factKey - The fact store key that changed.
|
|
1925
|
+
*/
|
|
1557
1926
|
invalidate(factKey: string): void;
|
|
1558
|
-
/**
|
|
1927
|
+
/**
|
|
1928
|
+
* Get the auto-tracked or explicit dependency set for a constraint.
|
|
1929
|
+
*
|
|
1930
|
+
* @param id - The constraint definition ID.
|
|
1931
|
+
* @returns A `Set` of fact keys, or `undefined` if no dependencies have been recorded.
|
|
1932
|
+
*/
|
|
1559
1933
|
getDependencies(id: string): Set<string> | undefined;
|
|
1560
|
-
/**
|
|
1934
|
+
/**
|
|
1935
|
+
* Record that a constraint's resolver completed successfully, unblocking
|
|
1936
|
+
* any constraints that list it in their `after` array.
|
|
1937
|
+
*
|
|
1938
|
+
* @param constraintId - The constraint definition ID whose resolver finished.
|
|
1939
|
+
*/
|
|
1561
1940
|
markResolved(constraintId: string): void;
|
|
1562
|
-
/**
|
|
1941
|
+
/**
|
|
1942
|
+
* Check whether a constraint is currently disabled.
|
|
1943
|
+
*
|
|
1944
|
+
* @param id - The constraint definition ID.
|
|
1945
|
+
* @returns `true` if the constraint has been disabled via {@link ConstraintsManager.disable | disable}.
|
|
1946
|
+
*/
|
|
1563
1947
|
isDisabled(id: string): boolean;
|
|
1564
|
-
/**
|
|
1948
|
+
/**
|
|
1949
|
+
* Check whether a constraint has been marked as resolved.
|
|
1950
|
+
*
|
|
1951
|
+
* @param constraintId - The constraint definition ID.
|
|
1952
|
+
* @returns `true` if {@link ConstraintsManager.markResolved | markResolved} was called for this constraint.
|
|
1953
|
+
*/
|
|
1565
1954
|
isResolved(constraintId: string): boolean;
|
|
1566
|
-
/**
|
|
1955
|
+
/**
|
|
1956
|
+
* Register additional constraint definitions at runtime (used for dynamic
|
|
1957
|
+
* module registration).
|
|
1958
|
+
*
|
|
1959
|
+
* @remarks
|
|
1960
|
+
* Rebuilds the topological order and reverse dependency map so new `after`
|
|
1961
|
+
* dependencies are validated for cycles and indexed.
|
|
1962
|
+
*
|
|
1963
|
+
* @param newDefs - New constraint definitions to merge into the manager.
|
|
1964
|
+
*/
|
|
1567
1965
|
registerDefinitions(newDefs: ConstraintsDef<Schema>): void;
|
|
1568
1966
|
}
|
|
1569
|
-
/**
|
|
1967
|
+
/**
|
|
1968
|
+
* Configuration options accepted by {@link createConstraintsManager}.
|
|
1969
|
+
*
|
|
1970
|
+
* @internal
|
|
1971
|
+
*/
|
|
1570
1972
|
interface CreateConstraintsOptions<S extends Schema> {
|
|
1973
|
+
/** Constraint definitions keyed by ID. */
|
|
1571
1974
|
definitions: ConstraintsDef<S>;
|
|
1975
|
+
/** Proxy-based facts object used to evaluate `when()` predicates. */
|
|
1572
1976
|
facts: Facts<S>;
|
|
1573
|
-
/** Custom key functions for
|
|
1977
|
+
/** Custom key functions for requirement deduplication, keyed by constraint ID. */
|
|
1574
1978
|
requirementKeys?: Record<string, RequirementKeyFn>;
|
|
1575
|
-
/** Default timeout for async
|
|
1979
|
+
/** Default timeout in milliseconds for async constraint evaluation (defaults to 5 000). */
|
|
1576
1980
|
defaultTimeout?: number;
|
|
1577
|
-
/**
|
|
1981
|
+
/** Called after each constraint evaluation with the constraint ID and whether `when()` was active. */
|
|
1578
1982
|
onEvaluate?: (id: string, active: boolean) => void;
|
|
1579
|
-
/**
|
|
1983
|
+
/** Called when a constraint's `when()` or `require()` throws. */
|
|
1580
1984
|
onError?: (id: string, error: unknown) => void;
|
|
1581
1985
|
}
|
|
1582
1986
|
/**
|
|
1583
1987
|
* Create a manager that evaluates constraint rules and produces unmet
|
|
1584
1988
|
* requirements.
|
|
1585
1989
|
*
|
|
1586
|
-
*
|
|
1990
|
+
* @remarks
|
|
1991
|
+
* Constraints are evaluated in priority order (higher priority first), with
|
|
1587
1992
|
* topological ordering for same-priority constraints connected by `after`
|
|
1588
|
-
* dependencies.
|
|
1589
|
-
* evaluation based on changed fact keys, and per-constraint
|
|
1993
|
+
* dependencies. The manager supports sync and async `when()` predicates,
|
|
1994
|
+
* incremental evaluation based on changed fact keys, and per-constraint
|
|
1995
|
+
* enable/disable toggling. Cycle detection runs eagerly at construction time
|
|
1996
|
+
* to prevent deadlocks in production.
|
|
1997
|
+
*
|
|
1998
|
+
* @param options - Configuration including constraint definitions, facts proxy,
|
|
1999
|
+
* custom requirement key functions, and lifecycle callbacks.
|
|
2000
|
+
* @returns A {@link ConstraintsManager} for evaluating, invalidating, and
|
|
2001
|
+
* managing constraint lifecycle.
|
|
2002
|
+
*
|
|
2003
|
+
* @example
|
|
2004
|
+
* ```typescript
|
|
2005
|
+
* const constraints = createConstraintsManager({
|
|
2006
|
+
* definitions: {
|
|
2007
|
+
* mustTransition: {
|
|
2008
|
+
* priority: 50,
|
|
2009
|
+
* when: (facts) => facts.phase === "red" && facts.elapsed > 30,
|
|
2010
|
+
* require: { type: "TRANSITION", to: "green" },
|
|
2011
|
+
* },
|
|
2012
|
+
* },
|
|
2013
|
+
* facts: factsProxy,
|
|
2014
|
+
* onEvaluate: (id, active) => console.log(id, active),
|
|
2015
|
+
* });
|
|
1590
2016
|
*
|
|
1591
|
-
*
|
|
1592
|
-
*
|
|
2017
|
+
* const unmet = await constraints.evaluate();
|
|
2018
|
+
* ```
|
|
2019
|
+
*
|
|
2020
|
+
* @internal
|
|
1593
2021
|
*/
|
|
1594
2022
|
declare function createConstraintsManager<S extends Schema>(options: CreateConstraintsOptions<S>): ConstraintsManager<S>;
|
|
1595
2023
|
|
|
@@ -1604,64 +2032,171 @@ declare function createConstraintsManager<S extends Schema>(options: CreateConst
|
|
|
1604
2032
|
* - Cancellation via AbortController
|
|
1605
2033
|
*/
|
|
1606
2034
|
|
|
1607
|
-
/**
|
|
2035
|
+
/**
|
|
2036
|
+
* Summary of a resolver that is currently in flight.
|
|
2037
|
+
*
|
|
2038
|
+
* @internal
|
|
2039
|
+
*/
|
|
1608
2040
|
interface InflightInfo {
|
|
2041
|
+
/** The unique requirement ID being resolved. */
|
|
1609
2042
|
id: string;
|
|
2043
|
+
/** The definition ID of the resolver handling this requirement. */
|
|
1610
2044
|
resolverId: string;
|
|
2045
|
+
/** Epoch timestamp (ms) when resolution started. */
|
|
1611
2046
|
startedAt: number;
|
|
1612
2047
|
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Manager returned by {@link createResolversManager} that matches
|
|
2050
|
+
* requirements to resolver handlers and manages their execution lifecycle.
|
|
2051
|
+
*
|
|
2052
|
+
* @internal
|
|
2053
|
+
*/
|
|
1613
2054
|
interface ResolversManager<_S extends Schema> {
|
|
1614
|
-
/**
|
|
2055
|
+
/**
|
|
2056
|
+
* Start resolving a requirement by matching it to a resolver handler.
|
|
2057
|
+
*
|
|
2058
|
+
* @remarks
|
|
2059
|
+
* Duplicate in-flight requirements (same `req.id`) are silently ignored.
|
|
2060
|
+
* If the matched resolver has `batch.enabled`, the requirement is queued
|
|
2061
|
+
* for batch processing instead of being resolved immediately.
|
|
2062
|
+
*
|
|
2063
|
+
* @param req - The requirement (with a stable identity ID) to resolve.
|
|
2064
|
+
*/
|
|
1615
2065
|
resolve(req: RequirementWithId): void;
|
|
1616
|
-
/**
|
|
2066
|
+
/**
|
|
2067
|
+
* Cancel an in-flight or batch-queued resolver by requirement ID.
|
|
2068
|
+
*
|
|
2069
|
+
* @remarks
|
|
2070
|
+
* Aborts the `AbortController` for in-flight resolvers. For batch-queued
|
|
2071
|
+
* requirements, removes the requirement from the pending batch.
|
|
2072
|
+
*
|
|
2073
|
+
* @param requirementId - The unique requirement ID to cancel.
|
|
2074
|
+
*/
|
|
1617
2075
|
cancel(requirementId: string): void;
|
|
1618
|
-
/**
|
|
2076
|
+
/**
|
|
2077
|
+
* Cancel every in-flight resolver and flush all pending batch queues.
|
|
2078
|
+
*/
|
|
1619
2079
|
cancelAll(): void;
|
|
1620
|
-
/**
|
|
2080
|
+
/**
|
|
2081
|
+
* Get the current status of a resolver by requirement ID.
|
|
2082
|
+
*
|
|
2083
|
+
* @param requirementId - The unique requirement ID to look up.
|
|
2084
|
+
* @returns The {@link ResolverStatus} (idle, pending, running, success, error, or canceled).
|
|
2085
|
+
*/
|
|
1621
2086
|
getStatus(requirementId: string): ResolverStatus;
|
|
1622
|
-
/**
|
|
2087
|
+
/**
|
|
2088
|
+
* Get the requirement IDs of all currently in-flight resolvers.
|
|
2089
|
+
*
|
|
2090
|
+
* @returns An array of requirement ID strings.
|
|
2091
|
+
*/
|
|
1623
2092
|
getInflight(): string[];
|
|
1624
|
-
/**
|
|
2093
|
+
/**
|
|
2094
|
+
* Get detailed info for every in-flight resolver.
|
|
2095
|
+
*
|
|
2096
|
+
* @returns An array of {@link InflightInfo} objects.
|
|
2097
|
+
*/
|
|
1625
2098
|
getInflightInfo(): InflightInfo[];
|
|
1626
|
-
/**
|
|
2099
|
+
/**
|
|
2100
|
+
* Check whether a requirement is currently being resolved.
|
|
2101
|
+
*
|
|
2102
|
+
* @param requirementId - The unique requirement ID to check.
|
|
2103
|
+
* @returns `true` if the requirement has an active in-flight resolver.
|
|
2104
|
+
*/
|
|
1627
2105
|
isResolving(requirementId: string): boolean;
|
|
1628
|
-
/**
|
|
2106
|
+
/**
|
|
2107
|
+
* Immediately flush all pending batch queues, executing their resolvers.
|
|
2108
|
+
*/
|
|
1629
2109
|
processBatches(): void;
|
|
1630
|
-
/**
|
|
2110
|
+
/**
|
|
2111
|
+
* Check whether any batch queues have requirements waiting to be processed.
|
|
2112
|
+
*
|
|
2113
|
+
* @returns `true` if at least one batch queue is non-empty.
|
|
2114
|
+
*/
|
|
1631
2115
|
hasPendingBatches(): boolean;
|
|
1632
|
-
/**
|
|
2116
|
+
/**
|
|
2117
|
+
* Register additional resolver definitions at runtime (used for dynamic
|
|
2118
|
+
* module registration).
|
|
2119
|
+
*
|
|
2120
|
+
* @remarks
|
|
2121
|
+
* Clears the resolver-by-type cache so newly registered resolvers are
|
|
2122
|
+
* discoverable on the next {@link ResolversManager.resolve | resolve} call.
|
|
2123
|
+
*
|
|
2124
|
+
* @param newDefs - New resolver definitions to merge into the manager.
|
|
2125
|
+
*/
|
|
1633
2126
|
registerDefinitions(newDefs: ResolversDef<Schema>): void;
|
|
1634
2127
|
}
|
|
1635
|
-
/**
|
|
2128
|
+
/**
|
|
2129
|
+
* Configuration options accepted by {@link createResolversManager}.
|
|
2130
|
+
*
|
|
2131
|
+
* @internal
|
|
2132
|
+
*/
|
|
1636
2133
|
interface CreateResolversOptions<S extends Schema> {
|
|
2134
|
+
/** Resolver definitions keyed by ID. */
|
|
1637
2135
|
definitions: ResolversDef<S>;
|
|
2136
|
+
/** Proxy-based facts object passed to resolver contexts. */
|
|
1638
2137
|
facts: Facts<S>;
|
|
2138
|
+
/** Underlying fact store used for `batch()` coalescing of mutations. */
|
|
1639
2139
|
store: FactsStore<S>;
|
|
1640
|
-
/**
|
|
2140
|
+
/** Called when a resolver begins execution. */
|
|
1641
2141
|
onStart?: (resolver: string, req: RequirementWithId) => void;
|
|
1642
|
-
/**
|
|
2142
|
+
/** Called when a resolver completes successfully, with the wall-clock duration in ms. */
|
|
1643
2143
|
onComplete?: (resolver: string, req: RequirementWithId, duration: number) => void;
|
|
1644
|
-
/**
|
|
2144
|
+
/** Called when a resolver exhausts all retry attempts. */
|
|
1645
2145
|
onError?: (resolver: string, req: RequirementWithId, error: unknown) => void;
|
|
1646
|
-
/**
|
|
2146
|
+
/** Called before each retry attempt with the upcoming attempt number. */
|
|
1647
2147
|
onRetry?: (resolver: string, req: RequirementWithId, attempt: number) => void;
|
|
1648
|
-
/**
|
|
2148
|
+
/** Called when a resolver is canceled via {@link ResolversManager.cancel | cancel}. */
|
|
1649
2149
|
onCancel?: (resolver: string, req: RequirementWithId) => void;
|
|
1650
|
-
/**
|
|
2150
|
+
/** Called after any resolver finishes (success, error, or batch completion) to trigger reconciliation. */
|
|
1651
2151
|
onResolutionComplete?: () => void;
|
|
1652
2152
|
}
|
|
1653
2153
|
/**
|
|
1654
2154
|
* Create a manager that fulfills requirements by matching them to resolver
|
|
1655
2155
|
* handlers.
|
|
1656
2156
|
*
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1661
|
-
*
|
|
2157
|
+
* @remarks
|
|
2158
|
+
* Resolvers are matched by requirement type (string equality) or a predicate
|
|
2159
|
+
* function. Each resolution runs with an `AbortController` for cancellation
|
|
2160
|
+
* and configurable retry policies (none, linear, or exponential backoff).
|
|
2161
|
+
*
|
|
2162
|
+
* **Batching:** When a resolver sets `batch.enabled`, incoming requirements
|
|
2163
|
+
* are queued and flushed either when `batch.maxSize` is reached or after
|
|
2164
|
+
* `batch.windowMs` elapses, whichever comes first. Batch resolvers can use
|
|
2165
|
+
* `resolveBatch` (all-or-nothing) or `resolveBatchWithResults` (per-item
|
|
2166
|
+
* success/failure). If only `resolve` is provided with batching enabled, the
|
|
2167
|
+
* manager falls back to individual resolution calls.
|
|
2168
|
+
*
|
|
2169
|
+
* Duplicate in-flight requirements (same requirement ID) are automatically
|
|
2170
|
+
* deduplicated. Resolver-by-type lookups are cached with FIFO eviction at
|
|
2171
|
+
* 1 000 entries to handle dynamic requirement types.
|
|
2172
|
+
*
|
|
2173
|
+
* @param options - Configuration including resolver definitions, facts proxy,
|
|
2174
|
+
* store, and lifecycle callbacks.
|
|
2175
|
+
* @returns A {@link ResolversManager} for dispatching, canceling, and
|
|
2176
|
+
* inspecting requirement resolution.
|
|
2177
|
+
*
|
|
2178
|
+
* @example
|
|
2179
|
+
* ```typescript
|
|
2180
|
+
* const resolvers = createResolversManager({
|
|
2181
|
+
* definitions: {
|
|
2182
|
+
* transition: {
|
|
2183
|
+
* requirement: "TRANSITION",
|
|
2184
|
+
* retry: { attempts: 3, backoff: "exponential" },
|
|
2185
|
+
* resolve: async (req, context) => {
|
|
2186
|
+
* context.facts.phase = req.to;
|
|
2187
|
+
* context.facts.elapsed = 0;
|
|
2188
|
+
* },
|
|
2189
|
+
* },
|
|
2190
|
+
* },
|
|
2191
|
+
* facts: factsProxy,
|
|
2192
|
+
* store: factsStore,
|
|
2193
|
+
* onComplete: (id, req, ms) => console.log(`${id} resolved in ${ms}ms`),
|
|
2194
|
+
* });
|
|
2195
|
+
*
|
|
2196
|
+
* resolvers.resolve(requirementWithId);
|
|
2197
|
+
* ```
|
|
1662
2198
|
*
|
|
1663
|
-
* @
|
|
1664
|
-
* @returns A `ResolversManager` with resolve/cancel/cancelAll/getStatus/processBatches methods
|
|
2199
|
+
* @internal
|
|
1665
2200
|
*/
|
|
1666
2201
|
declare function createResolversManager<S extends Schema>(options: CreateResolversOptions<S>): ResolversManager<S>;
|
|
1667
2202
|
|
|
@@ -1674,6 +2209,35 @@ declare function createResolversManager<S extends Schema>(options: CreateResolve
|
|
|
1674
2209
|
* - Plugins execute in registration order
|
|
1675
2210
|
*/
|
|
1676
2211
|
|
|
2212
|
+
/**
|
|
2213
|
+
* Internal manager that broadcasts lifecycle events to registered {@link Plugin} instances.
|
|
2214
|
+
*
|
|
2215
|
+
* @remarks
|
|
2216
|
+
* PluginManager uses `Schema` (flat) internally because the engine works with
|
|
2217
|
+
* flat schemas. The public API uses `ModuleSchema` (consolidated), and the
|
|
2218
|
+
* conversion happens in `createSystem`.
|
|
2219
|
+
*
|
|
2220
|
+
* Plugins execute in registration order. All hook invocations are wrapped in
|
|
2221
|
+
* try-catch so a misbehaving plugin never breaks the engine. Duplicate plugin
|
|
2222
|
+
* names are detected and the older registration is replaced with a warning.
|
|
2223
|
+
*
|
|
2224
|
+
* Lifecycle hook categories:
|
|
2225
|
+
* - **System lifecycle:** `emitInit`, `emitStart`, `emitStop`, `emitDestroy`
|
|
2226
|
+
* - **Facts:** `emitFactSet`, `emitFactDelete`, `emitFactsBatch`
|
|
2227
|
+
* - **Derivations:** `emitDerivationCompute`, `emitDerivationInvalidate`
|
|
2228
|
+
* - **Reconciliation:** `emitReconcileStart`, `emitReconcileEnd`
|
|
2229
|
+
* - **Constraints:** `emitConstraintEvaluate`, `emitConstraintError`
|
|
2230
|
+
* - **Requirements:** `emitRequirementCreated`, `emitRequirementMet`, `emitRequirementCanceled`
|
|
2231
|
+
* - **Resolvers:** `emitResolverStart`, `emitResolverComplete`, `emitResolverError`, `emitResolverRetry`, `emitResolverCancel`
|
|
2232
|
+
* - **Effects:** `emitEffectRun`, `emitEffectError`
|
|
2233
|
+
* - **Time-travel:** `emitSnapshot`, `emitTimeTravel`
|
|
2234
|
+
* - **Errors:** `emitError`, `emitErrorRecovery`
|
|
2235
|
+
* - **Run history:** `emitRunComplete`
|
|
2236
|
+
*
|
|
2237
|
+
* @typeParam _S - The flat schema type (unused at runtime).
|
|
2238
|
+
*
|
|
2239
|
+
* @internal
|
|
2240
|
+
*/
|
|
1677
2241
|
interface PluginManager<_S extends Schema = any> {
|
|
1678
2242
|
/** Register a plugin */
|
|
1679
2243
|
register(plugin: Plugin<any>): void;
|
|
@@ -1711,14 +2275,17 @@ interface PluginManager<_S extends Schema = any> {
|
|
|
1711
2275
|
emitRunComplete(run: RunChangelogEntry): void;
|
|
1712
2276
|
}
|
|
1713
2277
|
/**
|
|
1714
|
-
* Create a
|
|
2278
|
+
* Create a {@link PluginManager} that broadcasts lifecycle events to registered plugins.
|
|
1715
2279
|
*
|
|
1716
|
-
*
|
|
1717
|
-
*
|
|
1718
|
-
*
|
|
1719
|
-
* replaced with a
|
|
2280
|
+
* @remarks
|
|
2281
|
+
* Plugins are called in registration order. All hook invocations are wrapped
|
|
2282
|
+
* in try-catch so a misbehaving plugin never breaks the engine. Duplicate
|
|
2283
|
+
* plugin names are detected and the older registration is replaced with a
|
|
2284
|
+
* console warning.
|
|
1720
2285
|
*
|
|
1721
|
-
* @returns A
|
|
2286
|
+
* @returns A {@link PluginManager} with `register`/`unregister`/`getPlugins` and `emit*` methods for every lifecycle event.
|
|
2287
|
+
*
|
|
2288
|
+
* @internal
|
|
1722
2289
|
*/
|
|
1723
2290
|
declare function createPluginManager<S extends Schema = any>(): PluginManager<S>;
|
|
1724
2291
|
|
|
@@ -1733,7 +2300,9 @@ declare function createPluginManager<S extends Schema = any>(): PluginManager<S>
|
|
|
1733
2300
|
*/
|
|
1734
2301
|
|
|
1735
2302
|
/**
|
|
1736
|
-
*
|
|
2303
|
+
* A queued retry entry tracking its source, attempt count, and scheduled time.
|
|
2304
|
+
*
|
|
2305
|
+
* @internal
|
|
1737
2306
|
*/
|
|
1738
2307
|
interface PendingRetry {
|
|
1739
2308
|
source: ErrorSource;
|
|
@@ -1746,13 +2315,18 @@ interface PendingRetry {
|
|
|
1746
2315
|
/**
|
|
1747
2316
|
* Create a manager for deferred retry scheduling with exponential backoff.
|
|
1748
2317
|
*
|
|
1749
|
-
*
|
|
1750
|
-
*
|
|
1751
|
-
*
|
|
1752
|
-
*
|
|
2318
|
+
* @remarks
|
|
2319
|
+
* Retries are stored in a Map keyed by source ID. Each entry tracks its
|
|
2320
|
+
* attempt number and the timestamp of the next eligible retry. When
|
|
2321
|
+
* {@link createRetryLaterManager | processDueRetries} is called (typically
|
|
2322
|
+
* during reconciliation), entries whose scheduled time has elapsed are
|
|
2323
|
+
* returned and removed from the queue. The delay grows exponentially:
|
|
2324
|
+
* `delayMs * backoffMultiplier^(attempt - 1)`, capped at `maxDelayMs`.
|
|
1753
2325
|
*
|
|
1754
|
-
* @param config - Backoff configuration
|
|
1755
|
-
* @returns A manager
|
|
2326
|
+
* @param config - Backoff configuration including `delayMs`, `maxRetries`, `backoffMultiplier`, and `maxDelayMs`.
|
|
2327
|
+
* @returns A manager exposing `scheduleRetry`, `getPendingRetries`, `processDueRetries`, `cancelRetry`, and `clearAll` methods.
|
|
2328
|
+
*
|
|
2329
|
+
* @internal
|
|
1756
2330
|
*/
|
|
1757
2331
|
declare function createRetryLaterManager(config?: RetryLaterConfig): {
|
|
1758
2332
|
/** Schedule a retry */
|
|
@@ -1766,57 +2340,92 @@ declare function createRetryLaterManager(config?: RetryLaterConfig): {
|
|
|
1766
2340
|
/** Clear all pending retries */
|
|
1767
2341
|
clearAll: () => void;
|
|
1768
2342
|
};
|
|
2343
|
+
/**
|
|
2344
|
+
* Handle returned by {@link createErrorBoundaryManager} for routing errors
|
|
2345
|
+
* through configurable recovery strategies.
|
|
2346
|
+
*
|
|
2347
|
+
* @internal
|
|
2348
|
+
*/
|
|
1769
2349
|
interface ErrorBoundaryManager {
|
|
1770
|
-
/**
|
|
2350
|
+
/**
|
|
2351
|
+
* Route an error through the configured recovery strategy for its source.
|
|
2352
|
+
*
|
|
2353
|
+
* @param source - The subsystem that produced the error.
|
|
2354
|
+
* @param sourceId - Identifier of the specific constraint, resolver, effect, or derivation.
|
|
2355
|
+
* @param error - The thrown value (coerced to {@link DirectiveError} internally).
|
|
2356
|
+
* @param context - Optional context forwarded to callbacks and retry entries.
|
|
2357
|
+
* @returns The {@link RecoveryStrategy} that was applied.
|
|
2358
|
+
*/
|
|
1771
2359
|
handleError(source: ErrorSource, sourceId: string, error: unknown, context?: unknown): RecoveryStrategy;
|
|
1772
|
-
/**
|
|
2360
|
+
/**
|
|
2361
|
+
* Return the most recently recorded error, or `null` if none exist.
|
|
2362
|
+
*
|
|
2363
|
+
* @returns The last {@link DirectiveError}, or `null`.
|
|
2364
|
+
*/
|
|
1773
2365
|
getLastError(): DirectiveError | null;
|
|
1774
|
-
/**
|
|
2366
|
+
/**
|
|
2367
|
+
* Return a snapshot array of all recorded errors (up to the last 100).
|
|
2368
|
+
*
|
|
2369
|
+
* @returns A shallow copy of the internal error ring buffer.
|
|
2370
|
+
*/
|
|
1775
2371
|
getAllErrors(): DirectiveError[];
|
|
1776
|
-
/** Clear all errors */
|
|
2372
|
+
/** Clear all recorded errors. */
|
|
1777
2373
|
clearErrors(): void;
|
|
1778
|
-
/**
|
|
2374
|
+
/**
|
|
2375
|
+
* Access the underlying retry-later manager for advanced scheduling.
|
|
2376
|
+
*
|
|
2377
|
+
* @returns The {@link createRetryLaterManager} instance used internally.
|
|
2378
|
+
*/
|
|
1779
2379
|
getRetryLaterManager(): ReturnType<typeof createRetryLaterManager>;
|
|
1780
|
-
/**
|
|
2380
|
+
/**
|
|
2381
|
+
* Drain and return retry entries whose scheduled time has elapsed.
|
|
2382
|
+
*
|
|
2383
|
+
* @returns An array of {@link PendingRetry} entries that are now due.
|
|
2384
|
+
*/
|
|
1781
2385
|
processDueRetries(): PendingRetry[];
|
|
1782
|
-
/**
|
|
2386
|
+
/**
|
|
2387
|
+
* Reset retry attempt tracking for a source, typically after a successful resolution.
|
|
2388
|
+
*
|
|
2389
|
+
* @param sourceId - The source identifier whose retry counter should be cleared.
|
|
2390
|
+
*/
|
|
1783
2391
|
clearRetryAttempts(sourceId: string): void;
|
|
1784
2392
|
}
|
|
1785
|
-
/**
|
|
2393
|
+
/**
|
|
2394
|
+
* Options accepted by {@link createErrorBoundaryManager}.
|
|
2395
|
+
*
|
|
2396
|
+
* @internal
|
|
2397
|
+
*/
|
|
1786
2398
|
interface CreateErrorBoundaryOptions {
|
|
2399
|
+
/** Per-source recovery strategies and retry-later tuning. */
|
|
1787
2400
|
config?: ErrorBoundaryConfig;
|
|
1788
|
-
/**
|
|
2401
|
+
/** Invoked every time an error is recorded, before the recovery strategy runs. */
|
|
1789
2402
|
onError?: (error: DirectiveError) => void;
|
|
1790
|
-
/**
|
|
2403
|
+
/** Invoked after a recovery strategy has been selected for an error. */
|
|
1791
2404
|
onRecovery?: (error: DirectiveError, strategy: RecoveryStrategy) => void;
|
|
1792
2405
|
}
|
|
1793
2406
|
/**
|
|
1794
2407
|
* Create a manager that handles errors from constraints, resolvers, effects,
|
|
1795
2408
|
* and derivations with configurable per-source recovery strategies.
|
|
1796
2409
|
*
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
* and `"throw"` (re-throw). Recent errors are kept in a ring buffer
|
|
1800
|
-
* (last 100) for inspection. The retry-later strategy delegates to an
|
|
1801
|
-
* internal {@link createRetryLaterManager}.
|
|
2410
|
+
* @remarks
|
|
2411
|
+
* Five recovery strategies are available:
|
|
1802
2412
|
*
|
|
1803
|
-
*
|
|
1804
|
-
*
|
|
2413
|
+
* - `"skip"` -- Swallow the error and continue.
|
|
2414
|
+
* - `"retry"` -- Signal the caller to retry immediately.
|
|
2415
|
+
* - `"retry-later"` -- Enqueue a deferred retry with exponential backoff
|
|
2416
|
+
* (delegated to an internal {@link createRetryLaterManager}).
|
|
2417
|
+
* - `"disable"` -- Permanently disable the failing source.
|
|
2418
|
+
* - `"throw"` -- Re-throw the error as a {@link DirectiveError}.
|
|
1805
2419
|
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
1809
|
-
*
|
|
1810
|
-
* onResolverError: "retry-later",
|
|
1811
|
-
* onEffectError: "skip",
|
|
1812
|
-
* retryLater: { maxRetries: 5, delayMs: 500 },
|
|
1813
|
-
* },
|
|
1814
|
-
* onError: (err) => console.error(err.source, err.message),
|
|
1815
|
-
* });
|
|
2420
|
+
* Recent errors are kept in a ring buffer (last 100) for inspection via
|
|
2421
|
+
* {@link ErrorBoundaryManager.getAllErrors | getAllErrors}. Each strategy
|
|
2422
|
+
* can be configured per source type (`onConstraintError`, `onResolverError`,
|
|
2423
|
+
* etc.) or as a callback that dynamically selects a strategy.
|
|
1816
2424
|
*
|
|
1817
|
-
*
|
|
1818
|
-
*
|
|
1819
|
-
*
|
|
2425
|
+
* @param options - Error boundary configuration, plus `onError` and `onRecovery` callbacks for plugin integration.
|
|
2426
|
+
* @returns An {@link ErrorBoundaryManager} for routing errors through the configured strategies.
|
|
2427
|
+
*
|
|
2428
|
+
* @internal
|
|
1820
2429
|
*/
|
|
1821
2430
|
declare function createErrorBoundaryManager(options?: CreateErrorBoundaryOptions): ErrorBoundaryManager;
|
|
1822
2431
|
|
|
@@ -1830,6 +2439,23 @@ declare function createErrorBoundaryManager(options?: CreateErrorBoundaryOptions
|
|
|
1830
2439
|
* - Export/import state history
|
|
1831
2440
|
*/
|
|
1832
2441
|
|
|
2442
|
+
/**
|
|
2443
|
+
* Internal time-travel manager that extends the public {@link TimeTravelAPI}
|
|
2444
|
+
* with snapshot capture, restoration, and pause/resume controls.
|
|
2445
|
+
*
|
|
2446
|
+
* @remarks
|
|
2447
|
+
* - `takeSnapshot(trigger)` records the current facts into the ring buffer.
|
|
2448
|
+
* - `restore(snapshot)` deserializes a snapshot back into the facts store,
|
|
2449
|
+
* setting `isRestoring = true` so the engine skips reconciliation.
|
|
2450
|
+
* - `pause()` / `resume()` temporarily suspend snapshot recording (e.g.,
|
|
2451
|
+
* during bulk imports or programmatic state resets).
|
|
2452
|
+
* - `beginChangeset(label)` / `endChangeset()` group consecutive snapshots
|
|
2453
|
+
* so `goBack`/`goForward` treat them as a single undo/redo unit.
|
|
2454
|
+
*
|
|
2455
|
+
* @typeParam _S - The schema type (unused at runtime but preserved for type safety).
|
|
2456
|
+
*
|
|
2457
|
+
* @internal
|
|
2458
|
+
*/
|
|
1833
2459
|
interface TimeTravelManager<_S extends Schema> extends TimeTravelAPI {
|
|
1834
2460
|
/** Take a snapshot of current state */
|
|
1835
2461
|
takeSnapshot(trigger: string): Snapshot;
|
|
@@ -1844,7 +2470,13 @@ interface TimeTravelManager<_S extends Schema> extends TimeTravelAPI {
|
|
|
1844
2470
|
/** Resume snapshot taking */
|
|
1845
2471
|
resume(): void;
|
|
1846
2472
|
}
|
|
1847
|
-
/**
|
|
2473
|
+
/**
|
|
2474
|
+
* Options for creating a time-travel manager via {@link createTimeTravelManager}.
|
|
2475
|
+
*
|
|
2476
|
+
* @typeParam S - The facts schema type.
|
|
2477
|
+
*
|
|
2478
|
+
* @internal
|
|
2479
|
+
*/
|
|
1848
2480
|
interface CreateTimeTravelOptions<S extends Schema> {
|
|
1849
2481
|
config: DebugConfig;
|
|
1850
2482
|
facts: Facts<S>;
|
|
@@ -1855,24 +2487,35 @@ interface CreateTimeTravelOptions<S extends Schema> {
|
|
|
1855
2487
|
onTimeTravel?: (from: number, to: number) => void;
|
|
1856
2488
|
}
|
|
1857
2489
|
/**
|
|
1858
|
-
* Create a snapshot-based time-travel debugger
|
|
1859
|
-
* history.
|
|
2490
|
+
* Create a snapshot-based time-travel debugger backed by a ring buffer.
|
|
1860
2491
|
*
|
|
1861
|
-
*
|
|
1862
|
-
*
|
|
1863
|
-
*
|
|
1864
|
-
*
|
|
1865
|
-
*
|
|
2492
|
+
* @remarks
|
|
2493
|
+
* Snapshots are taken automatically after fact changes (during reconciliation)
|
|
2494
|
+
* and can be navigated with `goBack`/`goForward`/`goTo`. Use
|
|
2495
|
+
* `beginChangeset(label)` and `endChangeset()` to group multiple snapshots
|
|
2496
|
+
* into a single undo/redo unit. The entire history can be exported to JSON
|
|
2497
|
+
* via `export()` and re-imported with `import()` for cross-session debugging.
|
|
1866
2498
|
*
|
|
1867
|
-
*
|
|
1868
|
-
*
|
|
2499
|
+
* Call `pause()` to temporarily stop recording snapshots (e.g., during bulk
|
|
2500
|
+
* fact imports) and `resume()` to re-enable recording.
|
|
2501
|
+
*
|
|
2502
|
+
* @param options - Debug config, facts proxy, store, and optional snapshot/time-travel callbacks.
|
|
2503
|
+
* @returns A {@link TimeTravelManager} with snapshot capture, navigation, changeset, and export/import methods.
|
|
2504
|
+
*
|
|
2505
|
+
* @internal
|
|
1869
2506
|
*/
|
|
1870
2507
|
declare function createTimeTravelManager<S extends Schema>(options: CreateTimeTravelOptions<S>): TimeTravelManager<S>;
|
|
1871
2508
|
/**
|
|
1872
|
-
* Create a no-op time-travel manager
|
|
1873
|
-
*
|
|
2509
|
+
* Create a no-op time-travel manager for use when `debug.timeTravel` is disabled.
|
|
2510
|
+
*
|
|
2511
|
+
* @remarks
|
|
2512
|
+
* All methods are safe to call but perform no work. This avoids null-checks
|
|
2513
|
+
* throughout the engine -- callers can use the same {@link TimeTravelManager}
|
|
2514
|
+
* interface regardless of whether time-travel is enabled.
|
|
1874
2515
|
*
|
|
1875
|
-
* @returns A
|
|
2516
|
+
* @returns A {@link TimeTravelManager} where every method is a no-op and `isEnabled` is `false`.
|
|
2517
|
+
*
|
|
2518
|
+
* @internal
|
|
1876
2519
|
*/
|
|
1877
2520
|
declare function createDisabledTimeTravel<S extends Schema>(): TimeTravelManager<S>;
|
|
1878
2521
|
|
|
@@ -1892,12 +2535,13 @@ declare function createDisabledTimeTravel<S extends Schema>(): TimeTravelManager
|
|
|
1892
2535
|
* effects, constraints, resolvers, plugins, error boundaries, and time-travel
|
|
1893
2536
|
* into a single reactive system.
|
|
1894
2537
|
*
|
|
1895
|
-
*
|
|
1896
|
-
*
|
|
1897
|
-
*
|
|
2538
|
+
* @remarks
|
|
2539
|
+
* This is the internal factory used by {@link createSystem}. Most users should
|
|
2540
|
+
* call `createSystem` instead, which provides a friendlier API and handles
|
|
2541
|
+
* module composition.
|
|
1898
2542
|
*
|
|
1899
|
-
* @param config - Full system configuration
|
|
1900
|
-
* @returns A
|
|
2543
|
+
* @param config - Full system configuration including modules, plugins, error boundary settings, and debug options
|
|
2544
|
+
* @returns A {@link System} instance with facts, derive, events, dispatch, subscribe, watch, settle, and lifecycle methods
|
|
1901
2545
|
*
|
|
1902
2546
|
* @example
|
|
1903
2547
|
* ```ts
|
|
@@ -1913,6 +2557,8 @@ declare function createDisabledTimeTravel<S extends Schema>(): TimeTravelManager
|
|
|
1913
2557
|
* system.start();
|
|
1914
2558
|
* system.facts.count = 42;
|
|
1915
2559
|
* ```
|
|
2560
|
+
*
|
|
2561
|
+
* @internal
|
|
1916
2562
|
*/
|
|
1917
2563
|
declare function createEngine<S extends Schema>(config: SystemConfig<any>): System<any>;
|
|
1918
2564
|
|