@asaidimu/utils-artifacts 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -90,59 +90,6 @@ interface DataStore<T extends object> {
90
90
  state(): Readonly<StoreExecutionState<T>>;
91
91
  }
92
92
 
93
- /**
94
- * Represents all errors within the ArtifactContainer system, categorized
95
- * into "system" (internal structural), "external" (runtime failures),
96
- * or "cycle" (circular dependencies). This unified error class simplifies
97
- * error handling and provides clear semantics.
98
- */
99
- declare class ArtifactError extends Error {
100
- category: "system" | "external";
101
- constructor(message: string, category: "system" | "external", cause?: unknown);
102
- }
103
- /**
104
- * Error thrown when a circular dependency is detected during artifact resolution.
105
- * This indicates a structural problem in the artifact graph.
106
- */
107
- declare class CircularDependencyError extends ArtifactError {
108
- /**
109
- * Creates an instance of CircularDependencyError.
110
- * @param path The dependency path that caused the cycle.
111
- */
112
- constructor(path: string[]);
113
- }
114
- /**
115
- * Error thrown when an artifact requested for resolution is not found
116
- * within the current container or its parent hierarchy.
117
- */
118
- declare class ArtifactNotFoundError extends ArtifactError {
119
- /**
120
- * Creates an instance of ArtifactNotFoundError.
121
- * @param key The key of the artifact that was not found.
122
- */
123
- constructor(key: string);
124
- }
125
- /**
126
- * Error thrown when an operation is attempted that is not permitted
127
- * due to the artifact's scope or current state (e.g., calling `yield` on a Transient artifact).
128
- */
129
- declare class IllegalScopeError extends ArtifactError {
130
- /**
131
- * Creates an instance of IllegalScopeError.
132
- * @param message A descriptive message about the illegal operation.
133
- */
134
- constructor(message: string);
135
- }
136
- /**
137
- * Error returned when all a watched instance is disposed
138
- */
139
- declare class WatcherDisposedError extends ArtifactError {
140
- /**
141
- * Creates an instance of IllegalScopeError.
142
- * @param message A descriptive message about the illegal operation.
143
- */
144
- constructor(key: string);
145
- }
146
93
  /**
147
94
  * Defines the lifecycle and sharing strategy for an artifact.
148
95
  */
@@ -161,50 +108,6 @@ declare enum ArtifactScopes {
161
108
  Singleton = "singleton",
162
109
  Transient = "transient"
163
110
  }
164
- /**
165
- * Configuration options for defining an artifact. These options control
166
- * its lifecycle, instantiation, and error handling behavior.
167
- */
168
- interface ArtifactOptions {
169
- /**
170
- * The scope of the artifact, determining its lifecycle and sharing strategy.
171
- * Defaults to `ArtifactScopes.Singleton`.
172
- */
173
- scope?: ArtifactScope;
174
- /**
175
- * If `true` (default), the artifact's factory is executed only when the artifact
176
- * is first requested. If `false`, the artifact is built immediately upon registration
177
- * (only applies to Singleton scopes).
178
- */
179
- lazy?: boolean;
180
- /**
181
- * Maximum time in milliseconds allowed for the artifact's factory function
182
- * to complete execution. If exceeded, the factory will time out.
183
- */
184
- timeoutMs?: number;
185
- /**
186
- * Number of times to retry the artifact's factory on failure due to an
187
- * external (runtime) error. SystemErrors are not retried. Defaults to `0`.
188
- */
189
- retries?: number;
190
- /**
191
- * Base debounce time in milliseconds for invalidation events originating
192
- * from this artifact. This can be overridden by `UseOptions.debounce`.
193
- */
194
- debounce?: number;
195
- }
196
- /**
197
- * Options that can be applied to dependency resolutions within an artifact's factory,
198
- * allowing for fine-grained control over how dependencies affect the current artifact.
199
- */
200
- interface UseOptions {
201
- /**
202
- * Applies a specific debounce time in milliseconds to dependencies resolved
203
- * within the `use` block. If this value is higher than the artifact's
204
- * `baseDebounceMs` (or `activeDebounceMs`), it will be used for subsequent invalidations.
205
- */
206
- debounce?: number;
207
- }
208
111
  /**
209
112
  * Represents a snapshot of an artifact's state and dependencies for debugging purposes.
210
113
  * Provides insight into the artifact's current status and its position within the dependency graph.
@@ -259,6 +162,11 @@ interface UseDependencyContext<TRegistry extends Record<string, any>, TState ext
259
162
  */
