@directive-run/core 0.1.1
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/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/adapter-utils.cjs +2 -0
- package/dist/adapter-utils.cjs.map +1 -0
- package/dist/adapter-utils.d.cts +230 -0
- package/dist/adapter-utils.d.ts +230 -0
- package/dist/adapter-utils.js +2 -0
- package/dist/adapter-utils.js.map +1 -0
- package/dist/index.cjs +35 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2016 -0
- package/dist/index.d.ts +2016 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/migration.cjs +25 -0
- package/dist/migration.cjs.map +1 -0
- package/dist/migration.d.cts +109 -0
- package/dist/migration.d.ts +109 -0
- package/dist/migration.js +25 -0
- package/dist/migration.js.map +1 -0
- package/dist/plugins/index.cjs +3 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.cts +697 -0
- package/dist/plugins/index.d.ts +697 -0
- package/dist/plugins/index.js +3 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins-CcwEXXMS.d.cts +1876 -0
- package/dist/plugins-CcwEXXMS.d.ts +1876 -0
- package/dist/testing.cjs +12 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +235 -0
- package/dist/testing.d.ts +235 -0
- package/dist/testing.js +12 -0
- package/dist/testing.js.map +1 -0
- package/dist/utils-4JrY5fk9.d.cts +198 -0
- package/dist/utils-4JrY5fk9.d.ts +198 -0
- package/dist/worker.cjs +12 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +241 -0
- package/dist/worker.d.ts +241 -0
- package/dist/worker.js +12 -0
- package/dist/worker.js.map +1 -0
- package/package.json +85 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,2016 @@
|
|
|
1
|
+
import { S as Schema, F as Facts, R as Requirement, a as RequirementOutput, b as RetryPolicy, B as BatchConfig, c as ResolverContext, d as SchemaType, e as FactsStore, M as ModuleSchema, T as TypedDerivationsDef, f as TypedEventsDef, E as EffectsDef, g as TypedConstraintsDef, h as TypedResolversDef, i as ModuleHooks, C as CrossModuleDeps, j as CrossModuleDerivationsDef, k as CrossModuleEffectsDef, l as CrossModuleConstraintsDef, m as ModuleDef, n as CreateSystemOptionsSingle, o as SingleModuleSystem, p as ModulesMap, q as CreateSystemOptionsNamed, N as NamespacedSystem, D as DerivationsSchema, r as TypedConstraintDef, s as RequirementOutput$1, I as InferRequirements, P as Plugin, t as DebugConfig, u as ErrorBoundaryConfig, v as InferFacts, w as ExtractSchema, x as RequirementWithId, y as RequirementKeyFn, z as ConstraintsDef, A as ConstraintState, G as ResolversDef, H as ResolverStatus, J as System, K as FactChange, L as FactsSnapshot, O as ReconcileResult, Q as Snapshot, U as DirectiveError, V as RecoveryStrategy, W as ErrorSource, X as RetryLaterConfig, Y as TimeTravelAPI, Z as SystemConfig } from './plugins-CcwEXXMS.cjs';
|
|
2
|
+
export { _ as AnySystem, $ as BatchItemResult, a0 as BatchResolveResults, a1 as CircuitBreakerConfig, a2 as CircuitBreakerState, a3 as CrossModuleConstraintDef, a4 as CrossModuleDerivationFn, a5 as CrossModuleEffectDef, a6 as CrossModuleFactsWithSelf, a7 as DerivationKeys, a8 as DerivationReturnType, a9 as DeriveAccessor, aa as DispatchEventsFromSchema, ab as DistributableSnapshot, ac as DistributableSnapshotOptions, ad as EffectCleanup, ae as EventPayloadSchema, af as EventsAccessor, ag as EventsAccessorFromSchema, ah as EventsDef, ai as EventsSchema, aj as FactKeys, ak as FactReturnType, al as FlexibleEventHandler, am as InferDerivations, an as InferEventPayloadFromSchema, ao as InferEvents, ap as InferRequirementPayloadFromSchema, aq as InferRequirementTypes, ar as InferSchema, as as InferSchemaType, at as InferSelectorState, au as MutableNamespacedFacts, av as NamespacedDerivations, aw as NamespacedEventsAccessor, ax as NamespacedFacts, ay as ObservableKeys, az as RequirementExplanation, aA as RequirementPayloadSchema, aB as RequirementsSchema, aC as SnapshotMeta, aD as SystemEvent, aE as SystemInspection, aF as SystemMode, aG as SystemSnapshot, aH as TimeTravelState, aI as TypedResolverContext, aJ as TypedResolverDef, aK as UnionEvents, aL as isNamespacedSystem, aM as isSingleModuleSystem } from './plugins-CcwEXXMS.cjs';
|
|
3
|
+
export { D as DistributableSnapshotLike, S as SignedSnapshot, a as SnapshotDiff, b as SnapshotDiffEntry, d as diffSnapshots, i as isSignedSnapshot, c as isSnapshotExpired, s as shallowEqual, e as signSnapshot, v as validateSnapshot, f as verifySnapshotSignature } from './utils-4JrY5fk9.cjs';
|
|
4
|
+
export { DirectiveModuleStructure, ReduxSliceConfig, XStateMachineConfig, ZustandStoreConfig, analyzeReduxSlice, analyzeXStateMachine, analyzeZustandStore, generateMigrationChecklist, generateModuleCode } from './migration.cjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Derivation Types - Type definitions for derivations
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Tracking context for auto-dependency detection */
|
|
11
|
+
interface TrackingContext {
|
|
12
|
+
readonly isTracking: boolean;
|
|
13
|
+
track(key: string): void;
|
|
14
|
+
getDependencies(): Set<string>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Legacy derivation definition function signature.
|
|
18
|
+
* Used internally by the engine.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated For typed derivations, use TypedDerivationsDef from module.ts
|
|
21
|
+
*/
|
|
22
|
+
interface DerivationDef<S extends Schema, T, D extends DerivationsDef<S>> {
|
|
23
|
+
(facts: Facts<S>, derive: DerivedValues<S, D>): T;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Legacy map of derivation definitions.
|
|
27
|
+
* Used internally by the engine.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated For typed derivations, use TypedDerivationsDef from module.ts
|
|
30
|
+
*/
|
|
31
|
+
type DerivationsDef<S extends Schema> = Record<string, DerivationDef<S, unknown, DerivationsDef<S>>>;
|
|
32
|
+
/**
|
|
33
|
+
* Legacy computed derived values.
|
|
34
|
+
* Used internally by the engine.
|
|
35
|
+
*
|
|
36
|
+
* @deprecated For typed derivations, use InferDerivations from schema.ts
|
|
37
|
+
*/
|
|
38
|
+
type DerivedValues<S extends Schema, D extends DerivationsDef<S>> = {
|
|
39
|
+
readonly [K in keyof D]: ReturnType<D[K]>;
|
|
40
|
+
};
|
|
41
|
+
/** Internal derivation state */
|
|
42
|
+
interface DerivationState<T> {
|
|
43
|
+
id: string;
|
|
44
|
+
compute: () => T;
|
|
45
|
+
cachedValue: T | undefined;
|
|
46
|
+
dependencies: Set<string>;
|
|
47
|
+
isStale: boolean;
|
|
48
|
+
isComputing: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Type Helpers - External typed constraint and resolver definitions
|
|
53
|
+
*
|
|
54
|
+
* These types enable defining constraints and resolvers with full type safety
|
|
55
|
+
* outside of module definitions, while maintaining proper type inference.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* External constraint definition with full typing.
|
|
60
|
+
* Use this when defining constraints outside of createModule().
|
|
61
|
+
*
|
|
62
|
+
* @typeParam S - The schema type
|
|
63
|
+
* @typeParam R - The requirement type (defaults to Requirement)
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Define a typed constraint factory
|
|
68
|
+
* const createMaxCountConstraint = <S extends Schema>(
|
|
69
|
+
* maxCount: number
|
|
70
|
+
* ): TypedConstraint<S, { type: "RESET_COUNT" }> => ({
|
|
71
|
+
* priority: 10,
|
|
72
|
+
* when: (facts) => (facts as { count: number }).count > maxCount,
|
|
73
|
+
* require: { type: "RESET_COUNT" },
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* // Use in module
|
|
77
|
+
* const module = createModule("counter", {
|
|
78
|
+
* schema: { count: t.number() },
|
|
79
|
+
* constraints: {
|
|
80
|
+
* maxCount: createMaxCountConstraint(100),
|
|
81
|
+
* },
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
interface TypedConstraint<S extends Schema, R extends Requirement = Requirement> {
|
|
86
|
+
/** Priority for ordering (higher runs first) */
|
|
87
|
+
priority?: number;
|
|
88
|
+
/** Mark this constraint as async (avoids runtime detection) */
|
|
89
|
+
async?: boolean;
|
|
90
|
+
/** Condition function (sync or async) */
|
|
91
|
+
when: (facts: Facts<S>) => boolean | Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* Requirement(s) to produce when condition is met.
|
|
94
|
+
*/
|
|
95
|
+
require: RequirementOutput<R> | ((facts: Facts<S>) => RequirementOutput<R>);
|
|
96
|
+
/** Timeout for async constraints (ms) */
|
|
97
|
+
timeout?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Constraint IDs whose resolvers must complete before this constraint is evaluated.
|
|
100
|
+
* - If dependency's `when()` returns false, this constraint proceeds (nothing to wait for)
|
|
101
|
+
* - If dependency's resolver fails, this constraint remains blocked until it succeeds
|
|
102
|
+
* - Cross-module: use the constraint ID as it appears in the merged system
|
|
103
|
+
*/
|
|
104
|
+
after?: string[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* External resolver definition with full typing.
|
|
108
|
+
* Use this when defining resolvers outside of createModule().
|
|
109
|
+
*
|
|
110
|
+
* @typeParam S - The schema type
|
|
111
|
+
* @typeParam R - The requirement type (defaults to Requirement)
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* // Define a typed resolver factory
|
|
116
|
+
* interface FetchUserReq extends Requirement {
|
|
117
|
+
* type: "FETCH_USER";
|
|
118
|
+
* userId: string;
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* const createFetchUserResolver = <S extends Schema>(
|
|
122
|
+
* fetchFn: (userId: string) => Promise<User>
|
|
123
|
+
* ): TypedResolver<S, FetchUserReq> => ({
|
|
124
|
+
* requirement: (req): req is FetchUserReq => req.type === "FETCH_USER",
|
|
125
|
+
* key: (req) => `fetch-user-${req.userId}`,
|
|
126
|
+
* retry: { attempts: 3, backoff: "exponential" },
|
|
127
|
+
* resolve: async (req, ctx) => {
|
|
128
|
+
* const user = await fetchFn(req.userId);
|
|
129
|
+
* (ctx.facts as { user: User }).user = user;
|
|
130
|
+
* },
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
interface TypedResolver<S extends Schema, R extends Requirement = Requirement> {
|
|
135
|
+
/**
|
|
136
|
+
* Requirement type to handle.
|
|
137
|
+
* - String: matches `req.type` directly (e.g., `requirement: "FETCH_USER"`)
|
|
138
|
+
* - Function: type guard predicate (e.g., `requirement: (req) => req.type === "FETCH_USER"`)
|
|
139
|
+
*/
|
|
140
|
+
requirement: R["type"] | ((req: Requirement) => req is R);
|
|
141
|
+
/** Custom key function for deduplication */
|
|
142
|
+
key?: (req: R) => string;
|
|
143
|
+
/** Retry policy */
|
|
144
|
+
retry?: RetryPolicy;
|
|
145
|
+
/** Timeout for resolver execution (ms) */
|
|
146
|
+
timeout?: number;
|
|
147
|
+
/** Batch configuration */
|
|
148
|
+
batch?: BatchConfig;
|
|
149
|
+
/** Resolve function for single requirement */
|
|
150
|
+
resolve?: (req: R, ctx: ResolverContext<S>) => Promise<void>;
|
|
151
|
+
/** Resolve function for batched requirements */
|
|
152
|
+
resolveBatch?: (reqs: R[], ctx: ResolverContext<S>) => Promise<void>;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create a typed constraint factory for a specific schema.
|
|
156
|
+
* This enables creating reusable constraint definitions with proper typing.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const schema = { count: t.number(), threshold: t.number() };
|
|
161
|
+
* const factory = constraintFactory<typeof schema>();
|
|
162
|
+
*
|
|
163
|
+
* const maxCountConstraint = factory.create({
|
|
164
|
+
* when: (facts) => facts.count > facts.threshold,
|
|
165
|
+
* require: { type: "RESET" },
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function constraintFactory<S extends Schema>(): {
|
|
170
|
+
/**
|
|
171
|
+
* Create a typed constraint
|
|
172
|
+
*/
|
|
173
|
+
create<R extends Requirement = Requirement>(constraint: TypedConstraint<S, R>): TypedConstraint<S, R>;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Create a typed resolver factory for a specific schema.
|
|
177
|
+
* This enables creating reusable resolver definitions with proper typing.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* const schema = { user: t.object<User>() };
|
|
182
|
+
* const factory = resolverFactory<typeof schema>();
|
|
183
|
+
*
|
|
184
|
+
* const fetchUserResolver = factory.create<FetchUserReq>({
|
|
185
|
+
* requirement: (req): req is FetchUserReq => req.type === "FETCH_USER",
|
|
186
|
+
* resolve: async (req, ctx) => {
|
|
187
|
+
* ctx.facts.user = await fetchUser(req.userId);
|
|
188
|
+
* },
|
|
189
|
+
* });
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
declare function resolverFactory<S extends Schema>(): {
|
|
193
|
+
/**
|
|
194
|
+
* Create a typed resolver
|
|
195
|
+
*/
|
|
196
|
+
create<R extends Requirement = Requirement>(resolver: TypedResolver<S, R>): TypedResolver<S, R>;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Type-safe constraint creator.
|
|
200
|
+
* Simpler alternative to constraintFactory when you don't need a factory pattern.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const constraint = typedConstraint<typeof schema, { type: "RESET" }>({
|
|
205
|
+
* when: (facts) => facts.count > 100,
|
|
206
|
+
* require: { type: "RESET" },
|
|
207
|
+
* });
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
declare function typedConstraint<S extends Schema, R extends Requirement = Requirement>(constraint: TypedConstraint<S, R>): TypedConstraint<S, R>;
|
|
211
|
+
/**
|
|
212
|
+
* Type-safe resolver creator.
|
|
213
|
+
* Simpler alternative to resolverFactory when you don't need a factory pattern.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* const resolver = typedResolver<typeof schema, FetchUserReq>({
|
|
218
|
+
* requirement: (req): req is FetchUserReq => req.type === "FETCH_USER",
|
|
219
|
+
* resolve: async (req, ctx) => {
|
|
220
|
+
* ctx.facts.user = await fetchUser(req.userId);
|
|
221
|
+
* },
|
|
222
|
+
* });
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
declare function typedResolver<S extends Schema, R extends Requirement = Requirement>(resolver: TypedResolver<S, R>): TypedResolver<S, R>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Facts Store - Proxy-based reactive state with auto-tracking
|
|
229
|
+
*
|
|
230
|
+
* Features:
|
|
231
|
+
* - Proxy-based access (facts.phase instead of facts.get("phase"))
|
|
232
|
+
* - Automatic dependency tracking via tracking context
|
|
233
|
+
* - Batched updates with coalesced notifications
|
|
234
|
+
* - Granular subscriptions by key
|
|
235
|
+
* - Schema validation in development mode
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
/** Brand symbol for branded types */
|
|
239
|
+
declare const Brand: unique symbol;
|
|
240
|
+
/** Branded type - adds a unique brand to a base type */
|
|
241
|
+
type Branded<T, B extends string> = T & {
|
|
242
|
+
readonly [Brand]: B;
|
|
243
|
+
};
|
|
244
|
+
/** Extended SchemaType with type name for better error messages */
|
|
245
|
+
interface ExtendedSchemaType<T> extends SchemaType<T> {
|
|
246
|
+
readonly _typeName?: string;
|
|
247
|
+
readonly _default?: T | (() => T);
|
|
248
|
+
readonly _transform?: (value: unknown) => T;
|
|
249
|
+
readonly _description?: string;
|
|
250
|
+
readonly _refinements?: Array<{
|
|
251
|
+
predicate: (value: T) => boolean;
|
|
252
|
+
message: string;
|
|
253
|
+
}>;
|
|
254
|
+
/** Mutable - set by array validators to indicate which element failed */
|
|
255
|
+
_lastFailedIndex?: number;
|
|
256
|
+
}
|
|
257
|
+
/** Chainable schema type with all common methods */
|
|
258
|
+
interface ChainableSchemaType<T> extends ExtendedSchemaType<T> {
|
|
259
|
+
default(value: T | (() => T)): ChainableSchemaType<T>;
|
|
260
|
+
transform<U>(fn: (value: T) => U): ChainableSchemaType<U>;
|
|
261
|
+
brand<B extends string>(): ChainableSchemaType<Branded<T, B>>;
|
|
262
|
+
describe(description: string): ChainableSchemaType<T>;
|
|
263
|
+
refine(predicate: (value: T) => boolean, message: string): ChainableSchemaType<T>;
|
|
264
|
+
nullable(): ChainableSchemaType<T | null>;
|
|
265
|
+
optional(): ChainableSchemaType<T | undefined>;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Schema type builders for defining fact types.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* const module = createModule("example", {
|
|
273
|
+
* schema: {
|
|
274
|
+
* name: t.string(),
|
|
275
|
+
* age: t.number().min(0).max(150),
|
|
276
|
+
* active: t.boolean(),
|
|
277
|
+
* tags: t.array<string>().of(t.string()),
|
|
278
|
+
* user: t.object<{ id: string; email: string }>(),
|
|
279
|
+
* },
|
|
280
|
+
* });
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
declare const t: {
|
|
284
|
+
/**
|
|
285
|
+
* Create a string schema type.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* // Basic string
|
|
290
|
+
* schema: { name: t.string() }
|
|
291
|
+
*
|
|
292
|
+
* // String literal union (for type safety)
|
|
293
|
+
* schema: { phase: t.string<"red" | "green" | "yellow">() }
|
|
294
|
+
*
|
|
295
|
+
* // With custom validation
|
|
296
|
+
* schema: { email: t.string().validate(s => s.includes("@")) }
|
|
297
|
+
*
|
|
298
|
+
* // With transform
|
|
299
|
+
* schema: { trimmed: t.string().transform(s => s.trim()) }
|
|
300
|
+
*
|
|
301
|
+
* // With brand
|
|
302
|
+
* schema: { userId: t.string().brand<"UserId">() }
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
string<T extends string = string>(): ChainableSchemaType<T>;
|
|
306
|
+
/**
|
|
307
|
+
* Create a number schema type with optional min/max constraints.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* // Basic number
|
|
312
|
+
* schema: { count: t.number() }
|
|
313
|
+
*
|
|
314
|
+
* // With range constraints
|
|
315
|
+
* schema: { age: t.number().min(0).max(150) }
|
|
316
|
+
*
|
|
317
|
+
* // With custom validation
|
|
318
|
+
* schema: { even: t.number().validate(n => n % 2 === 0) }
|
|
319
|
+
*
|
|
320
|
+
* // With default
|
|
321
|
+
* schema: { count: t.number().default(0) }
|
|
322
|
+
*
|
|
323
|
+
* // With transform (from string)
|
|
324
|
+
* schema: { age: t.number().transform(v => parseInt(String(v), 10)) }
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
number(): ChainableSchemaType<number> & {
|
|
328
|
+
min(n: number): ChainableSchemaType<number> & /*elided*/ any;
|
|
329
|
+
max(n: number): ChainableSchemaType<number> & /*elided*/ any;
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* Create a boolean schema type.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* schema: {
|
|
337
|
+
* active: t.boolean(),
|
|
338
|
+
* verified: t.boolean().default(false),
|
|
339
|
+
* }
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
boolean(): ChainableSchemaType<boolean>;
|
|
343
|
+
/**
|
|
344
|
+
* Create an array schema type.
|
|
345
|
+
* Can be used with or without element validation:
|
|
346
|
+
* - `t.array<string>()` - Type-only, no element validation
|
|
347
|
+
* - `t.array<string>().of(t.string())` - With element validation
|
|
348
|
+
*/
|
|
349
|
+
array<T>(): ChainableSchemaType<T[]> & {
|
|
350
|
+
of(elementType: SchemaType<T>): ChainableSchemaType<T[]> & /*elided*/ any;
|
|
351
|
+
nonEmpty(): ChainableSchemaType<T[]> & /*elided*/ any;
|
|
352
|
+
maxLength(n: number): ChainableSchemaType<T[]> & /*elided*/ any;
|
|
353
|
+
minLength(n: number): ChainableSchemaType<T[]> & /*elided*/ any;
|
|
354
|
+
_lastFailedIndex?: number;
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* Create an object schema type.
|
|
358
|
+
* Can be used with or without shape validation:
|
|
359
|
+
* - `t.object<User>()` - Type-only, no property validation
|
|
360
|
+
* - `t.object<User>().shape({ name: t.string(), age: t.number() })` - With property validation
|
|
361
|
+
*/
|
|
362
|
+
object<T extends Record<string, unknown>>(): ChainableSchemaType<T> & {
|
|
363
|
+
shape(schema: { [K in keyof T]?: SchemaType<T[K]>; }): ChainableSchemaType<T> & /*elided*/ any;
|
|
364
|
+
nonNull(): ChainableSchemaType<T> & /*elided*/ any;
|
|
365
|
+
hasKeys(...keys: string[]): ChainableSchemaType<T> & /*elided*/ any;
|
|
366
|
+
};
|
|
367
|
+
/**
|
|
368
|
+
* Create an any-typed schema (bypasses all validation).
|
|
369
|
+
*
|
|
370
|
+
* @deprecated Use specific types (`t.string()`, `t.object()`, `t.union()`) for type safety.
|
|
371
|
+
* This bypasses all runtime validation.
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```typescript
|
|
375
|
+
* // Use when type is complex or external
|
|
376
|
+
* schema: {
|
|
377
|
+
* externalApiResponse: t.any<ExternalAPIResponse>(),
|
|
378
|
+
* }
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
any<T>(): ExtendedSchemaType<T>;
|
|
382
|
+
/**
|
|
383
|
+
* Create an enum schema type for string literal unions.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```typescript
|
|
387
|
+
* // Define allowed values
|
|
388
|
+
* schema: { status: t.enum("idle", "loading", "success", "error") }
|
|
389
|
+
*
|
|
390
|
+
* // Type is inferred as "idle" | "loading" | "success" | "error"
|
|
391
|
+
* ```
|
|
392
|
+
*/
|
|
393
|
+
enum<T extends string>(...values: T[]): ChainableSchemaType<T>;
|
|
394
|
+
/**
|
|
395
|
+
* Create a literal schema type for exact value matching.
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```typescript
|
|
399
|
+
* // Exact string match
|
|
400
|
+
* schema: { type: t.literal("user") }
|
|
401
|
+
*
|
|
402
|
+
* // Exact number match
|
|
403
|
+
* schema: { version: t.literal(1) }
|
|
404
|
+
*
|
|
405
|
+
* // Exact boolean
|
|
406
|
+
* schema: { enabled: t.literal(true) }
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
409
|
+
literal<T extends string | number | boolean>(value: T): ChainableSchemaType<T>;
|
|
410
|
+
/**
|
|
411
|
+
* Create a nullable schema type (T | null).
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* ```typescript
|
|
415
|
+
* // Nullable string
|
|
416
|
+
* schema: { name: t.nullable(t.string()) }
|
|
417
|
+
*
|
|
418
|
+
* // Nullable object
|
|
419
|
+
* schema: { user: t.nullable(t.object<User>()) }
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
nullable<T>(innerType: SchemaType<T>): SchemaType<T | null>;
|
|
423
|
+
/**
|
|
424
|
+
* Create an optional schema type (T | undefined).
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```typescript
|
|
428
|
+
* // Optional string
|
|
429
|
+
* schema: { nickname: t.optional(t.string()) }
|
|
430
|
+
*
|
|
431
|
+
* // Optional number
|
|
432
|
+
* schema: { age: t.optional(t.number()) }
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
optional<T>(innerType: SchemaType<T>): SchemaType<T | undefined>;
|
|
436
|
+
/**
|
|
437
|
+
* Create a union schema type.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```typescript
|
|
441
|
+
* // String or number
|
|
442
|
+
* schema: { value: t.union(t.string(), t.number()) }
|
|
443
|
+
*
|
|
444
|
+
* // Multiple types
|
|
445
|
+
* schema: { data: t.union(t.string(), t.number(), t.boolean()) }
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
union<T extends SchemaType<unknown>[]>(...types: T): ChainableSchemaType<T[number] extends SchemaType<infer U> ? U : never>;
|
|
449
|
+
/**
|
|
450
|
+
* Create a record schema type for dynamic key-value maps.
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```typescript
|
|
454
|
+
* // Record with string values
|
|
455
|
+
* schema: { metadata: t.record(t.string()) }
|
|
456
|
+
*
|
|
457
|
+
* // Record with number values
|
|
458
|
+
* schema: { scores: t.record(t.number()) }
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
record<V>(valueType: SchemaType<V>): ChainableSchemaType<Record<string, V>>;
|
|
462
|
+
/**
|
|
463
|
+
* Create a tuple schema type for fixed-length arrays with specific types.
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* // [string, number] tuple
|
|
468
|
+
* schema: { coord: t.tuple(t.string(), t.number()) }
|
|
469
|
+
*
|
|
470
|
+
* // [x, y, z] coordinates
|
|
471
|
+
* schema: { position: t.tuple(t.number(), t.number(), t.number()) }
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
tuple<T extends SchemaType<unknown>[]>(...types: T): ChainableSchemaType<{ [K in keyof T]: T[K] extends SchemaType<infer U> ? U : never; }>;
|
|
475
|
+
/**
|
|
476
|
+
* Create a date schema type.
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```typescript
|
|
480
|
+
* schema: { createdAt: t.date() }
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
date(): ChainableSchemaType<Date>;
|
|
484
|
+
/**
|
|
485
|
+
* Create a UUID schema type.
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* ```typescript
|
|
489
|
+
* schema: { id: t.uuid() }
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
uuid(): ChainableSchemaType<string>;
|
|
493
|
+
/**
|
|
494
|
+
* Create an email schema type.
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* ```typescript
|
|
498
|
+
* schema: { email: t.email() }
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
email(): ChainableSchemaType<string>;
|
|
502
|
+
/**
|
|
503
|
+
* Create a URL schema type.
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```typescript
|
|
507
|
+
* schema: { website: t.url() }
|
|
508
|
+
* ```
|
|
509
|
+
*/
|
|
510
|
+
url(): ChainableSchemaType<string>;
|
|
511
|
+
/**
|
|
512
|
+
* Create a bigint schema type.
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```typescript
|
|
516
|
+
* schema: { largeNumber: t.bigint() }
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
bigint(): ChainableSchemaType<bigint>;
|
|
520
|
+
};
|
|
521
|
+
/** Options for creating a facts store */
|
|
522
|
+
interface CreateFactsStoreOptions<S extends Schema> {
|
|
523
|
+
schema: S;
|
|
524
|
+
/** Validate values against schema (default: process.env.NODE_ENV !== 'production') */
|
|
525
|
+
validate?: boolean;
|
|
526
|
+
/** Throw on unknown schema keys (default: true in dev mode) */
|
|
527
|
+
strictKeys?: boolean;
|
|
528
|
+
/** Redact sensitive values in error messages */
|
|
529
|
+
redactErrors?: boolean;
|
|
530
|
+
/** Callback when facts change (for plugin hooks) */
|
|
531
|
+
onChange?: (key: string, value: unknown, prev: unknown) => void;
|
|
532
|
+
/** Callback for batch changes */
|
|
533
|
+
onBatch?: (changes: Array<{
|
|
534
|
+
key: string;
|
|
535
|
+
value: unknown;
|
|
536
|
+
prev: unknown;
|
|
537
|
+
type: "set" | "delete";
|
|
538
|
+
}>) => void;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Create a reactive facts store backed by a Map with schema validation,
|
|
542
|
+
* batched mutations, and granular key-level subscriptions.
|
|
543
|
+
*
|
|
544
|
+
* The store is the low-level primitive that powers the `facts` proxy.
|
|
545
|
+
* Most users should use {@link createFacts} or `createModule` instead.
|
|
546
|
+
*
|
|
547
|
+
* @param options - Store configuration including schema, validation settings, and change callbacks
|
|
548
|
+
* @returns A `FactsStore<S>` with get/set/batch/subscribe methods and automatic schema validation
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* ```ts
|
|
552
|
+
* const store = createFactsStore({
|
|
553
|
+
* schema: { count: t.number(), name: t.string() },
|
|
554
|
+
* });
|
|
555
|
+
*
|
|
556
|
+
* store.set("count", 1);
|
|
557
|
+
* store.get("count"); // 1
|
|
558
|
+
*
|
|
559
|
+
* store.batch(() => {
|
|
560
|
+
* store.set("count", 2);
|
|
561
|
+
* store.set("name", "hello");
|
|
562
|
+
* }); // listeners fire once after batch completes
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
declare function createFactsStore<S extends Schema>(options: CreateFactsStoreOptions<S>): FactsStore<S>;
|
|
566
|
+
/**
|
|
567
|
+
* Create a Proxy wrapper around a {@link FactsStore} for clean property-style
|
|
568
|
+
* access (`facts.phase`) with automatic dependency tracking.
|
|
569
|
+
*
|
|
570
|
+
* Reading a property calls `store.get()` (which tracks the access for
|
|
571
|
+
* auto-tracked derivations). Writing a property calls `store.set()` (which
|
|
572
|
+
* validates against the schema). The proxy also exposes `$store` for direct
|
|
573
|
+
* store access and `$snapshot()` for untracked reads.
|
|
574
|
+
*
|
|
575
|
+
* @param store - The underlying facts store to wrap
|
|
576
|
+
* @param schema - The schema definition (used for `ownKeys` enumeration)
|
|
577
|
+
* @returns A `Facts<S>` proxy with property-style get/set and prototype pollution guards
|
|
578
|
+
*/
|
|
579
|
+
declare function createFactsProxy<S extends Schema>(store: FactsStore<S>, schema: S): Facts<S>;
|
|
580
|
+
/**
|
|
581
|
+
* Convenience factory that creates both a {@link FactsStore} and its
|
|
582
|
+
* {@link createFactsProxy | proxy wrapper} in a single call.
|
|
583
|
+
*
|
|
584
|
+
* This is the recommended entry point when you need low-level store access
|
|
585
|
+
* outside of `createModule` / `createSystem`.
|
|
586
|
+
*
|
|
587
|
+
* @param options - Same options as {@link createFactsStore}
|
|
588
|
+
* @returns An object with `store` (the reactive Map-backed store) and `facts` (the Proxy accessor)
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* const { store, facts } = createFacts({
|
|
593
|
+
* schema: { phase: t.string<"red" | "green">() },
|
|
594
|
+
* });
|
|
595
|
+
*
|
|
596
|
+
* facts.phase = "red";
|
|
597
|
+
* console.log(facts.phase); // "red"
|
|
598
|
+
* store.subscribe(["phase"], () => console.log("phase changed"));
|
|
599
|
+
* ```
|
|
600
|
+
*/
|
|
601
|
+
declare function createFacts<S extends Schema>(options: CreateFactsStoreOptions<S>): {
|
|
602
|
+
store: FactsStore<S>;
|
|
603
|
+
facts: Facts<S>;
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Module - The declarative API for defining Directive modules
|
|
608
|
+
*
|
|
609
|
+
* Modules group related facts, constraints, resolvers, effects, and derivations.
|
|
610
|
+
*/
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Module configuration with consolidated schema.
|
|
614
|
+
*
|
|
615
|
+
* derive and events are optional - omit them if your schema has empty derivations/events.
|
|
616
|
+
*/
|
|
617
|
+
interface ModuleConfig<M extends ModuleSchema> {
|
|
618
|
+
schema: M;
|
|
619
|
+
init?: (facts: Facts<M["facts"]>) => void;
|
|
620
|
+
derive?: TypedDerivationsDef<M>;
|
|
621
|
+
events?: TypedEventsDef<M>;
|
|
622
|
+
effects?: EffectsDef<M["facts"]>;
|
|
623
|
+
constraints?: TypedConstraintsDef<M>;
|
|
624
|
+
resolvers?: TypedResolversDef<M>;
|
|
625
|
+
hooks?: ModuleHooks<M>;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Module configuration with cross-module dependencies for type-safe access
|
|
629
|
+
* to other modules' facts in effects and constraints.
|
|
630
|
+
*
|
|
631
|
+
* When crossModuleDeps is provided:
|
|
632
|
+
* - Own module facts: `facts.self.*`
|
|
633
|
+
* - Cross-module facts: `facts.{dep}.*`
|
|
634
|
+
*
|
|
635
|
+
* @example
|
|
636
|
+
* ```typescript
|
|
637
|
+
* import { authSchema } from './auth';
|
|
638
|
+
* import { dataSchema } from './data';
|
|
639
|
+
*
|
|
640
|
+
* const uiModule = createModule("ui", {
|
|
641
|
+
* schema: uiSchema,
|
|
642
|
+
* crossModuleDeps: { auth: authSchema, data: dataSchema },
|
|
643
|
+
* effects: {
|
|
644
|
+
* onAuthChange: {
|
|
645
|
+
* run: (facts) => {
|
|
646
|
+
* facts.self.notifications // ✅ own module via "self"
|
|
647
|
+
* facts.auth.isAuthenticated // ✅ cross-module (namespaced)
|
|
648
|
+
* facts.data.users // ✅ cross-module (namespaced)
|
|
649
|
+
* }
|
|
650
|
+
* }
|
|
651
|
+
* },
|
|
652
|
+
* constraints: {
|
|
653
|
+
* fetchWhenAuth: {
|
|
654
|
+
* when: (facts) => facts.auth.isAuthenticated && facts.self.users.length === 0,
|
|
655
|
+
* require: { type: "FETCH_USERS" },
|
|
656
|
+
* }
|
|
657
|
+
* }
|
|
658
|
+
* });
|
|
659
|
+
* ```
|
|
660
|
+
*/
|
|
661
|
+
interface ModuleConfigWithDeps<M extends ModuleSchema, Deps extends CrossModuleDeps> {
|
|
662
|
+
schema: M;
|
|
663
|
+
/**
|
|
664
|
+
* Cross-module dependencies for type-safe access in derive/effects/constraints.
|
|
665
|
+
*
|
|
666
|
+
* **Access patterns by context:**
|
|
667
|
+
* - `derive`, `effects`, `constraints`: Use `facts.self.*` for own module, `facts.{dep}.*` for cross-module
|
|
668
|
+
* - `init`, `events`, `resolvers`: Use flat access (`facts.myFact`) - no cross-module access
|
|
669
|
+
*
|
|
670
|
+
* This separation ensures initialization and event handling stay scoped to own module,
|
|
671
|
+
* while observers (derive/effects/constraints) can see across modules.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* ```typescript
|
|
675
|
+
* crossModuleDeps: { auth: authSchema },
|
|
676
|
+
* init: (facts) => { facts.users = []; }, // flat access
|
|
677
|
+
* derive: { count: (facts) => facts.self.users.length }, // facts.self.*
|
|
678
|
+
* effects: { log: { run: (facts) => console.log(facts.auth.token) } }, // facts.{dep}.*
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
crossModuleDeps: Deps;
|
|
682
|
+
/** Initialize module facts. Uses flat access (`facts.myFact`) to ensure modules initialize independently. */
|
|
683
|
+
init?: (facts: Facts<M["facts"]>) => void;
|
|
684
|
+
/** Derivations with cross-module facts access (`facts.self.*` + `facts.{dep}.*`) */
|
|
685
|
+
derive?: CrossModuleDerivationsDef<M, Deps>;
|
|
686
|
+
/** Event handlers. Uses flat access (`facts.myFact`) to keep mutations scoped to own module. */
|
|
687
|
+
events?: TypedEventsDef<M>;
|
|
688
|
+
/** Effects with cross-module facts access (`facts.self.*` + `facts.{dep}.*`) */
|
|
689
|
+
effects?: CrossModuleEffectsDef<M, Deps>;
|
|
690
|
+
/** Constraints with cross-module facts access (`facts.self.*` + `facts.{dep}.*`) */
|
|
691
|
+
constraints?: CrossModuleConstraintsDef<M, Deps>;
|
|
692
|
+
/** Resolvers. Uses flat access (`ctx.facts.myFact`) to keep async mutations scoped to own module. */
|
|
693
|
+
resolvers?: TypedResolversDef<M>;
|
|
694
|
+
hooks?: ModuleHooks<M>;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Create a module definition with full type inference.
|
|
698
|
+
*
|
|
699
|
+
* The consolidated schema provides:
|
|
700
|
+
* - Derivation composition (`derive.otherDerivation` is typed)
|
|
701
|
+
* - Event dispatch (`system.dispatch({ type: "..." })` has autocomplete)
|
|
702
|
+
* - Resolver requirements (`req.payload` is typed based on requirement type)
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```ts
|
|
706
|
+
* const trafficLight = createModule("traffic-light", {
|
|
707
|
+
* schema: {
|
|
708
|
+
* facts: {
|
|
709
|
+
* phase: t.string<"red" | "green" | "yellow">(),
|
|
710
|
+
* elapsed: t.number(),
|
|
711
|
+
* },
|
|
712
|
+
* derivations: {
|
|
713
|
+
* isRed: t.boolean(),
|
|
714
|
+
* timeRemaining: t.number(),
|
|
715
|
+
* },
|
|
716
|
+
* events: {
|
|
717
|
+
* tick: {},
|
|
718
|
+
* setPhase: { phase: t.string<"red" | "green" | "yellow">() },
|
|
719
|
+
* },
|
|
720
|
+
* requirements: {
|
|
721
|
+
* TRANSITION: { to: t.string<"red" | "green" | "yellow">() },
|
|
722
|
+
* },
|
|
723
|
+
* },
|
|
724
|
+
* init: (facts) => {
|
|
725
|
+
* facts.phase = "red";
|
|
726
|
+
* facts.elapsed = 0;
|
|
727
|
+
* },
|
|
728
|
+
* derive: {
|
|
729
|
+
* isRed: (facts) => facts.phase === "red",
|
|
730
|
+
* timeRemaining: (facts, derive) => {
|
|
731
|
+
* // derive.isRed is typed as boolean!
|
|
732
|
+
* return derive.isRed ? 30 - facts.elapsed : 0;
|
|
733
|
+
* },
|
|
734
|
+
* },
|
|
735
|
+
* events: {
|
|
736
|
+
* tick: (facts) => { facts.elapsed += 1; },
|
|
737
|
+
* setPhase: (facts, { phase }) => { facts.phase = phase; }, // phase is typed!
|
|
738
|
+
* },
|
|
739
|
+
* constraints: {
|
|
740
|
+
* shouldTransition: {
|
|
741
|
+
* when: (facts) => facts.phase === "red" && facts.elapsed > 30,
|
|
742
|
+
* require: { type: "TRANSITION", to: "green" },
|
|
743
|
+
* },
|
|
744
|
+
* },
|
|
745
|
+
* resolvers: {
|
|
746
|
+
* transition: {
|
|
747
|
+
* requirement: "TRANSITION",
|
|
748
|
+
* resolve: async (req, ctx) => {
|
|
749
|
+
* ctx.facts.phase = req.to; // req.to is typed!
|
|
750
|
+
* ctx.facts.elapsed = 0;
|
|
751
|
+
* },
|
|
752
|
+
* },
|
|
753
|
+
* },
|
|
754
|
+
* });
|
|
755
|
+
* ```
|
|
756
|
+
*
|
|
757
|
+
* @example With cross-module dependencies
|
|
758
|
+
* ```ts
|
|
759
|
+
* import { authSchema } from './auth';
|
|
760
|
+
*
|
|
761
|
+
* const dataModule = createModule("data", {
|
|
762
|
+
* schema: dataSchema,
|
|
763
|
+
* crossModuleDeps: { auth: authSchema },
|
|
764
|
+
* constraints: {
|
|
765
|
+
* fetchWhenAuth: {
|
|
766
|
+
* when: (facts) => {
|
|
767
|
+
* // facts.self.* for own module, facts.auth.* for cross-module
|
|
768
|
+
* return facts.auth.isAuthenticated && facts.self.users.length === 0;
|
|
769
|
+
* },
|
|
770
|
+
* require: { type: "FETCH_USERS" },
|
|
771
|
+
* },
|
|
772
|
+
* },
|
|
773
|
+
* derive: {
|
|
774
|
+
* canFetch: (facts) => facts.auth.isAuthenticated && facts.self.users.length === 0,
|
|
775
|
+
* },
|
|
776
|
+
* });
|
|
777
|
+
* ```
|
|
778
|
+
*/
|
|
779
|
+
declare function createModule<const M extends ModuleSchema, const Deps extends CrossModuleDeps>(id: string, config: ModuleConfigWithDeps<M, Deps>): ModuleDef<M>;
|
|
780
|
+
declare function createModule<const M extends ModuleSchema>(id: string, config: ModuleConfig<M>): ModuleDef<M>;
|
|
781
|
+
declare function createModule<const M extends ModuleSchema>(id: string, config: ModuleConfigWithDeps<M, CrossModuleDeps> | ModuleConfig<M>): ModuleDef<M>;
|
|
782
|
+
/**
|
|
783
|
+
* Create a module factory that produces named instances from a single definition.
|
|
784
|
+
* Useful for multi-instance UIs (tabs, panels, multi-tenant) where you need
|
|
785
|
+
* isolated state from the same schema.
|
|
786
|
+
*
|
|
787
|
+
* @example
|
|
788
|
+
* ```typescript
|
|
789
|
+
* const chatRoom = createModuleFactory({
|
|
790
|
+
* schema: {
|
|
791
|
+
* facts: { messages: t.array<string>(), users: t.array<string>() },
|
|
792
|
+
* derivations: { count: t.number() },
|
|
793
|
+
* },
|
|
794
|
+
* init: (facts) => { facts.messages = []; facts.users = []; },
|
|
795
|
+
* derive: { count: (facts) => facts.messages.length },
|
|
796
|
+
* });
|
|
797
|
+
*
|
|
798
|
+
* const system = createSystem({
|
|
799
|
+
* modules: {
|
|
800
|
+
* lobby: chatRoom("lobby"),
|
|
801
|
+
* support: chatRoom("support"),
|
|
802
|
+
* },
|
|
803
|
+
* });
|
|
804
|
+
* ```
|
|
805
|
+
*/
|
|
806
|
+
declare function createModuleFactory<const M extends ModuleSchema>(config: ModuleConfig<M>): (name: string) => ModuleDef<M>;
|
|
807
|
+
declare function createModuleFactory<const M extends ModuleSchema, const Deps extends CrossModuleDeps>(config: ModuleConfigWithDeps<M, Deps>): (name: string) => ModuleDef<M>;
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* System - The top-level API for creating a Directive runtime
|
|
811
|
+
*
|
|
812
|
+
* A system combines modules with plugins and configuration.
|
|
813
|
+
* Modules are passed as an object with namespaced access:
|
|
814
|
+
*
|
|
815
|
+
* @example
|
|
816
|
+
* ```typescript
|
|
817
|
+
* const system = createSystem({
|
|
818
|
+
* modules: { auth: authModule, data: dataModule },
|
|
819
|
+
* });
|
|
820
|
+
*
|
|
821
|
+
* system.facts.auth.token // Namespaced facts
|
|
822
|
+
* system.derive.data.userCount // Namespaced derivations
|
|
823
|
+
* system.events.auth.login() // Namespaced events
|
|
824
|
+
* ```
|
|
825
|
+
*/
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Create a Directive system.
|
|
829
|
+
*
|
|
830
|
+
* Supports two modes:
|
|
831
|
+
* - **Single module**: Use `module` prop for direct access without namespace
|
|
832
|
+
* - **Multiple modules**: Use `modules` prop for namespaced access
|
|
833
|
+
*
|
|
834
|
+
* @example Single module (direct access)
|
|
835
|
+
* ```ts
|
|
836
|
+
* const system = createSystem({ module: counterModule });
|
|
837
|
+
* system.facts.count // Direct access
|
|
838
|
+
* system.events.increment() // Direct events
|
|
839
|
+
* ```
|
|
840
|
+
*
|
|
841
|
+
* @example Multiple modules (namespaced access)
|
|
842
|
+
* ```ts
|
|
843
|
+
* const system = createSystem({
|
|
844
|
+
* modules: { auth: authModule, data: dataModule },
|
|
845
|
+
* });
|
|
846
|
+
* system.facts.auth.token // Namespaced access
|
|
847
|
+
* system.events.auth.login() // Namespaced events
|
|
848
|
+
* ```
|
|
849
|
+
*/
|
|
850
|
+
declare function createSystem<S extends ModuleSchema>(options: CreateSystemOptionsSingle<S>): SingleModuleSystem<S>;
|
|
851
|
+
declare function createSystem<const Modules extends ModulesMap>(options: CreateSystemOptionsNamed<Modules>): NamespacedSystem<Modules>;
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Builder Pattern API for Directive Modules
|
|
855
|
+
*
|
|
856
|
+
* An alternative, fluent API for creating modules that provides
|
|
857
|
+
* a more declarative style for module definition.
|
|
858
|
+
*
|
|
859
|
+
* @example
|
|
860
|
+
* ```typescript
|
|
861
|
+
* import { module, t } from '@directive-run/core';
|
|
862
|
+
*
|
|
863
|
+
* const counter = module("counter")
|
|
864
|
+
* .schema({
|
|
865
|
+
* facts: { count: t.number(), lastAction: t.string() },
|
|
866
|
+
* derivations: { doubled: t.number(), isPositive: t.boolean() },
|
|
867
|
+
* events: { increment: {}, decrement: {} },
|
|
868
|
+
* requirements: {},
|
|
869
|
+
* })
|
|
870
|
+
* .init((facts) => {
|
|
871
|
+
* facts.count = 0;
|
|
872
|
+
* facts.lastAction = "";
|
|
873
|
+
* })
|
|
874
|
+
* .derive({
|
|
875
|
+
* doubled: (facts) => facts.count * 2,
|
|
876
|
+
* isPositive: (facts) => facts.count > 0,
|
|
877
|
+
* })
|
|
878
|
+
* .events({
|
|
879
|
+
* increment: (facts) => {
|
|
880
|
+
* facts.count += 1;
|
|
881
|
+
* facts.lastAction = "increment";
|
|
882
|
+
* },
|
|
883
|
+
* decrement: (facts) => {
|
|
884
|
+
* facts.count -= 1;
|
|
885
|
+
* facts.lastAction = "decrement";
|
|
886
|
+
* },
|
|
887
|
+
* })
|
|
888
|
+
* .build();
|
|
889
|
+
* ```
|
|
890
|
+
*/
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Module builder interface - provides fluent API for building modules.
|
|
894
|
+
*
|
|
895
|
+
* @typeParam M - The module schema type (set after calling `.schema()`)
|
|
896
|
+
*/
|
|
897
|
+
interface ModuleBuilder<M extends ModuleSchema = ModuleSchema> {
|
|
898
|
+
/**
|
|
899
|
+
* Define the schema for this module (facts, derivations, events, requirements).
|
|
900
|
+
*/
|
|
901
|
+
schema<NewM extends ModuleSchema>(schema: NewM): ModuleBuilder<NewM>;
|
|
902
|
+
/**
|
|
903
|
+
* Define the initialization function for this module.
|
|
904
|
+
*/
|
|
905
|
+
init(initFn: (facts: Facts<M["facts"]>) => void): ModuleBuilder<M>;
|
|
906
|
+
/**
|
|
907
|
+
* Define derivation implementations for this module.
|
|
908
|
+
* Keys must match those declared in schema.derivations.
|
|
909
|
+
*/
|
|
910
|
+
derive<D extends Record<string, (facts: Facts<M["facts"]>, derive: DeriveAccessor<M>) => unknown>>(derivations: D): ModuleBuilder<M>;
|
|
911
|
+
/**
|
|
912
|
+
* Define event handler implementations for this module.
|
|
913
|
+
* Keys must match those declared in schema.events.
|
|
914
|
+
*/
|
|
915
|
+
events<E extends Record<string, (facts: Facts<M["facts"]>, payload: unknown) => void>>(events: E): ModuleBuilder<M>;
|
|
916
|
+
/**
|
|
917
|
+
* Define effects (side effects) for this module.
|
|
918
|
+
*/
|
|
919
|
+
effects(effects: EffectsDef<M["facts"]>): ModuleBuilder<M>;
|
|
920
|
+
/**
|
|
921
|
+
* Define constraints for this module.
|
|
922
|
+
*/
|
|
923
|
+
constraints<C extends Record<string, ConstraintDef<M>>>(constraints: C): ModuleBuilder<M>;
|
|
924
|
+
/**
|
|
925
|
+
* Define resolvers for this module.
|
|
926
|
+
*/
|
|
927
|
+
resolvers<R extends Record<string, ResolverDef<M>>>(resolvers: R): ModuleBuilder<M>;
|
|
928
|
+
/**
|
|
929
|
+
* Define lifecycle hooks for this module.
|
|
930
|
+
*/
|
|
931
|
+
hooks(hooks: ModuleHooks<M>): ModuleBuilder<M>;
|
|
932
|
+
/**
|
|
933
|
+
* Build the module definition.
|
|
934
|
+
*/
|
|
935
|
+
build(): ModuleDef<M>;
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Accessor for reading other derivations within a derivation function.
|
|
939
|
+
*/
|
|
940
|
+
type DeriveAccessor<M extends ModuleSchema> = M["derivations"] extends DerivationsSchema ? {
|
|
941
|
+
readonly [K in keyof M["derivations"]]: InferSchemaType<M["derivations"][K]>;
|
|
942
|
+
} : Record<string, never>;
|
|
943
|
+
/**
|
|
944
|
+
* Infer the TypeScript type from a schema type definition.
|
|
945
|
+
*/
|
|
946
|
+
type InferSchemaType<T> = T extends {
|
|
947
|
+
_type: infer U;
|
|
948
|
+
} ? U : any;
|
|
949
|
+
/**
|
|
950
|
+
* Constraint definition for the builder.
|
|
951
|
+
*/
|
|
952
|
+
interface ConstraintDef<M extends ModuleSchema> {
|
|
953
|
+
when: (facts: Facts<M["facts"]>) => boolean;
|
|
954
|
+
require: {
|
|
955
|
+
type: string;
|
|
956
|
+
[key: string]: unknown;
|
|
957
|
+
} | ((facts: Facts<M["facts"]>) => {
|
|
958
|
+
type: string;
|
|
959
|
+
[key: string]: unknown;
|
|
960
|
+
} | null);
|
|
961
|
+
priority?: number;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Resolver definition for the builder.
|
|
965
|
+
*/
|
|
966
|
+
interface ResolverDef<M extends ModuleSchema> {
|
|
967
|
+
requirement: string | ((req: {
|
|
968
|
+
type: string;
|
|
969
|
+
[key: string]: unknown;
|
|
970
|
+
}) => boolean);
|
|
971
|
+
resolve: (req: {
|
|
972
|
+
type: string;
|
|
973
|
+
[key: string]: unknown;
|
|
974
|
+
}, ctx: {
|
|
975
|
+
facts: Facts<M["facts"]>;
|
|
976
|
+
signal?: AbortSignal;
|
|
977
|
+
}) => void | Promise<void>;
|
|
978
|
+
retry?: {
|
|
979
|
+
attempts?: number;
|
|
980
|
+
backoff?: "linear" | "exponential";
|
|
981
|
+
delay?: number;
|
|
982
|
+
};
|
|
983
|
+
timeout?: number;
|
|
984
|
+
key?: (req: {
|
|
985
|
+
type: string;
|
|
986
|
+
[key: string]: unknown;
|
|
987
|
+
}) => string;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Create a new module builder.
|
|
991
|
+
*
|
|
992
|
+
* @param id - The unique identifier for this module
|
|
993
|
+
* @returns A module builder
|
|
994
|
+
*/
|
|
995
|
+
declare function module$1(id: string): ModuleBuilder<ModuleSchema>;
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* Constraint Builder API
|
|
999
|
+
*
|
|
1000
|
+
* Fluent builders for creating typed constraint definitions.
|
|
1001
|
+
*
|
|
1002
|
+
* @example Full builder
|
|
1003
|
+
* ```typescript
|
|
1004
|
+
* import { constraint } from '@directive-run/core';
|
|
1005
|
+
*
|
|
1006
|
+
* const escalate = constraint<typeof schema>()
|
|
1007
|
+
* .when(f => f.confidence < 0.7)
|
|
1008
|
+
* .require({ type: 'ESCALATE' })
|
|
1009
|
+
* .priority(50)
|
|
1010
|
+
* .build();
|
|
1011
|
+
* ```
|
|
1012
|
+
*
|
|
1013
|
+
* @example Quick shorthand
|
|
1014
|
+
* ```typescript
|
|
1015
|
+
* import { when } from '@directive-run/core';
|
|
1016
|
+
*
|
|
1017
|
+
* const pause = when<typeof schema>(f => f.errors > 3)
|
|
1018
|
+
* .require({ type: 'PAUSE' });
|
|
1019
|
+
* ```
|
|
1020
|
+
*/
|
|
1021
|
+
|
|
1022
|
+
type WhenFn<M extends ModuleSchema> = (facts: Facts<M["facts"]>) => boolean | Promise<boolean>;
|
|
1023
|
+
type RequireValue<M extends ModuleSchema> = RequirementOutput$1<InferRequirements<M>> | ((facts: Facts<M["facts"]>) => RequirementOutput$1<InferRequirements<M>>);
|
|
1024
|
+
/** Builder after constraint() — must call .when() first */
|
|
1025
|
+
interface ConstraintBuilderStart<M extends ModuleSchema> {
|
|
1026
|
+
when(condition: WhenFn<M>): ConstraintBuilderWithWhen<M>;
|
|
1027
|
+
}
|
|
1028
|
+
/** Builder after .when() — must call .require() next */
|
|
1029
|
+
interface ConstraintBuilderWithWhen<M extends ModuleSchema> {
|
|
1030
|
+
require(req: RequireValue<M>): ConstraintBuilderComplete<M>;
|
|
1031
|
+
}
|
|
1032
|
+
/** Builder after .require() — optional chaining + .build() */
|
|
1033
|
+
interface ConstraintBuilderComplete<M extends ModuleSchema> {
|
|
1034
|
+
priority(n: number): ConstraintBuilderComplete<M>;
|
|
1035
|
+
after(...ids: string[]): ConstraintBuilderComplete<M>;
|
|
1036
|
+
deps(...keys: string[]): ConstraintBuilderComplete<M>;
|
|
1037
|
+
timeout(ms: number): ConstraintBuilderComplete<M>;
|
|
1038
|
+
async(value: boolean): ConstraintBuilderComplete<M>;
|
|
1039
|
+
build(): TypedConstraintDef<M>;
|
|
1040
|
+
}
|
|
1041
|
+
/** Result from when().require() — a valid constraint with optional immutable chaining */
|
|
1042
|
+
type WhenConstraint<M extends ModuleSchema> = TypedConstraintDef<M> & {
|
|
1043
|
+
withPriority(n: number): WhenConstraint<M>;
|
|
1044
|
+
withAfter(...ids: string[]): WhenConstraint<M>;
|
|
1045
|
+
withDeps(...keys: string[]): WhenConstraint<M>;
|
|
1046
|
+
withTimeout(ms: number): WhenConstraint<M>;
|
|
1047
|
+
withAsync(value: boolean): WhenConstraint<M>;
|
|
1048
|
+
};
|
|
1049
|
+
/** Result from when() — must call .require() */
|
|
1050
|
+
interface WhenBuilder<M extends ModuleSchema> {
|
|
1051
|
+
require(req: RequireValue<M>): WhenConstraint<M>;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Create a constraint using the full builder pattern.
|
|
1055
|
+
* Requires `.when()`, `.require()`, and `.build()`.
|
|
1056
|
+
*
|
|
1057
|
+
* @example
|
|
1058
|
+
* ```typescript
|
|
1059
|
+
* const c = constraint<typeof schema>()
|
|
1060
|
+
* .when(f => f.phase === "red")
|
|
1061
|
+
* .require({ type: "TRANSITION", to: "green" })
|
|
1062
|
+
* .priority(50)
|
|
1063
|
+
* .after("healthCheck")
|
|
1064
|
+
* .build();
|
|
1065
|
+
* ```
|
|
1066
|
+
*/
|
|
1067
|
+
declare function constraint<M extends ModuleSchema>(): ConstraintBuilderStart<M>;
|
|
1068
|
+
/**
|
|
1069
|
+
* Quick shorthand for creating constraints.
|
|
1070
|
+
* Returns a valid constraint directly (no `.build()` needed).
|
|
1071
|
+
*
|
|
1072
|
+
* @example
|
|
1073
|
+
* ```typescript
|
|
1074
|
+
* const pause = when<typeof schema>(f => f.errors > 3)
|
|
1075
|
+
* .require({ type: 'PAUSE' });
|
|
1076
|
+
*
|
|
1077
|
+
* // With optional chaining (immutable — returns new constraint)
|
|
1078
|
+
* const halt = when<typeof schema>(f => f.errors > 10)
|
|
1079
|
+
* .require({ type: 'HALT' })
|
|
1080
|
+
* .withPriority(100)
|
|
1081
|
+
* .withAfter('healthCheck');
|
|
1082
|
+
* ```
|
|
1083
|
+
*/
|
|
1084
|
+
declare function when<M extends ModuleSchema>(condition: WhenFn<M>): WhenBuilder<M>;
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* System Builder API
|
|
1088
|
+
*
|
|
1089
|
+
* Fluent builder for creating Directive systems.
|
|
1090
|
+
*
|
|
1091
|
+
* @example Single module
|
|
1092
|
+
* ```typescript
|
|
1093
|
+
* import { system } from '@directive-run/core';
|
|
1094
|
+
*
|
|
1095
|
+
* const sys = system()
|
|
1096
|
+
* .module(counterModule)
|
|
1097
|
+
* .plugins([loggingPlugin()])
|
|
1098
|
+
* .debug({ timeTravel: true })
|
|
1099
|
+
* .build();
|
|
1100
|
+
* ```
|
|
1101
|
+
*
|
|
1102
|
+
* @example Multiple modules
|
|
1103
|
+
* ```typescript
|
|
1104
|
+
* const sys = system()
|
|
1105
|
+
* .modules({ auth: authModule, cart: cartModule })
|
|
1106
|
+
* .plugins([loggingPlugin()])
|
|
1107
|
+
* .build();
|
|
1108
|
+
* ```
|
|
1109
|
+
*/
|
|
1110
|
+
|
|
1111
|
+
/** Initial builder — must choose .module() or .modules() */
|
|
1112
|
+
interface SystemBuilderStart {
|
|
1113
|
+
module<S extends ModuleSchema>(mod: ModuleDef<S>): SingleModuleSystemBuilder<S>;
|
|
1114
|
+
modules<const Modules extends ModulesMap>(mods: Modules): NamespacedSystemBuilder<Modules>;
|
|
1115
|
+
}
|
|
1116
|
+
/** Builder for single-module system */
|
|
1117
|
+
interface SingleModuleSystemBuilder<S extends ModuleSchema> {
|
|
1118
|
+
plugins(plugins: Array<Plugin<ModuleSchema>>): SingleModuleSystemBuilder<S>;
|
|
1119
|
+
debug(config: DebugConfig): SingleModuleSystemBuilder<S>;
|
|
1120
|
+
errorBoundary(config: ErrorBoundaryConfig): SingleModuleSystemBuilder<S>;
|
|
1121
|
+
tickMs(ms: number): SingleModuleSystemBuilder<S>;
|
|
1122
|
+
zeroConfig(enabled?: boolean): SingleModuleSystemBuilder<S>;
|
|
1123
|
+
initialFacts(facts: Partial<InferFacts<S>>): SingleModuleSystemBuilder<S>;
|
|
1124
|
+
build(): SingleModuleSystem<S>;
|
|
1125
|
+
}
|
|
1126
|
+
/** Builder for namespaced multi-module system */
|
|
1127
|
+
interface NamespacedSystemBuilder<Modules extends ModulesMap> {
|
|
1128
|
+
plugins(plugins: Array<Plugin<ModuleSchema>>): NamespacedSystemBuilder<Modules>;
|
|
1129
|
+
debug(config: DebugConfig): NamespacedSystemBuilder<Modules>;
|
|
1130
|
+
errorBoundary(config: ErrorBoundaryConfig): NamespacedSystemBuilder<Modules>;
|
|
1131
|
+
tickMs(ms: number): NamespacedSystemBuilder<Modules>;
|
|
1132
|
+
zeroConfig(enabled?: boolean): NamespacedSystemBuilder<Modules>;
|
|
1133
|
+
initialFacts(facts: Partial<{
|
|
1134
|
+
[K in keyof Modules]: Partial<InferFacts<ExtractSchema<Modules[K]>>>;
|
|
1135
|
+
}>): NamespacedSystemBuilder<Modules>;
|
|
1136
|
+
initOrder(order: "auto" | "declaration" | Array<keyof Modules & string>): NamespacedSystemBuilder<Modules>;
|
|
1137
|
+
build(): NamespacedSystem<Modules>;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Create a system using the fluent builder pattern.
|
|
1141
|
+
* Choose `.module()` for single-module or `.modules()` for namespaced.
|
|
1142
|
+
*
|
|
1143
|
+
* @example
|
|
1144
|
+
* ```typescript
|
|
1145
|
+
* const sys = system()
|
|
1146
|
+
* .module(counterModule)
|
|
1147
|
+
* .plugins([loggingPlugin()])
|
|
1148
|
+
* .build();
|
|
1149
|
+
* ```
|
|
1150
|
+
*/
|
|
1151
|
+
declare function system(): SystemBuilderStart;
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Requirement Status Utilities
|
|
1155
|
+
*
|
|
1156
|
+
* Provides reactive tracking of requirement status for UI feedback.
|
|
1157
|
+
*/
|
|
1158
|
+
|
|
1159
|
+
/** Status of a requirement type */
|
|
1160
|
+
interface RequirementTypeStatus {
|
|
1161
|
+
/** Number of pending (unmet) requirements of this type */
|
|
1162
|
+
pending: number;
|
|
1163
|
+
/** Number of inflight (being resolved) requirements of this type */
|
|
1164
|
+
inflight: number;
|
|
1165
|
+
/** Number of failed requirements of this type */
|
|
1166
|
+
failed: number;
|
|
1167
|
+
/** Whether any requirements of this type are loading (pending or inflight) */
|
|
1168
|
+
isLoading: boolean;
|
|
1169
|
+
/** Whether any requirements of this type have failed */
|
|
1170
|
+
hasError: boolean;
|
|
1171
|
+
/** Last error for this type (if any) */
|
|
1172
|
+
lastError: Error | null;
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Create a plugin that tracks requirement status for reactive UI updates.
|
|
1176
|
+
*
|
|
1177
|
+
* @example
|
|
1178
|
+
* ```typescript
|
|
1179
|
+
* import { createRequirementStatusPlugin } from '@directive-run/core';
|
|
1180
|
+
*
|
|
1181
|
+
* const statusPlugin = createRequirementStatusPlugin();
|
|
1182
|
+
*
|
|
1183
|
+
* const system = createSystem({
|
|
1184
|
+
* modules: [myModule],
|
|
1185
|
+
* plugins: [statusPlugin.plugin],
|
|
1186
|
+
* });
|
|
1187
|
+
*
|
|
1188
|
+
* // Get status for a requirement type
|
|
1189
|
+
* const status = statusPlugin.getStatus("FETCH_USER");
|
|
1190
|
+
* console.log(status.isLoading, status.hasError);
|
|
1191
|
+
*
|
|
1192
|
+
* // Subscribe to status changes
|
|
1193
|
+
* const unsubscribe = statusPlugin.subscribe(() => {
|
|
1194
|
+
* console.log("Status changed:", statusPlugin.getStatus("FETCH_USER"));
|
|
1195
|
+
* });
|
|
1196
|
+
* ```
|
|
1197
|
+
*/
|
|
1198
|
+
declare function createRequirementStatusPlugin(): {
|
|
1199
|
+
plugin: Plugin<never>;
|
|
1200
|
+
getStatus: (type: string) => RequirementTypeStatus;
|
|
1201
|
+
getAllStatus: () => Map<string, RequirementTypeStatus>;
|
|
1202
|
+
subscribe: (listener: () => void) => () => void;
|
|
1203
|
+
reset: () => void;
|
|
1204
|
+
};
|
|
1205
|
+
/**
|
|
1206
|
+
* Create a hook factory for requirement status.
|
|
1207
|
+
* This is designed to be used with React's useSyncExternalStore.
|
|
1208
|
+
*
|
|
1209
|
+
* @example
|
|
1210
|
+
* ```typescript
|
|
1211
|
+
* import { useSyncExternalStore } from 'react';
|
|
1212
|
+
* import { createRequirementStatusPlugin, createStatusHook } from '@directive-run/core';
|
|
1213
|
+
*
|
|
1214
|
+
* const statusPlugin = createRequirementStatusPlugin();
|
|
1215
|
+
* const useRequirementStatus = createStatusHook(statusPlugin);
|
|
1216
|
+
*
|
|
1217
|
+
* function MyComponent() {
|
|
1218
|
+
* const status = useRequirementStatus("FETCH_USER");
|
|
1219
|
+
* if (status.isLoading) return <Spinner />;
|
|
1220
|
+
* if (status.hasError) return <Error error={status.lastError} />;
|
|
1221
|
+
* return <Content />;
|
|
1222
|
+
* }
|
|
1223
|
+
* ```
|
|
1224
|
+
*/
|
|
1225
|
+
declare function createStatusHook(statusPlugin: ReturnType<typeof createRequirementStatusPlugin>): (type: string) => RequirementTypeStatus;
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* System with Status Plugin Helper
|
|
1229
|
+
*
|
|
1230
|
+
* Convenience function for creating a system with status tracking enabled.
|
|
1231
|
+
*/
|
|
1232
|
+
|
|
1233
|
+
/** Options for createSystemWithStatus */
|
|
1234
|
+
interface CreateSystemWithStatusOptions<M extends ModuleSchema> {
|
|
1235
|
+
/** The module to use for the system */
|
|
1236
|
+
module: ModuleDef<M>;
|
|
1237
|
+
/** Additional plugins to include alongside the status plugin */
|
|
1238
|
+
plugins?: Plugin<any>[];
|
|
1239
|
+
/** Debug configuration */
|
|
1240
|
+
debug?: DebugConfig;
|
|
1241
|
+
/** Error boundary configuration */
|
|
1242
|
+
errorBoundary?: ErrorBoundaryConfig;
|
|
1243
|
+
/** Tick interval in milliseconds */
|
|
1244
|
+
tickMs?: number;
|
|
1245
|
+
/** Enable zero-config mode */
|
|
1246
|
+
zeroConfig?: boolean;
|
|
1247
|
+
/** Initial facts to set on the system */
|
|
1248
|
+
initialFacts?: Record<string, any>;
|
|
1249
|
+
}
|
|
1250
|
+
/** Return type for createSystemWithStatus */
|
|
1251
|
+
interface SystemWithStatus<M extends ModuleSchema> {
|
|
1252
|
+
/**
|
|
1253
|
+
* The Directive system instance.
|
|
1254
|
+
* This is a SingleModuleSystem - use system.facts, system.dispatch(), etc.
|
|
1255
|
+
*/
|
|
1256
|
+
system: SingleModuleSystem<M>;
|
|
1257
|
+
/** The status plugin for use with useRequirementStatus hooks */
|
|
1258
|
+
statusPlugin: ReturnType<typeof createRequirementStatusPlugin>;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Create a Directive system with a status plugin pre-configured.
|
|
1262
|
+
*
|
|
1263
|
+
* This is a convenience wrapper around `createSystem` and `createRequirementStatusPlugin`
|
|
1264
|
+
* that handles the wiring automatically. The status plugin is added to the system's
|
|
1265
|
+
* plugins array so it receives lifecycle events.
|
|
1266
|
+
*
|
|
1267
|
+
* @param options - System configuration options
|
|
1268
|
+
* @returns An object containing both the system and the statusPlugin
|
|
1269
|
+
*
|
|
1270
|
+
* @example
|
|
1271
|
+
* ```tsx
|
|
1272
|
+
* import { createSystemWithStatus } from '@directive-run/core';
|
|
1273
|
+
* import { useRequirementStatus, useFact } from '@directive-run/react';
|
|
1274
|
+
*
|
|
1275
|
+
* // Simple setup - no provider needed
|
|
1276
|
+
* const { system, statusPlugin } = createSystemWithStatus({
|
|
1277
|
+
* module: myModule,
|
|
1278
|
+
* });
|
|
1279
|
+
* system.start();
|
|
1280
|
+
*
|
|
1281
|
+
* function App() {
|
|
1282
|
+
* const data = useFact(system, "data");
|
|
1283
|
+
* return <LoadingIndicator />;
|
|
1284
|
+
* }
|
|
1285
|
+
*
|
|
1286
|
+
* function LoadingIndicator() {
|
|
1287
|
+
* const status = useRequirementStatus(statusPlugin, "FETCH_DATA");
|
|
1288
|
+
* if (status.isLoading) return <Spinner />;
|
|
1289
|
+
* if (status.hasError) return <Error message={status.lastError?.message} />;
|
|
1290
|
+
* return <Content />;
|
|
1291
|
+
* }
|
|
1292
|
+
* ```
|
|
1293
|
+
*/
|
|
1294
|
+
declare function createSystemWithStatus<M extends ModuleSchema>(options: CreateSystemWithStatusOptions<M>): SystemWithStatus<M>;
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* Requirements - Typed requirement identity with custom dedupe keys
|
|
1298
|
+
*
|
|
1299
|
+
* Features:
|
|
1300
|
+
* - Type-safe requirement definitions
|
|
1301
|
+
* - Stable identity generation
|
|
1302
|
+
* - Custom key functions for deduplication control
|
|
1303
|
+
* - Requirement comparison and hashing
|
|
1304
|
+
*/
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Generate a stable ID for a requirement.
|
|
1308
|
+
* Uses type + sorted properties by default.
|
|
1309
|
+
*/
|
|
1310
|
+
declare function generateRequirementId(req: Requirement, keyFn?: RequirementKeyFn): string;
|
|
1311
|
+
/**
|
|
1312
|
+
* Helper to create typed requirements with a fluent API.
|
|
1313
|
+
*
|
|
1314
|
+
* Creates a factory function that produces requirements with a specific type.
|
|
1315
|
+
* Useful for creating requirements in constraint definitions.
|
|
1316
|
+
*
|
|
1317
|
+
* @param type - The requirement type string
|
|
1318
|
+
* @returns A factory function that creates requirements with the given type
|
|
1319
|
+
*
|
|
1320
|
+
* @example
|
|
1321
|
+
* ```typescript
|
|
1322
|
+
* // Create a requirement factory
|
|
1323
|
+
* const fetchUser = req("FETCH_USER");
|
|
1324
|
+
*
|
|
1325
|
+
* // Use in constraint definition
|
|
1326
|
+
* constraints: {
|
|
1327
|
+
* needsUser: {
|
|
1328
|
+
* when: (facts) => facts.userId && !facts.user,
|
|
1329
|
+
* require: fetchUser({ userId: 123, priority: "high" }),
|
|
1330
|
+
* },
|
|
1331
|
+
* }
|
|
1332
|
+
*
|
|
1333
|
+
* // Results in: { type: "FETCH_USER", userId: 123, priority: "high" }
|
|
1334
|
+
* ```
|
|
1335
|
+
*/
|
|
1336
|
+
declare function req<T extends string>(type: T): <P extends Record<string, unknown>>(props: P) => Requirement & {
|
|
1337
|
+
type: T;
|
|
1338
|
+
} & P;
|
|
1339
|
+
/**
|
|
1340
|
+
* Check if a requirement matches a type.
|
|
1341
|
+
*/
|
|
1342
|
+
declare function isRequirementType<T extends string>(req: Requirement, type: T): req is Requirement & {
|
|
1343
|
+
type: T;
|
|
1344
|
+
};
|
|
1345
|
+
/**
|
|
1346
|
+
* Create a type guard for resolver `requirement` predicate.
|
|
1347
|
+
* Cleaner alternative to writing verbose type guards.
|
|
1348
|
+
*
|
|
1349
|
+
* @example
|
|
1350
|
+
* ```typescript
|
|
1351
|
+
* // With explicit requirement type (recommended for complex types)
|
|
1352
|
+
* interface FetchUserRequirement { type: "FETCH_USER"; userId: string }
|
|
1353
|
+
* requirement: forType<FetchUserRequirement>("FETCH_USER"),
|
|
1354
|
+
* key: (req) => req.userId, // req is FetchUserRequirement
|
|
1355
|
+
*
|
|
1356
|
+
* // Or simple string literal (for basic types)
|
|
1357
|
+
* requirement: forType("FETCH_USER"),
|
|
1358
|
+
* key: (req) => req.type, // req is Requirement & { type: "FETCH_USER" }
|
|
1359
|
+
* ```
|
|
1360
|
+
*/
|
|
1361
|
+
declare function forType<R extends Requirement>(type: R["type"]): (req: Requirement) => req is R;
|
|
1362
|
+
declare function forType<T extends string>(type: T): (req: Requirement) => req is Requirement & {
|
|
1363
|
+
type: T;
|
|
1364
|
+
};
|
|
1365
|
+
/**
|
|
1366
|
+
* A set of requirements with automatic deduplication by ID.
|
|
1367
|
+
*
|
|
1368
|
+
* Requirements are uniquely identified by their ID (generated from type + properties).
|
|
1369
|
+
* When adding a requirement with a duplicate ID, the first one wins.
|
|
1370
|
+
*
|
|
1371
|
+
* @example
|
|
1372
|
+
* ```typescript
|
|
1373
|
+
* const set = new RequirementSet();
|
|
1374
|
+
*
|
|
1375
|
+
* // Add requirements
|
|
1376
|
+
* set.add(createRequirementWithId({ type: "FETCH_USER", userId: 1 }, "constraint1"));
|
|
1377
|
+
* set.add(createRequirementWithId({ type: "FETCH_USER", userId: 1 }, "constraint2")); // Ignored (duplicate)
|
|
1378
|
+
*
|
|
1379
|
+
* // Check and retrieve
|
|
1380
|
+
* console.log(set.size); // 1
|
|
1381
|
+
* console.log(set.has("FETCH_USER:{\"userId\":1}")); // true
|
|
1382
|
+
*
|
|
1383
|
+
* // Diff with another set
|
|
1384
|
+
* const newSet = new RequirementSet();
|
|
1385
|
+
* newSet.add(createRequirementWithId({ type: "FETCH_USER", userId: 2 }, "constraint1"));
|
|
1386
|
+
* const { added, removed } = newSet.diff(set);
|
|
1387
|
+
* // added: [{ type: "FETCH_USER", userId: 2 }]
|
|
1388
|
+
* // removed: [{ type: "FETCH_USER", userId: 1 }]
|
|
1389
|
+
* ```
|
|
1390
|
+
*/
|
|
1391
|
+
declare class RequirementSet {
|
|
1392
|
+
private map;
|
|
1393
|
+
/**
|
|
1394
|
+
* Add a requirement to the set.
|
|
1395
|
+
* If a requirement with the same ID already exists, it is ignored (first wins).
|
|
1396
|
+
* @param req - The requirement with its computed ID
|
|
1397
|
+
*/
|
|
1398
|
+
add(req: RequirementWithId): void;
|
|
1399
|
+
/** Remove a requirement by ID */
|
|
1400
|
+
remove(id: string): boolean;
|
|
1401
|
+
/** Check if a requirement exists */
|
|
1402
|
+
has(id: string): boolean;
|
|
1403
|
+
/** Get a requirement by ID */
|
|
1404
|
+
get(id: string): RequirementWithId | undefined;
|
|
1405
|
+
/** Get all requirements */
|
|
1406
|
+
all(): RequirementWithId[];
|
|
1407
|
+
/** Get all requirement IDs */
|
|
1408
|
+
ids(): string[];
|
|
1409
|
+
/** Get the count of requirements */
|
|
1410
|
+
get size(): number;
|
|
1411
|
+
/** Clear all requirements */
|
|
1412
|
+
clear(): void;
|
|
1413
|
+
/** Create a copy */
|
|
1414
|
+
clone(): RequirementSet;
|
|
1415
|
+
/** Diff with another set - returns added and removed */
|
|
1416
|
+
diff(other: RequirementSet): {
|
|
1417
|
+
added: RequirementWithId[];
|
|
1418
|
+
removed: RequirementWithId[];
|
|
1419
|
+
unchanged: RequirementWithId[];
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/**
|
|
1424
|
+
* Derivations - Auto-tracked computed values with composition
|
|
1425
|
+
*
|
|
1426
|
+
* Features:
|
|
1427
|
+
* - Automatic dependency tracking (no manual deps arrays)
|
|
1428
|
+
* - Memoization with smart invalidation
|
|
1429
|
+
* - Derivation composition (derivations can depend on other derivations)
|
|
1430
|
+
* - Circular dependency detection
|
|
1431
|
+
* - Lazy evaluation
|
|
1432
|
+
*/
|
|
1433
|
+
|
|
1434
|
+
interface DerivationsManager<S extends Schema, D extends DerivationsDef<S>> {
|
|
1435
|
+
/** Get a derived value (computes if stale) */
|
|
1436
|
+
get<K extends keyof D>(id: K): ReturnType<D[K]>;
|
|
1437
|
+
/** Check if a derivation is stale */
|
|
1438
|
+
isStale(id: keyof D): boolean;
|
|
1439
|
+
/** Invalidate derivations that depend on a fact key */
|
|
1440
|
+
invalidate(factKey: string): void;
|
|
1441
|
+
/** Invalidate derivations for multiple fact keys, notifying listeners once at the end */
|
|
1442
|
+
invalidateMany(factKeys: Iterable<string>): void;
|
|
1443
|
+
/** Invalidate all derivations */
|
|
1444
|
+
invalidateAll(): void;
|
|
1445
|
+
/** Subscribe to derivation changes */
|
|
1446
|
+
subscribe(ids: Array<keyof D>, listener: () => void): () => void;
|
|
1447
|
+
/** Get the proxy for composition */
|
|
1448
|
+
getProxy(): DerivedValues<S, D>;
|
|
1449
|
+
/** Get dependencies for a derivation */
|
|
1450
|
+
getDependencies(id: keyof D): Set<string>;
|
|
1451
|
+
/** Register new derivation definitions (for dynamic module registration) */
|
|
1452
|
+
registerDefinitions(newDefs: DerivationsDef<S>): void;
|
|
1453
|
+
}
|
|
1454
|
+
/** Options for creating a derivations manager */
|
|
1455
|
+
interface CreateDerivationsOptions<S extends Schema, D extends DerivationsDef<S>> {
|
|
1456
|
+
definitions: D;
|
|
1457
|
+
facts: Facts<S>;
|
|
1458
|
+
store: FactsStore<S>;
|
|
1459
|
+
/** Callback when a derivation is computed */
|
|
1460
|
+
onCompute?: (id: string, value: unknown, deps: string[]) => void;
|
|
1461
|
+
/** Callback when a derivation is invalidated */
|
|
1462
|
+
onInvalidate?: (id: string) => void;
|
|
1463
|
+
/** Callback when a derivation errors */
|
|
1464
|
+
onError?: (id: string, error: unknown) => void;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Create a manager for lazily-evaluated, auto-tracked derived values.
|
|
1468
|
+
*
|
|
1469
|
+
* Derivations are memoized computations that automatically track which facts
|
|
1470
|
+
* they read. When a tracked fact changes, the derivation is invalidated and
|
|
1471
|
+
* recomputed on next access. Derivations can depend on other derivations
|
|
1472
|
+
* (composition), and circular dependencies are detected at compute time.
|
|
1473
|
+
*
|
|
1474
|
+
* Notifications are deferred during invalidation so listeners always see
|
|
1475
|
+
* consistent state across multiple simultaneous fact changes.
|
|
1476
|
+
*
|
|
1477
|
+
* @param options - Derivation definitions, facts proxy, store, and optional lifecycle callbacks
|
|
1478
|
+
* @returns A `DerivationsManager` with get/invalidate/subscribe/getProxy methods
|
|
1479
|
+
*/
|
|
1480
|
+
declare function createDerivationsManager<S extends Schema, D extends DerivationsDef<S>>(options: CreateDerivationsOptions<S, D>): DerivationsManager<S, D>;
|
|
1481
|
+
|
|
1482
|
+
/**
|
|
1483
|
+
* Effects - Fire-and-forget side effects
|
|
1484
|
+
*
|
|
1485
|
+
* Features:
|
|
1486
|
+
* - Separate from requirement resolution
|
|
1487
|
+
* - Error isolation (never breaks reconciliation)
|
|
1488
|
+
* - Optional explicit dependencies for optimization
|
|
1489
|
+
* - Runs after facts stabilize
|
|
1490
|
+
*
|
|
1491
|
+
* IMPORTANT: Auto-tracking limitations
|
|
1492
|
+
* ------------------------------------
|
|
1493
|
+
* When using auto-tracking (no explicit `deps`), only SYNCHRONOUS fact accesses
|
|
1494
|
+
* are tracked. If your effect reads facts after an `await`, those reads are NOT
|
|
1495
|
+
* tracked and won't trigger the effect on future changes.
|
|
1496
|
+
*
|
|
1497
|
+
* For async effects, always use explicit `deps`:
|
|
1498
|
+
* @example
|
|
1499
|
+
* ```typescript
|
|
1500
|
+
* effects: {
|
|
1501
|
+
* // BAD: fetchData is async, facts.userId read after await won't be tracked
|
|
1502
|
+
* badEffect: {
|
|
1503
|
+
* run: async (facts) => {
|
|
1504
|
+
* await someAsyncOp();
|
|
1505
|
+
* console.log(facts.userId); // NOT tracked!
|
|
1506
|
+
* },
|
|
1507
|
+
* },
|
|
1508
|
+
* // GOOD: explicit deps for async effects
|
|
1509
|
+
* goodEffect: {
|
|
1510
|
+
* deps: ["userId"],
|
|
1511
|
+
* run: async (facts) => {
|
|
1512
|
+
* await someAsyncOp();
|
|
1513
|
+
* console.log(facts.userId); // Works because we declared the dep
|
|
1514
|
+
* },
|
|
1515
|
+
* },
|
|
1516
|
+
* }
|
|
1517
|
+
* ```
|
|
1518
|
+
*/
|
|
1519
|
+
|
|
1520
|
+
interface EffectsManager<_S extends Schema = Schema> {
|
|
1521
|
+
/** Run all effects that should trigger based on changes */
|
|
1522
|
+
runEffects(changedKeys: Set<string>): Promise<void>;
|
|
1523
|
+
/** Run all effects unconditionally */
|
|
1524
|
+
runAll(): Promise<void>;
|
|
1525
|
+
/** Disable an effect */
|
|
1526
|
+
disable(id: string): void;
|
|
1527
|
+
/** Enable an effect */
|
|
1528
|
+
enable(id: string): void;
|
|
1529
|
+
/** Check if an effect is enabled */
|
|
1530
|
+
isEnabled(id: string): boolean;
|
|
1531
|
+
/** Run all stored cleanup functions (called on system stop/destroy) */
|
|
1532
|
+
cleanupAll(): void;
|
|
1533
|
+
/** Register new effect definitions (for dynamic module registration) */
|
|
1534
|
+
registerDefinitions(newDefs: EffectsDef<Schema>): void;
|
|
1535
|
+
}
|
|
1536
|
+
/** Options for creating an effects manager */
|
|
1537
|
+
interface CreateEffectsOptions<S extends Schema> {
|
|
1538
|
+
definitions: EffectsDef<S>;
|
|
1539
|
+
facts: Facts<S>;
|
|
1540
|
+
store: FactsStore<S>;
|
|
1541
|
+
/** Callback when an effect runs */
|
|
1542
|
+
onRun?: (id: string) => void;
|
|
1543
|
+
/** Callback when an effect errors */
|
|
1544
|
+
onError?: (id: string, error: unknown) => void;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Create a manager for fire-and-forget side effects that run after facts
|
|
1548
|
+
* stabilize.
|
|
1549
|
+
*
|
|
1550
|
+
* Effects support auto-tracked dependencies (re-tracked on every run to
|
|
1551
|
+
* capture conditional reads) or explicit `deps` arrays. Each effect can
|
|
1552
|
+
* return a cleanup function that runs before the next execution or on
|
|
1553
|
+
* system stop. Errors in effects are isolated and never break the
|
|
1554
|
+
* reconciliation loop.
|
|
1555
|
+
*
|
|
1556
|
+
* @param options - Effect definitions, facts proxy, store, and optional lifecycle callbacks
|
|
1557
|
+
* @returns An `EffectsManager` with runEffects/runAll/enable/disable/cleanupAll methods
|
|
1558
|
+
*/
|
|
1559
|
+
declare function createEffectsManager<S extends Schema>(options: CreateEffectsOptions<S>): EffectsManager<S>;
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* Constraints - Rules that produce requirements when conditions aren't met
|
|
1563
|
+
*
|
|
1564
|
+
* Features:
|
|
1565
|
+
* - Sync and async constraint evaluation
|
|
1566
|
+
* - Priority ordering (higher runs first)
|
|
1567
|
+
* - Timeout handling for async constraints
|
|
1568
|
+
* - Error isolation
|
|
1569
|
+
*/
|
|
1570
|
+
|
|
1571
|
+
interface ConstraintsManager<_S extends Schema> {
|
|
1572
|
+
/** Evaluate all constraints and return unmet requirements */
|
|
1573
|
+
evaluate(changedKeys?: Set<string>): Promise<RequirementWithId[]>;
|
|
1574
|
+
/** Get the current state of a constraint */
|
|
1575
|
+
getState(id: string): ConstraintState | undefined;
|
|
1576
|
+
/** Get all constraint states */
|
|
1577
|
+
getAllStates(): ConstraintState[];
|
|
1578
|
+
/** Disable a constraint */
|
|
1579
|
+
disable(id: string): void;
|
|
1580
|
+
/** Enable a constraint */
|
|
1581
|
+
enable(id: string): void;
|
|
1582
|
+
/** Invalidate constraints that depend on the given fact key */
|
|
1583
|
+
invalidate(factKey: string): void;
|
|
1584
|
+
/** Mark a constraint's resolver as completed (for `after` ordering) */
|
|
1585
|
+
markResolved(constraintId: string): void;
|
|
1586
|
+
/** Check if a constraint has been resolved (for `after` ordering) */
|
|
1587
|
+
isResolved(constraintId: string): boolean;
|
|
1588
|
+
/** Register new constraint definitions (for dynamic module registration) */
|
|
1589
|
+
registerDefinitions(newDefs: ConstraintsDef<Schema>): void;
|
|
1590
|
+
}
|
|
1591
|
+
/** Options for creating a constraints manager */
|
|
1592
|
+
interface CreateConstraintsOptions<S extends Schema> {
|
|
1593
|
+
definitions: ConstraintsDef<S>;
|
|
1594
|
+
facts: Facts<S>;
|
|
1595
|
+
/** Custom key functions for requirements (by constraint ID) */
|
|
1596
|
+
requirementKeys?: Record<string, RequirementKeyFn>;
|
|
1597
|
+
/** Default timeout for async constraints (ms) */
|
|
1598
|
+
defaultTimeout?: number;
|
|
1599
|
+
/** Callback when a constraint is evaluated */
|
|
1600
|
+
onEvaluate?: (id: string, active: boolean) => void;
|
|
1601
|
+
/** Callback when a constraint errors */
|
|
1602
|
+
onError?: (id: string, error: unknown) => void;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Create a manager that evaluates constraint rules and produces unmet
|
|
1606
|
+
* requirements.
|
|
1607
|
+
*
|
|
1608
|
+
* Constraints are evaluated in priority order (higher first), with
|
|
1609
|
+
* topological ordering for same-priority constraints connected by `after`
|
|
1610
|
+
* dependencies. Supports sync and async `when()` predicates, incremental
|
|
1611
|
+
* evaluation based on changed fact keys, and per-constraint enable/disable.
|
|
1612
|
+
*
|
|
1613
|
+
* @param options - Constraint definitions, facts proxy, custom requirement key functions, and lifecycle callbacks
|
|
1614
|
+
* @returns A `ConstraintsManager` with evaluate/invalidate/enable/disable/markResolved methods
|
|
1615
|
+
*/
|
|
1616
|
+
declare function createConstraintsManager<S extends Schema>(options: CreateConstraintsOptions<S>): ConstraintsManager<S>;
|
|
1617
|
+
|
|
1618
|
+
/**
|
|
1619
|
+
* Resolvers - Capability-based handlers for requirements
|
|
1620
|
+
*
|
|
1621
|
+
* Features:
|
|
1622
|
+
* - Capability matching (handles predicate)
|
|
1623
|
+
* - Custom dedupe keys
|
|
1624
|
+
* - Retry policies with exponential backoff
|
|
1625
|
+
* - Batched resolution for similar requirements
|
|
1626
|
+
* - Cancellation via AbortController
|
|
1627
|
+
*/
|
|
1628
|
+
|
|
1629
|
+
/** Inflight resolver info */
|
|
1630
|
+
interface InflightInfo {
|
|
1631
|
+
id: string;
|
|
1632
|
+
resolverId: string;
|
|
1633
|
+
startedAt: number;
|
|
1634
|
+
}
|
|
1635
|
+
interface ResolversManager<_S extends Schema> {
|
|
1636
|
+
/** Start resolving a requirement */
|
|
1637
|
+
resolve(req: RequirementWithId): void;
|
|
1638
|
+
/** Cancel a resolver by requirement ID */
|
|
1639
|
+
cancel(requirementId: string): void;
|
|
1640
|
+
/** Cancel all inflight resolvers */
|
|
1641
|
+
cancelAll(): void;
|
|
1642
|
+
/** Get status of a resolver by requirement ID */
|
|
1643
|
+
getStatus(requirementId: string): ResolverStatus;
|
|
1644
|
+
/** Get all inflight requirement IDs */
|
|
1645
|
+
getInflight(): string[];
|
|
1646
|
+
/** Get full info for all inflight resolvers */
|
|
1647
|
+
getInflightInfo(): InflightInfo[];
|
|
1648
|
+
/** Check if a requirement is being resolved */
|
|
1649
|
+
isResolving(requirementId: string): boolean;
|
|
1650
|
+
/** Process batched requirements (called periodically) */
|
|
1651
|
+
processBatches(): void;
|
|
1652
|
+
/** Register new resolver definitions (for dynamic module registration) */
|
|
1653
|
+
registerDefinitions(newDefs: ResolversDef<Schema>): void;
|
|
1654
|
+
}
|
|
1655
|
+
/** Options for creating a resolvers manager */
|
|
1656
|
+
interface CreateResolversOptions<S extends Schema> {
|
|
1657
|
+
definitions: ResolversDef<S>;
|
|
1658
|
+
facts: Facts<S>;
|
|
1659
|
+
store: FactsStore<S>;
|
|
1660
|
+
/** Callback when a resolver starts */
|
|
1661
|
+
onStart?: (resolver: string, req: RequirementWithId) => void;
|
|
1662
|
+
/** Callback when a resolver completes */
|
|
1663
|
+
onComplete?: (resolver: string, req: RequirementWithId, duration: number) => void;
|
|
1664
|
+
/** Callback when a resolver errors */
|
|
1665
|
+
onError?: (resolver: string, req: RequirementWithId, error: unknown) => void;
|
|
1666
|
+
/** Callback when a resolver retries */
|
|
1667
|
+
onRetry?: (resolver: string, req: RequirementWithId, attempt: number) => void;
|
|
1668
|
+
/** Callback when a resolver is canceled */
|
|
1669
|
+
onCancel?: (resolver: string, req: RequirementWithId) => void;
|
|
1670
|
+
/** Callback when resolution cycle completes (for reconciliation) */
|
|
1671
|
+
onResolutionComplete?: () => void;
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Create a manager that fulfills requirements by matching them to resolver
|
|
1675
|
+
* handlers.
|
|
1676
|
+
*
|
|
1677
|
+
* Resolvers are matched by requirement type (string or predicate). Each
|
|
1678
|
+
* resolution runs with an `AbortController` for cancellation, configurable
|
|
1679
|
+
* retry policies (none/linear/exponential backoff), and optional batching
|
|
1680
|
+
* for grouping similar requirements. Duplicate in-flight requirements are
|
|
1681
|
+
* automatically deduplicated.
|
|
1682
|
+
*
|
|
1683
|
+
* @param options - Resolver definitions, facts proxy, store, and lifecycle callbacks (onStart/onComplete/onError/onRetry/onCancel/onResolutionComplete)
|
|
1684
|
+
* @returns A `ResolversManager` with resolve/cancel/cancelAll/getStatus/processBatches methods
|
|
1685
|
+
*/
|
|
1686
|
+
declare function createResolversManager<S extends Schema>(options: CreateResolversOptions<S>): ResolversManager<S>;
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* Plugin Architecture - Extensible middleware for Directive
|
|
1690
|
+
*
|
|
1691
|
+
* Features:
|
|
1692
|
+
* - Lifecycle hooks for all engine events
|
|
1693
|
+
* - Multiple plugins can be composed
|
|
1694
|
+
* - Plugins execute in registration order
|
|
1695
|
+
*/
|
|
1696
|
+
|
|
1697
|
+
interface PluginManager<_S extends Schema = any> {
|
|
1698
|
+
/** Register a plugin */
|
|
1699
|
+
register(plugin: Plugin<any>): void;
|
|
1700
|
+
/** Unregister a plugin by name */
|
|
1701
|
+
unregister(name: string): void;
|
|
1702
|
+
/** Get all registered plugins */
|
|
1703
|
+
getPlugins(): Plugin<any>[];
|
|
1704
|
+
emitInit(system: System<any>): Promise<void>;
|
|
1705
|
+
emitStart(system: System<any>): void;
|
|
1706
|
+
emitStop(system: System<any>): void;
|
|
1707
|
+
emitDestroy(system: System<any>): void;
|
|
1708
|
+
emitFactSet(key: string, value: unknown, prev: unknown): void;
|
|
1709
|
+
emitFactDelete(key: string, prev: unknown): void;
|
|
1710
|
+
emitFactsBatch(changes: FactChange[]): void;
|
|
1711
|
+
emitDerivationCompute(id: string, value: unknown, deps: string[]): void;
|
|
1712
|
+
emitDerivationInvalidate(id: string): void;
|
|
1713
|
+
emitReconcileStart(snapshot: FactsSnapshot<any>): void;
|
|
1714
|
+
emitReconcileEnd(result: ReconcileResult): void;
|
|
1715
|
+
emitConstraintEvaluate(id: string, active: boolean): void;
|
|
1716
|
+
emitConstraintError(id: string, error: unknown): void;
|
|
1717
|
+
emitRequirementCreated(req: RequirementWithId): void;
|
|
1718
|
+
emitRequirementMet(req: RequirementWithId, byResolver: string): void;
|
|
1719
|
+
emitRequirementCanceled(req: RequirementWithId): void;
|
|
1720
|
+
emitResolverStart(resolver: string, req: RequirementWithId): void;
|
|
1721
|
+
emitResolverComplete(resolver: string, req: RequirementWithId, duration: number): void;
|
|
1722
|
+
emitResolverError(resolver: string, req: RequirementWithId, error: unknown): void;
|
|
1723
|
+
emitResolverRetry(resolver: string, req: RequirementWithId, attempt: number): void;
|
|
1724
|
+
emitResolverCancel(resolver: string, req: RequirementWithId): void;
|
|
1725
|
+
emitEffectRun(id: string): void;
|
|
1726
|
+
emitEffectError(id: string, error: unknown): void;
|
|
1727
|
+
emitSnapshot(snapshot: Snapshot): void;
|
|
1728
|
+
emitTimeTravel(from: number, to: number): void;
|
|
1729
|
+
emitError(error: DirectiveError): void;
|
|
1730
|
+
emitErrorRecovery(error: DirectiveError, strategy: RecoveryStrategy): void;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Create a manager that broadcasts lifecycle events to registered plugins.
|
|
1734
|
+
*
|
|
1735
|
+
* Plugins are called in registration order. All hook invocations are
|
|
1736
|
+
* wrapped in try-catch so a misbehaving plugin never breaks the engine.
|
|
1737
|
+
* Duplicate plugin names are detected and the older registration is
|
|
1738
|
+
* replaced with a warning.
|
|
1739
|
+
*
|
|
1740
|
+
* @returns A `PluginManager` with register/unregister/getPlugins and emit* methods for every lifecycle event
|
|
1741
|
+
*/
|
|
1742
|
+
declare function createPluginManager<S extends Schema = any>(): PluginManager<S>;
|
|
1743
|
+
|
|
1744
|
+
/**
|
|
1745
|
+
* Error Boundaries - Configurable error handling and recovery
|
|
1746
|
+
*
|
|
1747
|
+
* Features:
|
|
1748
|
+
* - Catch errors in constraints/resolvers/effects/derivations
|
|
1749
|
+
* - Configurable recovery strategies (skip, retry, retry-later, disable, throw)
|
|
1750
|
+
* - Circuit breaker pattern for automatic failure protection
|
|
1751
|
+
* - Error reporting to plugins
|
|
1752
|
+
*/
|
|
1753
|
+
|
|
1754
|
+
/**
|
|
1755
|
+
* Pending retry entry.
|
|
1756
|
+
*/
|
|
1757
|
+
interface PendingRetry {
|
|
1758
|
+
source: ErrorSource;
|
|
1759
|
+
sourceId: string;
|
|
1760
|
+
context: unknown;
|
|
1761
|
+
attempt: number;
|
|
1762
|
+
nextRetryTime: number;
|
|
1763
|
+
callback?: () => void;
|
|
1764
|
+
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Create a manager for deferred retry scheduling with exponential backoff.
|
|
1767
|
+
*
|
|
1768
|
+
* Retries are stored in a Map keyed by source ID. Each retry tracks its
|
|
1769
|
+
* attempt number and next retry time. When `processDueRetries()` is called
|
|
1770
|
+
* (typically during reconciliation), entries whose time has elapsed are
|
|
1771
|
+
* returned and removed from the queue.
|
|
1772
|
+
*
|
|
1773
|
+
* @param config - Backoff configuration: `delayMs`, `maxRetries`, `backoffMultiplier`, `maxDelayMs`
|
|
1774
|
+
* @returns A manager with `scheduleRetry`, `getPendingRetries`, `processDueRetries`, `cancelRetry`, and `clearAll` methods
|
|
1775
|
+
*/
|
|
1776
|
+
declare function createRetryLaterManager(config?: RetryLaterConfig): {
|
|
1777
|
+
/** Schedule a retry */
|
|
1778
|
+
scheduleRetry: (source: ErrorSource, sourceId: string, context: unknown, attempt: number, callback?: () => void) => PendingRetry | null;
|
|
1779
|
+
/** Get pending retries */
|
|
1780
|
+
getPendingRetries: () => PendingRetry[];
|
|
1781
|
+
/** Process due retries */
|
|
1782
|
+
processDueRetries: () => PendingRetry[];
|
|
1783
|
+
/** Cancel a retry */
|
|
1784
|
+
cancelRetry: (sourceId: string) => void;
|
|
1785
|
+
/** Clear all pending retries */
|
|
1786
|
+
clearAll: () => void;
|
|
1787
|
+
};
|
|
1788
|
+
interface ErrorBoundaryManager {
|
|
1789
|
+
/** Handle an error from a specific source */
|
|
1790
|
+
handleError(source: ErrorSource, sourceId: string, error: unknown, context?: unknown): RecoveryStrategy;
|
|
1791
|
+
/** Get the last error */
|
|
1792
|
+
getLastError(): DirectiveError | null;
|
|
1793
|
+
/** Get all errors */
|
|
1794
|
+
getAllErrors(): DirectiveError[];
|
|
1795
|
+
/** Clear all errors */
|
|
1796
|
+
clearErrors(): void;
|
|
1797
|
+
/** Get retry-later manager */
|
|
1798
|
+
getRetryLaterManager(): ReturnType<typeof createRetryLaterManager>;
|
|
1799
|
+
/** Process due retries (call periodically or on reconcile) */
|
|
1800
|
+
processDueRetries(): PendingRetry[];
|
|
1801
|
+
/** Clear retry attempts for a source ID (call on success) */
|
|
1802
|
+
clearRetryAttempts(sourceId: string): void;
|
|
1803
|
+
}
|
|
1804
|
+
/** Options for creating an error boundary manager */
|
|
1805
|
+
interface CreateErrorBoundaryOptions {
|
|
1806
|
+
config?: ErrorBoundaryConfig;
|
|
1807
|
+
/** Callback when an error occurs */
|
|
1808
|
+
onError?: (error: DirectiveError) => void;
|
|
1809
|
+
/** Callback when recovery is attempted */
|
|
1810
|
+
onRecovery?: (error: DirectiveError, strategy: RecoveryStrategy) => void;
|
|
1811
|
+
}
|
|
1812
|
+
/**
|
|
1813
|
+
* Create a manager that handles errors from constraints, resolvers, effects,
|
|
1814
|
+
* and derivations with configurable per-source recovery strategies.
|
|
1815
|
+
*
|
|
1816
|
+
* Supported strategies: `"skip"` (ignore), `"retry"` (immediate),
|
|
1817
|
+
* `"retry-later"` (deferred with backoff), `"disable"` (turn off source),
|
|
1818
|
+
* and `"throw"` (re-throw). Recent errors are kept in a ring buffer
|
|
1819
|
+
* (last 100) for inspection. The retry-later strategy delegates to an
|
|
1820
|
+
* internal {@link createRetryLaterManager}.
|
|
1821
|
+
*
|
|
1822
|
+
* @param options - Error boundary configuration, plus `onError` and `onRecovery` callbacks for plugin integration
|
|
1823
|
+
* @returns An `ErrorBoundaryManager` with handleError/getLastError/getAllErrors/clearErrors/processDueRetries methods
|
|
1824
|
+
*
|
|
1825
|
+
* @example
|
|
1826
|
+
* ```ts
|
|
1827
|
+
* const boundary = createErrorBoundaryManager({
|
|
1828
|
+
* config: {
|
|
1829
|
+
* onResolverError: "retry-later",
|
|
1830
|
+
* onEffectError: "skip",
|
|
1831
|
+
* retryLater: { maxRetries: 5, delayMs: 500 },
|
|
1832
|
+
* },
|
|
1833
|
+
* onError: (err) => console.error(err.source, err.message),
|
|
1834
|
+
* });
|
|
1835
|
+
*
|
|
1836
|
+
* const strategy = boundary.handleError("resolver", "fetchUser", new Error("timeout"));
|
|
1837
|
+
* // strategy === "retry-later"
|
|
1838
|
+
* ```
|
|
1839
|
+
*/
|
|
1840
|
+
declare function createErrorBoundaryManager(options?: CreateErrorBoundaryOptions): ErrorBoundaryManager;
|
|
1841
|
+
|
|
1842
|
+
/**
|
|
1843
|
+
* Time-Travel Debugging - Snapshot-based state history
|
|
1844
|
+
*
|
|
1845
|
+
* Features:
|
|
1846
|
+
* - Ring buffer of state snapshots
|
|
1847
|
+
* - Go back/forward through history
|
|
1848
|
+
* - Replay from any snapshot
|
|
1849
|
+
* - Export/import state history
|
|
1850
|
+
*/
|
|
1851
|
+
|
|
1852
|
+
interface TimeTravelManager<_S extends Schema> extends TimeTravelAPI {
|
|
1853
|
+
/** Take a snapshot of current state */
|
|
1854
|
+
takeSnapshot(trigger: string): Snapshot;
|
|
1855
|
+
/** Restore facts from a snapshot */
|
|
1856
|
+
restore(snapshot: Snapshot): void;
|
|
1857
|
+
/** Check if time-travel is enabled */
|
|
1858
|
+
readonly isEnabled: boolean;
|
|
1859
|
+
/** True while restoring a snapshot (engine should skip reconciliation) */
|
|
1860
|
+
readonly isRestoring: boolean;
|
|
1861
|
+
/** Pause snapshot taking */
|
|
1862
|
+
pause(): void;
|
|
1863
|
+
/** Resume snapshot taking */
|
|
1864
|
+
resume(): void;
|
|
1865
|
+
}
|
|
1866
|
+
/** Options for creating a time-travel manager */
|
|
1867
|
+
interface CreateTimeTravelOptions<S extends Schema> {
|
|
1868
|
+
config: DebugConfig;
|
|
1869
|
+
facts: Facts<S>;
|
|
1870
|
+
store: FactsStore<S>;
|
|
1871
|
+
/** Callback when a snapshot is taken */
|
|
1872
|
+
onSnapshot?: (snapshot: Snapshot) => void;
|
|
1873
|
+
/** Callback when time-travel occurs */
|
|
1874
|
+
onTimeTravel?: (from: number, to: number) => void;
|
|
1875
|
+
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Create a snapshot-based time-travel debugger with a ring buffer of state
|
|
1878
|
+
* history.
|
|
1879
|
+
*
|
|
1880
|
+
* Snapshots are taken automatically after fact changes (during
|
|
1881
|
+
* reconciliation) and can be navigated with `goBack`/`goForward`/`goTo`.
|
|
1882
|
+
* Changesets group multiple snapshots into a single undo/redo unit.
|
|
1883
|
+
* The entire history can be exported to JSON and re-imported for
|
|
1884
|
+
* cross-session debugging.
|
|
1885
|
+
*
|
|
1886
|
+
* @param options - Debug config (maxSnapshots, timeTravel flag), facts proxy, store, and snapshot/time-travel callbacks
|
|
1887
|
+
* @returns A `TimeTravelManager` with takeSnapshot/restore/goBack/goForward/goTo/replay/export/import and changeset methods
|
|
1888
|
+
*/
|
|
1889
|
+
declare function createTimeTravelManager<S extends Schema>(options: CreateTimeTravelOptions<S>): TimeTravelManager<S>;
|
|
1890
|
+
/**
|
|
1891
|
+
* Create a no-op time-travel manager used when `debug.timeTravel` is
|
|
1892
|
+
* disabled. All methods are safe to call but perform no work.
|
|
1893
|
+
*
|
|
1894
|
+
* @returns A `TimeTravelManager` where every method is a no-op and `isEnabled` is `false`
|
|
1895
|
+
*/
|
|
1896
|
+
declare function createDisabledTimeTravel<S extends Schema>(): TimeTravelManager<S>;
|
|
1897
|
+
|
|
1898
|
+
/**
|
|
1899
|
+
* Engine - The core reconciliation loop
|
|
1900
|
+
*
|
|
1901
|
+
* The engine orchestrates:
|
|
1902
|
+
* 1. Fact changes trigger reconciliation
|
|
1903
|
+
* 2. Constraints produce requirements
|
|
1904
|
+
* 3. Resolvers fulfill requirements
|
|
1905
|
+
* 4. Effects run after stabilization
|
|
1906
|
+
* 5. Derivations are invalidated and recomputed
|
|
1907
|
+
*/
|
|
1908
|
+
|
|
1909
|
+
/**
|
|
1910
|
+
* Create the core Directive reconciliation engine that wires facts, derivations,
|
|
1911
|
+
* effects, constraints, resolvers, plugins, error boundaries, and time-travel
|
|
1912
|
+
* into a single reactive system.
|
|
1913
|
+
*
|
|
1914
|
+
* This is the internal factory used by `createSystem`. Most users should call
|
|
1915
|
+
* `createSystem` instead, which provides a friendlier API and handles module
|
|
1916
|
+
* composition.
|
|
1917
|
+
*
|
|
1918
|
+
* @param config - Full system configuration: modules, plugins, error boundary settings, and debug options
|
|
1919
|
+
* @returns A `System` instance with facts, derive, events, dispatch, subscribe, watch, settle, and lifecycle methods
|
|
1920
|
+
*
|
|
1921
|
+
* @example
|
|
1922
|
+
* ```ts
|
|
1923
|
+
* // Prefer createSystem for most use cases:
|
|
1924
|
+
* import { createSystem, createModule, t } from "@directive-run/core";
|
|
1925
|
+
*
|
|
1926
|
+
* const counter = createModule("counter", {
|
|
1927
|
+
* schema: { count: t.number() },
|
|
1928
|
+
* init: (facts) => { facts.count = 0; },
|
|
1929
|
+
* });
|
|
1930
|
+
*
|
|
1931
|
+
* const system = createSystem({ module: counter });
|
|
1932
|
+
* system.start();
|
|
1933
|
+
* system.facts.count = 42;
|
|
1934
|
+
* ```
|
|
1935
|
+
*/
|
|
1936
|
+
declare function createEngine<S extends Schema>(config: SystemConfig<any>): System<any>;
|
|
1937
|
+
|
|
1938
|
+
/**
|
|
1939
|
+
* Dependency tracking context for auto-tracking derivations
|
|
1940
|
+
*
|
|
1941
|
+
* Uses a stack-based approach to handle nested derivation computations.
|
|
1942
|
+
* When a derivation accesses a fact, the tracking context records it.
|
|
1943
|
+
*/
|
|
1944
|
+
|
|
1945
|
+
/**
|
|
1946
|
+
* Get the current tracking context.
|
|
1947
|
+
* Returns null context if no tracking is active.
|
|
1948
|
+
*/
|
|
1949
|
+
declare function getCurrentTracker(): TrackingContext;
|
|
1950
|
+
/**
|
|
1951
|
+
* Check if we're currently tracking dependencies.
|
|
1952
|
+
*/
|
|
1953
|
+
declare function isTracking(): boolean;
|
|
1954
|
+
/**
|
|
1955
|
+
* Run a function with dependency tracking.
|
|
1956
|
+
* Returns the computed value and the set of dependencies accessed.
|
|
1957
|
+
*/
|
|
1958
|
+
declare function withTracking<T>(fn: () => T): {
|
|
1959
|
+
value: T;
|
|
1960
|
+
deps: Set<string>;
|
|
1961
|
+
};
|
|
1962
|
+
/**
|
|
1963
|
+
* Run a function without tracking.
|
|
1964
|
+
* Useful for reading facts without creating dependencies.
|
|
1965
|
+
*/
|
|
1966
|
+
declare function withoutTracking<T>(fn: () => T): T;
|
|
1967
|
+
/**
|
|
1968
|
+
* Track a specific key in the current context.
|
|
1969
|
+
* No-op if not currently tracking.
|
|
1970
|
+
*/
|
|
1971
|
+
declare function trackAccess(key: string): void;
|
|
1972
|
+
|
|
1973
|
+
/**
|
|
1974
|
+
* @directive-run/core
|
|
1975
|
+
*
|
|
1976
|
+
* Constraint-driven runtime for TypeScript.
|
|
1977
|
+
*
|
|
1978
|
+
* Also available:
|
|
1979
|
+
* - `@directive-run/core/plugins` – Logging, devtools, persistence, observability, circuit breaker
|
|
1980
|
+
* - `@directive-run/core/testing` – Mock resolvers, fake timers, assertion helpers
|
|
1981
|
+
* - `@directive-run/core/migration` – Redux/Zustand/XState migration codemods
|
|
1982
|
+
* - `@directive-run/core/adapter-utils` – Shared framework adapter utilities
|
|
1983
|
+
* - `@directive-run/core/worker` – Web Worker support
|
|
1984
|
+
*
|
|
1985
|
+
* @packageDocumentation
|
|
1986
|
+
*/
|
|
1987
|
+
|
|
1988
|
+
/**
|
|
1989
|
+
* Backoff strategy constants for retry policies.
|
|
1990
|
+
* Use for autocomplete when configuring resolver retry policies.
|
|
1991
|
+
*
|
|
1992
|
+
* @example
|
|
1993
|
+
* ```ts
|
|
1994
|
+
* import { Backoff } from '@directive-run/core';
|
|
1995
|
+
*
|
|
1996
|
+
* const resolver = {
|
|
1997
|
+
* requirement: "FETCH_DATA",
|
|
1998
|
+
* retry: {
|
|
1999
|
+
* attempts: 3,
|
|
2000
|
+
* backoff: Backoff.Exponential, // Autocomplete-friendly!
|
|
2001
|
+
* initialDelay: 100,
|
|
2002
|
+
* },
|
|
2003
|
+
* resolve: async (req, ctx) => { ... },
|
|
2004
|
+
* };
|
|
2005
|
+
* ```
|
|
2006
|
+
*/
|
|
2007
|
+
declare const Backoff: {
|
|
2008
|
+
/** No delay between retries */
|
|
2009
|
+
readonly None: "none";
|
|
2010
|
+
/** Linear delay increase (initialDelay * attempt) */
|
|
2011
|
+
readonly Linear: "linear";
|
|
2012
|
+
/** Exponential delay increase (initialDelay * 2^attempt) */
|
|
2013
|
+
readonly Exponential: "exponential";
|
|
2014
|
+
};
|
|
2015
|
+
|
|
2016
|
+
export { Backoff, BatchConfig, type Branded, type ChainableSchemaType, type ConstraintBuilderComplete, type ConstraintBuilderStart, type ConstraintBuilderWithWhen, ConstraintState, ConstraintsDef, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleConstraintsDef, CrossModuleDeps, CrossModuleDerivationsDef, CrossModuleEffectsDef, DebugConfig, type DerivationState, type DerivationsDef, DerivationsSchema, type DerivedValues, DirectiveError, EffectsDef, ErrorBoundaryConfig, ErrorSource, type ExtendedSchemaType, FactChange, Facts, FactsSnapshot, FactsStore, InferFacts, InferRequirements, type InflightInfo, type ModuleBuilder, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, type NamespacedSystemBuilder, type PendingRetry, Plugin, ReconcileResult, RecoveryStrategy, Requirement, RequirementKeyFn, RequirementOutput$1 as RequirementOutput, RequirementSet, type RequirementTypeStatus, RequirementWithId, ResolverContext, ResolverStatus, ResolversDef, RetryLaterConfig, RetryPolicy, Schema, SchemaType, SingleModuleSystem, type SingleModuleSystemBuilder, Snapshot, System, type SystemBuilderStart, SystemConfig, TimeTravelAPI, type TypedConstraint, TypedConstraintDef, TypedConstraintsDef, TypedDerivationsDef, TypedEventsDef, type TypedResolver, TypedResolversDef, type WhenBuilder, type WhenConstraint, constraint, constraintFactory, createConstraintsManager, createDerivationsManager, createDisabledTimeTravel, createEffectsManager, createEngine, createErrorBoundaryManager, createFacts, createFactsProxy, createFactsStore, createModule, createModuleFactory, createPluginManager, createRequirementStatusPlugin, createResolversManager, createRetryLaterManager, createStatusHook, createSystem, createSystemWithStatus, createTimeTravelManager, forType, generateRequirementId, getCurrentTracker, isRequirementType, isTracking, module$1 as module, req, resolverFactory, system, t, trackAccess, typedConstraint, typedResolver, when, withTracking, withoutTracking };
|