260
163
  select<S>(selector: (state: TState) => S): S;
261
164
  }
165
+ type ArtifactStreamContext<TArtifact> = {
166
+ value: TArtifact | undefined;
167
+ signal: AbortSignal;
168
+ emit: (value: TArtifact) => Promise<void>;
169
+ };
262
170
  /**
263
171
  * The full context provided to an artifact's factory function.
264
172
  * This context allows the artifact to interact with the container,
@@ -289,7 +197,7 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
289
197
  * @param options Optional settings for this dependency block, like debounce.
290
198
  * @returns A Promise resolving to the result of the callback.
291
199
  */
292
- use<R>(callback: (ctx: UseDependencyContext<TRegistry, TState>) => R | Promise<R>, options?: UseOptions): Promise<R>;
200
+ use<R>(callback: (ctx: UseDependencyContext<TRegistry, TState>) => R | Promise<R>): Promise<R>;
293
201
  /**
294
202
  * Registers a cleanup function to be executed when the artifact is
295
203
  * invalidated and before its new instance is built. This is useful
@@ -313,7 +221,7 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
313
221
  * @throws {SystemError} if called on a Transient artifact, as Transient artifacts
314
222
  * do not maintain a persistent value.
315
223
  */
316
- yield(value: TArtifact): void;
224
+ stream(callback: (ctx: ArtifactStreamContext<TArtifact>) => void | Promise<void>): void;
317
225
  }
318
226
  /**
319
227
  * A function that performs cleanup logic for an artifact, potentially asynchronously.
@@ -363,7 +271,7 @@ type ArtifactFactory<TRegistry extends Record<string, any>, TState extends objec
363
271
  * Provides a way to get the current resolved artifact and subscribe to updates.
364
272
  * @template TArtifact The type of the artifact being watched.
365
273
  */
366
- interface ArtifactWatcher<TArtifact> {
274
+ interface ArtifactObserver<TArtifact> {
367
275
  /** The unique identifier (key) of the artifact being watched. */
368
276
  id: string;
369
277
  /**
@@ -382,7 +290,7 @@ interface ArtifactWatcher<TArtifact> {
382
290
  * @param callback The function to call on updates.
383
291
  * @returns A function to unsubscribe the callback.
384
292
  */
385
- subscribe(callback: () => void): () => void;
293
+ subscribe(callback: (artifact: ResolvedArtifact<TArtifact>) => void): () => void;
386
294
  /**
387
295
  * Disposes of this watcher reference, decrementing the reference count.
388
296
  * When the count reaches zero, cleans up all associated resources.
@@ -396,218 +304,155 @@ interface ArtifactWatcher<TArtifact> {
396
304
  * depends on another or is depended upon by another, potentially across
397
305
  * different `ArtifactContainer` instances (e.g., parent/child containers).
398
306
  */
399
- interface DependencyLink {
307
+ interface DependencyLink<T> {
400
308
  /** The key of the artifact involved in the dependency. */
401
309
  key: string;
402
310
  /** The `ArtifactContainer` instance that owns the linked artifact. */
403
- container: ArtifactContainer<any, any>;
311
+ container: T;
312
+ }
313
+
314
+ /**
315
+ * Configuration options for defining an artifact. These options control
316
+ * its lifecycle, instantiation, and error handling behavior.
317
+ */
318
+ interface ArtifactTemplate<TRegistry extends Record<string, any>, TState extends object, K extends keyof TRegistry> {
319
+ /** The unique key identifying this artifact. */
320
+ key: K;
321
+ /** The factory function responsible for creating the artifact's instance. */
322
+ factory: ArtifactFactory<TRegistry, TState, K>;
323
+ /**
324
+ * The scope of the artifact, determining its lifecycle and sharing strategy.
325
+ * Defaults to `ArtifactScopes.Singleton`.
326
+ */
327
+ scope?: ArtifactScope;
328
+ /**
329
+ * If `true` (default), the artifact's factory is executed only when the artifact
330
+ * is first requested. If `false`, the artifact is built immediately upon registration
331
+ * (only applies to Singleton scopes).
332
+ */
333
+ lazy?: boolean;
334
+ /**
335
+ * Maximum time in milliseconds allowed for the artifact's factory function
336
+ * to complete execution. If exceeded, the factory will time out.
337
+ */
338
+ timeout?: number;
339
+ /**
340
+ * Number of times to retry the artifact's factory on failure due to an
341
+ * external (runtime) error. SystemErrors are not retried. Defaults to `0`.
342
+ */
343
+ retries?: number;
344
+ /**
345
+ * Base debounce time in milliseconds for invalidation events originating
346
+ * from this artifact. This can be overridden by `UseOptions.debounce`.
347
+ */
348
+ debounce?: number;
404
349
  }
350
+
405
351
  /**
406
352
  * A dependency injection container for managing the lifecycle, dependencies,
407
353
  * and instances of "artifacts" (any JavaScript/TypeScript object or value).
408
- * It supports hierarchical containers, different scopes (singleton, transient),
409
- * dependency resolution, state-based invalidation, and debounced rebuilding.
410
354
  *
411
- * @template TRegistry A type that maps artifact keys (strings) to their
412
- * corresponding artifact types. This provides strong
413
- * typing for `resolve`, `register`, and other operations.
414
- * @template TState The type of the global state object that artifacts can depend on.
355
+ * Refactored to separate concerns:
356
+ * - ArtifactRegistry: Stores artifact templates (factories + options)
357
+ * - ArtifactCache: Stores resolved singleton instances
358
+ * - ArtifactDependencyGraph: Tracks artifact dependencies using DependencyGraph
359
+ * - ArtifactManager: Handles lifecycle (build, invalidate, dispose)
360
+ * - ArtifactObserver: Manages watchers and subscriptions
361
+ *
362
+ * @template TRegistry A type that maps artifact keys to their types
363
+ * @template TState The type of the global state object
415
364
  */
416
365
  declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<string, any>, TState extends object = any> {
417
- private readonly artifacts;
418
- private readonly resolvingStack;
419
- private readonly listeners;
420
- private readonly watcherCache;
421
- private readonly props;
422
- private readonly parent?;
423
- private isDisposed;
424
- private resolvedArtifacts;
366
+ private readonly registry;
367
+ private readonly cache;
368
+ private readonly graph;
369
+ private readonly manager;
370
+ private readonly observer;
371
+ private readonly store;
425
372
  /**
426
373
  * Creates a new ArtifactContainer instance.
427
- * @param props An object providing functions to interact with a global data store,
428
- * specifically `watch` for state changes and `get` for current state.
429
- * @param parent An optional parent `ArtifactContainer`. If provided, this container
430
- * can resolve artifacts registered in its parent.
431
- */
432
- constructor(store: Pick<DataStore<TState>, "watch" | "get">, parent?: ArtifactContainer<TRegistry, TState>);
433
- /**
434
- * Creates a new child `ArtifactContainer` that inherits from the current container.
435
- * Child containers can resolve artifacts registered in their parent, but
436
- * artifacts registered in the child are local to that child.
437
- * @returns A new `ArtifactContainer` instance.
374
+ *
375
+ * @param store An object providing functions to interact with a global data store
438
376
  */
439
- createChild(): ArtifactContainer<TRegistry, TState>;
377
+ constructor(store: Pick<DataStore<TState>, "watch" | "get">);
440
378
  /**
441
379
  * Provides debug information about all artifacts currently registered in this container.
442
- * This is useful for inspecting the state, scope, dependencies, and activity of artifacts.
443
- * @returns An array of `ArtifactDebugNode` objects, each representing a registered artifact.
380
+ *
381
+ * @returns An array of ArtifactDebugNode objects
444
382
  */
445
- getDebugInfo(): ArtifactDebugNode[];
383
+ debugInfo(): ArtifactDebugNode[];
446
384
  /**
447
385
  * Registers a new artifact with the container.
448
386
  * If an artifact with the same key already exists, it will be overwritten and disposed.
449
387
  * For Singleton, non-lazy artifacts, the factory will be immediately invoked.
450
- * @template K The key of the artifact to register.
451
- * @param {object} params The registration parameters.
452
- * @param {K} params.key The unique identifier for the artifact.
453
- * @param {ArtifactFactory<TRegistry, TState, K>} params.factory The function that creates the artifact instance.
454
- * @param {ArtifactOptions} params.options Optional configuration for the artifact's lifecycle.
455
- * @returns A cleanup function that, when called, unregisters the artifact.
456
- */
457
- register<K extends keyof TRegistry>({ key, factory, ...options }: {
458
- key: K;
459
- factory: ArtifactFactory<TRegistry, TState, K>;
460
- } & ArtifactOptions): () => void;
388
+ *
389
+ * @param params The registration parameters
390
+ * @returns A cleanup function that unregisters the artifact
391
+ */
392
+ register<K extends keyof TRegistry>(params: ArtifactTemplate<TRegistry, TState, K>): () => void;
461
393
  /**
462
394
  * Unregisters an artifact from the container, disposing of its current instance
463
395
  * and removing all associated resources and dependency links.
464
- * @template K The key of the artifact to unregister.
465
- * @param key The unique identifier of the artifact.
466
- * @returns A Promise that resolves when the artifact has been fully unregistered and disposed.
396
+ *
397
+ * @param key The unique identifier of the artifact
467
398
  */
468
399
  unregister<K extends keyof TRegistry>(key: K): Promise<void>;
469
400
  /**
470
401
  * Resolves an artifact by its key, returning its instance or an error.
471
- * This method handles dependency resolution, cycle detection, caching,
472
- * and retry logic. It traverses the container hierarchy if the artifact
402
+ * This method handles dependency resolution, cycle detection (via graph),
403
+ * caching, and retry logic. Traverses the container hierarchy if the artifact
473
404
  * is not found locally.
474
- * @template K The key of the artifact to resolve.
475
- * @param key The unique identifier for the artifact.
476
- * @returns A Promise that resolves to a `ResolvedArtifact`. This object
477
- * will contain either the `instance` (if successful) or an `error`
478
- * (if an external error occurred during factory execution).
479
- * @throws {CircularDependencyError} if a circular dependency is detected during resolution.
480
- * @throws {ArtifactNotFoundError} if the artifact with the given key is not found
481
- * in the current container or any parent containers.
482
- * @throws {SystemError} for any other critical structural or configuration issues.
405
+ *
406
+ * @param key The unique identifier for the artifact
407
+ * @returns A Promise that resolves to a ResolvedArtifact
408
+ * @throws {ArtifactNotFoundError} if the artifact is not found
409
+ * @throws {ArtifactError} if a cycle is detected or other system errors occur
483
410
  */
484
411
  resolve<K extends keyof TRegistry>(key: K): Promise<ResolvedArtifact<TRegistry[K]>>;
485
412
  /**
486
- * Returns an `ArtifactWatcher` for a given artifact key.
487
- * The watcher allows subscribing to changes in the artifact's resolved value
488
- * @template K The key of the artifact to watch.
489
- * @param key The unique identifier for the artifact.
490
- * @returns An `ArtifactWatcher` instance.
413
+ * Returns an ArtifactWatcher for a given artifact key.
414
+ * The watcher allows subscribing to changes in the artifact's resolved value.
415
+ *
416
+ * @param key The unique identifier for the artifact
417
+ * @returns An ArtifactWatcher instance
491
418
  */
492
- watch<K extends keyof TRegistry>(key: K): ArtifactWatcher<TRegistry[K]>;
419
+ watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry[K]>;
493
420
  /**
494
421
  * Peeks at the resolved instance of an artifact without triggering its resolution
495
- * if it's lazy, or registering a dependency. It simply returns the currently
496
- * available instance (if any).
497
- * @template K The key of the artifact to peek at.
498
- * @param key The unique identifier for the artifact.
499
- * @returns The artifact instance if it's already built, otherwise `undefined`.
422
+ * if it's lazy, or registering a dependency.
423
+ *
424
+ * @param key The unique identifier for the artifact
425
+ * @returns The artifact instance if it's already built, otherwise undefined
500
426
  */
501
427
  peek<K extends keyof TRegistry>(key: K): TRegistry[K] | undefined;
502
- private findDefinition;
503
- /**
504
- * Packages an `ArtifactDefinition` into a `ResolvedArtifact` for public consumption.
505
- * This abstracts away internal details and provides the external API for interacting
506
- * with a resolved artifact (e.g., `invalidate`).
507
- * @template T The expected type of the artifact instance.
508
- * @param def The internal `ArtifactDefinition`.
509
- * @returns A `ResolvedArtifact` object.
510
- */
511
- private packageArtifact;
512
- /**
513
- * Core logic for executing an artifact's factory and capturing its dependencies.
514
- * This method is responsible for setting up the factory context, running the
515
- * factory (with retries and timeouts), and collecting all declared dependencies
516
- * (both artifact and state).
517
- * @template K The key of the artifact being created.
518
- * @param def The `ArtifactDefinition` for the artifact.
519
- * @param outArtifactDeps A Set to capture discovered artifact dependencies.
520
- * @param outStateDeps A Set to capture discovered state dependencies.
521
- * @returns A Promise resolving to an object containing the instance, cleanup function, and any external error.
522
- * @throws {SystemError} if a critical internal error occurs (e.g., circular dependency detected).
523
- */
524
- private createArtifactInstance;
525
- /**
526
- * Handles the propagation of a `yield` event from a Singleton artifact.
527
- * This involves invalidating all direct dependents and notifying any listeners.
528
- * @param key The key of the artifact that yielded a new value.
529
- */
530
- private processYieldPropagation;
531
- /**
532
- * Registers a dependency from a `dependent` artifact on a `target` artifact.
533
- * This builds the inverse dependency graph, allowing for efficient cascade invalidations.
534
- * This method is public so that child containers can register dependents on artifacts
535
- * owned by a parent container.
536
- * @param targetKey The key of the artifact being depended upon.
537
- * @param dependentKey The key of the artifact that depends on the target.
538
- * @param dependentContainer The container instance where the dependent artifact is registered.
539
- */
540
- registerDependent(targetKey: string, dependentKey: string, dependentContainer: ArtifactContainer<any, any>): void;
541
- /**
542
- * Removes a previously registered dependency link.
543
- * This method is public so that child containers can remove dependents on artifacts
544
- * owned by a parent container when their artifacts are disposed.
545
- * @param targetKey The key of the artifact that was depended upon.
546
- * @param dependentKey The key of the artifact that previously depended on the target.
547
- * @param dependentContainer The container instance where the dependent artifact was registered.
548
- */
549
- removeDependent(targetKey: string, dependentKey: string, dependentContainer: ArtifactContainer<any, any>): void;
550
- /**
551
- * Initiates the invalidation process for an artifact, potentially debouncing the rebuild.
552
- * Invalidation marks an artifact as needing to be rebuilt on its next resolution.
553
- * @template K The key of the artifact to invalidate.
554
- * @param key The unique identifier for the artifact.
555
- * @param replace If `true`, bypasses debouncing and forces an immediate execution of `executeInvalidation`.
556
- * @returns A Promise that resolves when the invalidation (and potential debounced rebuild) is complete.
557
- */
558
- private invalidate;
559
- /**
560
- * Executes the actual invalidation and rebuild logic for an artifact.
561
- * This includes disposing the old instance, invalidating dependents, and (optionally) resolving a new instance.
562
- * @template K The key of the artifact to invalidate.
563
- * @param key The unique identifier for the artifact.
564
- * @param replace If `true`, forces immediate disposal and rebuild without waiting for existing rebuild promises.
565
- * @returns A Promise that resolves when the invalidation and rebuild process is complete.
566
- */
567
- private executeInvalidation;
568
- /**
569
- * Disposes of an artifact's instance by running its cleanup and dispose functions,
570
- * unsubscribing from state changes, and clearing its cached instance and error.
571
- * This prepares the artifact for a rebuild or removal.
572
- * @param def The `ArtifactDefinition` of the instance to dispose.
573
- */
574
- private disposeInstance;
575
- /**
576
- * Fully disposes of an artifact, including its instance and all its associated
577
- * dependency graph links and resources. This is typically called when an artifact
578
- * is unregistered or the container itself is disposed.
579
- * @param key The unique identifier of the artifact to dispose.
580
- */
581
- private disposeArtifact;
582
- /**
583
- * Updates the dependency graph for an artifact based on newly discovered dependencies
584
- * during its factory execution. This involves adding and removing dependent links,
585
- * and setting up or tearing down state subscriptions.
586
- * @param def The `ArtifactDefinition` whose graph is being updated.
587
- * @param newArtifactDeps The set of artifact dependencies discovered during the latest build.
588
- * @param newStateDeps The set of state path dependencies discovered during the latest build.
589
- */
590
- private updateGraph;
591
- /**
592
- * Creates a single composite cleanup function from an array of individual cleanup functions.
593
- * The composite function executes all provided cleanups in reverse order of registration,
594
- * ensuring proper resource release, and handles potential asynchronous cleanups.
595
- * @param fns An array of `ArtifactCleanup` functions.
596
- * @returns A composite `ArtifactCleanup` function, or `undefined` if the array is empty.
597
- */
598
- private createCompositeCleanup;
599
- /**
600
- * Notifies all registered listeners (watchers) for a specific artifact that
601
- * its state (instance or error) has potentially changed.
602
- * @param key The key of the artifact whose listeners should be notified.
603
- */
604
- private notifyListeners;
605
- /**
606
- * Disposes of the entire `ArtifactContainer` and all artifacts registered within it.
428
+ /**
429
+ * Invalidates an artifact, triggering rebuild and cascade to dependents.
430
+ *
431
+ * @param key The artifact key to invalidate
432
+ * @param replace If true, forces immediate rebuild bypassing debounce
433
+ */
434
+ invalidate<K extends keyof TRegistry>(key: K, replace?: boolean): Promise<void>;
435
+ /**
436
+ * Notifies observers that an artifact has changed.
437
+ * Called by ArtifactManager during stream propagation.
438
+ *
439
+ * @param key The artifact key
440
+ */
441
+ notifyObservers(key: string): void;
442
+ /**
443
+ * Checks if an artifact has active watchers.
444
+ * Called by ArtifactManager to determine if lazy artifacts should rebuild.
445
+ *
446
+ * @param key The artifact key
447
+ * @returns True if the artifact has active watchers
448
+ */
449
+ hasWatchers(key: string): boolean;
450
+ /**
451
+ * Disposes of the entire ArtifactContainer and all artifacts registered within it.
607
452
  * This releases all resources, stops all watchers, and clears all internal state.
608
453
  * After disposal, the container should no longer be used.
609
454
  */
610
455
  dispose(): void;
611
456
  }
612
457
 
613
- export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, ArtifactError, type ArtifactFactory, type ArtifactFactoryContext, ArtifactNotFoundError, type ArtifactOptions, type ArtifactScope, ArtifactScopes, type ArtifactWatcher, CircularDependencyError, type DependencyLink, IllegalScopeError, type ResolvedArtifact, type UseDependencyContext, type UseOptions, WatcherDisposedError };
458
+ export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactObserver, type ArtifactScope, ArtifactScopes, type ArtifactStreamContext, type DependencyLink, type ResolvedArtifact, type UseDependencyContext };