@asaidimu/utils-artifacts 3.1.2 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.mts +156 -94
- package/index.d.ts +156 -94
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +1 -1
package/index.d.mts
CHANGED
|
@@ -91,22 +91,30 @@ interface DataStore<T extends object> {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Defines the lifecycle and sharing strategy for an artifact.
|
|
94
|
+
* Defines the lifecycle and sharing strategy for an artifact within the container.
|
|
95
95
|
*/
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Defines the lifecycle and sharing strategy for an artifact.
|
|
99
|
+
*/
|
|
97
100
|
type ArtifactScope =
|
|
98
101
|
/**
|
|
99
|
-
* A single instance of the artifact is created and shared across all resolutions
|
|
100
|
-
* within the container. It is created once and reused.
|
|
102
|
+
* **Singleton:** A single instance of the artifact is created and shared across all resolutions
|
|
103
|
+
* within the container. It is created once (often lazily) and reused until invalidated.
|
|
101
104
|
*/
|
|
102
105
|
"singleton"
|
|
103
106
|
/**
|
|
104
|
-
* A new instance of the artifact is created every time it is resolved.
|
|
105
|
-
* Transient artifacts do not participate in caching or shared state.
|
|
107
|
+
* **Transient:** A new instance of the artifact is created every time it is resolved.
|
|
108
|
+
* Transient artifacts do not participate in caching or shared state management.
|
|
106
109
|
*/
|
|
107
110
|
| "transient";
|
|
111
|
+
/**
|
|
112
|
+
* Enumeration of standard artifact scopes for strongly typed configuration.
|
|
113
|
+
*/
|
|
108
114
|
declare enum ArtifactScopes {
|
|
115
|
+
/** A single instance is shared globally. */
|
|
109
116
|
Singleton = "singleton",
|
|
117
|
+
/** A new instance is created on every resolution. */
|
|
110
118
|
Transient = "transient"
|
|
111
119
|
}
|
|
112
120
|
/**
|
|
@@ -120,19 +128,20 @@ interface ArtifactDebugNode {
|
|
|
120
128
|
scope: ArtifactScope;
|
|
121
129
|
/**
|
|
122
130
|
* The current status of the artifact, indicating its lifecycle phase.
|
|
123
|
-
* - 'active'
|
|
124
|
-
* - 'error'
|
|
125
|
-
* - 'idle'
|
|
126
|
-
* - 'building'
|
|
127
|
-
* - '
|
|
128
|
-
*/
|
|
129
|
-
status: "active" | "error" | "idle" | "
|
|
131
|
+
* - `'active'`: The artifact is successfully built and its instance is available.
|
|
132
|
+
* - `'error'`: The artifact failed to build due to an external (runtime) error.
|
|
133
|
+
* - `'idle'`: The artifact has not yet been built (for lazy singletons) or has been disposed.
|
|
134
|
+
* - `'building'`: The artifact's factory is currently executing.
|
|
135
|
+
* - `'pending'`: The artifact is waiting to be built, often after an invalidation and before any debounce.
|
|
136
|
+
*/
|
|
137
|
+
status: "active" | "error" | "idle" | "building" | "pending" | "debouncing";
|
|
138
|
+
/** A list of artifact keys that this artifact directly depends on. */
|
|
130
139
|
dependencies: string[];
|
|
131
|
-
/** A list of artifact keys that directly depend on this artifact. */
|
|
140
|
+
/** A list of artifact keys that directly depend on this artifact (its consumers). */
|
|
132
141
|
dependents: string[];
|
|
133
142
|
/** A list of state paths (selectors) that this artifact depends on. */
|
|
134
143
|
stateDependencies: string[];
|
|
135
|
-
/** The number of times this artifact's factory has been successfully executed. */
|
|
144
|
+
/** The number of times this artifact's factory has been successfully executed/rebuilt. */
|
|
136
145
|
renderCount: number;
|
|
137
146
|
}
|
|
138
147
|
/**
|
|
@@ -143,54 +152,62 @@ interface ArtifactDebugNode {
|
|
|
143
152
|
*/
|
|
144
153
|
interface UseDependencyContext<TRegistry extends Record<string, any>, TState extends object> {
|
|
145
154
|
/**
|
|
146
|
-
* Resolves another artifact from the container.
|
|
147
|
-
*
|
|
148
|
-
* changes, this artifact will be invalidated and rebuilt.
|
|
155
|
+
* Resolves another artifact from the container and registers a dependency on it.
|
|
156
|
+
* If the dependency changes, the current artifact will be invalidated and rebuilt.
|
|
149
157
|
* @template K The key of the artifact to resolve.
|
|
150
158
|
* @param key The key of the artifact to resolve.
|
|
151
159
|
* @returns A Promise that resolves to a `ResolvedArtifact` containing the instance
|
|
152
|
-
*
|
|
160
|
+
* or an external error.
|
|
153
161
|
* @throws {SystemError} if the key is missing or if resolving creates a circular dependency.
|
|
154
162
|
*/
|
|
155
163
|
resolve<K extends keyof TRegistry>(key: K): Promise<ResolvedArtifact<TRegistry[K]>>;
|
|
156
164
|
/**
|
|
157
|
-
* Selects a slice of the global state.
|
|
158
|
-
*
|
|
159
|
-
*
|
|
165
|
+
* Selects a slice of the global state and registers a dependency on it.
|
|
166
|
+
* If the selected state slice changes (based on a deep comparison), the current
|
|
167
|
+
* artifact will be invalidated and rebuilt.
|
|
160
168
|
* @template S The type of the selected state slice.
|
|
161
|
-
* @param selector A function that takes the full state and returns a slice.
|
|
169
|
+
* @param selector A function that takes the full state and returns a slice of state.
|
|
162
170
|
* @returns The selected slice of state.
|
|
163
171
|
*/
|
|
164
172
|
select<S>(selector: (state: TState) => S): S;
|
|
165
173
|
}
|
|
166
174
|
/**
|
|
167
|
-
* Context object provided to an artifact stream producer function.
|
|
168
|
-
* It contains methods and properties necessary for managing the stream
|
|
169
|
-
*
|
|
175
|
+
* Context object provided to an artifact stream producer function (`ctx.stream` callback).
|
|
176
|
+
* It contains methods and properties necessary for managing the stream and communicating
|
|
177
|
+
* new artifact values to the container and its consumers.
|
|
170
178
|
*
|
|
179
|
+
* @template TState The type of the global state.
|
|
171
180
|
* @template TArtifact The type of the artifact being streamed.
|
|
172
181
|
*/
|
|
173
182
|
type ArtifactStreamContext<TState, TArtifact> = {
|
|
174
183
|
/**
|
|
175
184
|
* The current value of the artifact. This is `undefined` before the first value is emitted.
|
|
176
185
|
* Useful for diffing or migrating state during an update.
|
|
186
|
+
* @returns The current artifact value or `undefined`.
|
|
177
187
|
*/
|
|
178
188
|
value: () => TArtifact | undefined;
|
|
179
189
|
/**
|
|
180
190
|
* An AbortSignal that indicates if the stream has been cancelled or aborted
|
|
181
|
-
* from the consumer side.
|
|
182
|
-
* processing when it is set.
|
|
191
|
+
* from the consumer side (e.g., due to container disposal or artifact invalidation).
|
|
192
|
+
* Producers should check this signal and stop processing when it is set to prevent leaks.
|
|
183
193
|
*/
|
|
184
194
|
signal: AbortSignal;
|
|
185
195
|
/**
|
|
186
|
-
* A function to asynchronously emit a new value of the artifact to the
|
|
187
|
-
* Calling this function updates the
|
|
188
|
-
*
|
|
196
|
+
* A function to asynchronously emit a new value of the artifact to the container.
|
|
197
|
+
* Calling this function updates the artifact's resolved value, triggers invalidation
|
|
198
|
+
* for its dependents, and updates the `value()` property for subsequent emissions.
|
|
189
199
|
*
|
|
190
200
|
* @param value The new artifact value to emit.
|
|
191
|
-
* @returns A Promise that resolves when the value has been sent.
|
|
201
|
+
* @returns A Promise that resolves when the value has been sent and dependents have been notified.
|
|
192
202
|
*/
|
|
193
203
|
emit: (value: TArtifact) => Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* Dispatches a state update to the global store, analogous to a standard `setState`.
|
|
206
|
+
* **Note:** This does not automatically register a dependency for the current artifact.
|
|
207
|
+
* @param update A `StateUpdater` function or a partial state object.
|
|
208
|
+
* @param options Optional settings for the update, including `force` and `actionId`.
|
|
209
|
+
* @returns A Promise that resolves when the state update is complete.
|
|
210
|
+
*/
|
|
194
211
|
set(update: StateUpdater<TState>, options?: {
|
|
195
212
|
force?: boolean;
|
|
196
213
|
actionId?: string;
|
|
@@ -208,13 +225,14 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
|
|
|
208
225
|
/**
|
|
209
226
|
* Returns the current global state object. This is a non-reactive read;
|
|
210
227
|
* changes to the state will not automatically invalidate the artifact
|
|
211
|
-
* unless explicitly selected via `ctx.
|
|
228
|
+
* unless explicitly selected via `ctx.use` and `ctx.select`.
|
|
212
229
|
* @returns The current global state.
|
|
213
230
|
*/
|
|
214
231
|
state(): TState;
|
|
215
232
|
/**
|
|
216
|
-
* The previous instance of the artifact if it's a Singleton and is being rebuilt
|
|
217
|
-
*
|
|
233
|
+
* The previous instance of the artifact if it's a Singleton and is being rebuilt
|
|
234
|
+
* after an invalidation. This is `undefined` on the initial build.
|
|
235
|
+
* Useful for diffing, migrating state, or reusing resources during an update.
|
|
218
236
|
*/
|
|
219
237
|
previous?: TArtifact;
|
|
220
238
|
/**
|
|
@@ -223,81 +241,123 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
|
|
|
223
241
|
* dependencies for the current artifact.
|
|
224
242
|
* @template R The return type of the callback.
|
|
225
243
|
* @param callback The function to execute to resolve dependencies.
|
|
226
|
-
* @param options Optional settings for this dependency block, like debounce.
|
|
227
244
|
* @returns A Promise resolving to the result of the callback.
|
|
228
245
|
*/
|
|
229
246
|
use<R>(callback: (ctx: UseDependencyContext<TRegistry, TState>) => R | Promise<R>): Promise<R>;
|
|
230
247
|
/**
|
|
231
|
-
* Registers a cleanup function to be executed when the
|
|
232
|
-
* invalidated and before its new instance is built. This is useful
|
|
233
|
-
* for releasing resources specific to the *previous* instance.
|
|
248
|
+
* Registers a cleanup function to be executed when the **current instance** of the
|
|
249
|
+
* artifact is invalidated and before its new instance is built. This is useful
|
|
250
|
+
* for releasing resources (e.g., event listeners) specific to the *previous* instance.
|
|
234
251
|
* @param cleanup The cleanup function.
|
|
235
252
|
*/
|
|
236
253
|
onCleanup(cleanup: ArtifactCleanup): void;
|
|
237
254
|
/**
|
|
238
255
|
* Registers a dispose function to be executed when the artifact is
|
|
239
256
|
* permanently removed from the container or the container itself is disposed.
|
|
240
|
-
* This is for final resource release.
|
|
257
|
+
* This is for final, permanent resource release.
|
|
241
258
|
* @param callback The dispose function.
|
|
242
259
|
*/
|
|
243
260
|
onDispose(callback: ArtifactCleanup): void;
|
|
244
261
|
/**
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
* for
|
|
248
|
-
*
|
|
249
|
-
* @param value The new value for the artifact.
|
|
262
|
+
* Starts a stream process for a Singleton artifact, allowing it to emit
|
|
263
|
+
* multiple values over time. The callback receives an `ArtifactStreamContext`
|
|
264
|
+
* for emitting values and managing the stream lifecycle.
|
|
265
|
+
* @param callback The function that implements the streaming logic.
|
|
250
266
|
* @throws {SystemError} if called on a Transient artifact, as Transient artifacts
|
|
251
|
-
*
|
|
267
|
+
* do not maintain a persistent value.
|
|
252
268
|
*/
|
|
253
269
|
stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => void | Promise<void>): void;
|
|
254
270
|
}
|
|
255
271
|
/**
|
|
256
|
-
* A function that performs cleanup logic for an artifact, potentially asynchronously.
|
|
272
|
+
* A function that performs cleanup or disposal logic for an artifact, potentially asynchronously.
|
|
257
273
|
* Used for `onCleanup` and `onDispose` callbacks.
|
|
258
274
|
*/
|
|
259
275
|
type ArtifactCleanup = () => void | Promise<void>;
|
|
260
276
|
/**
|
|
261
|
-
*
|
|
262
|
-
* cleanup functionality, and details about any external errors.
|
|
277
|
+
* Common properties shared across all possible states of a resolved artifact.
|
|
263
278
|
* @template TArtifact The type of the resolved artifact instance.
|
|
264
279
|
*/
|
|
265
|
-
interface
|
|
266
|
-
/** The successfully resolved instance of the artifact, if no error occurred. */
|
|
267
|
-
instance?: TArtifact;
|
|
280
|
+
interface ResolvedArtifactBase {
|
|
268
281
|
/**
|
|
269
282
|
* A function to manually trigger cleanup associated with this specific
|
|
270
|
-
* resolved instance. This is typically only relevant for Transient artifacts
|
|
283
|
+
* resolved instance. This is typically only relevant for Transient artifacts
|
|
284
|
+
* where the consumer is responsible for cleanup.
|
|
271
285
|
*/
|
|
272
286
|
cleanup?: ArtifactCleanup;
|
|
273
|
-
/**
|
|
274
|
-
* Any runtime or external error that occurred during the artifact's factory
|
|
275
|
-
* execution (e.g., fetch failed, timeout). SystemErrors are explicitly
|
|
276
|
-
* thrown and will not appear here.
|
|
277
|
-
*/
|
|
278
|
-
error?: any;
|
|
279
|
-
ready: boolean;
|
|
280
287
|
/**
|
|
281
288
|
* Manually invalidates this artifact, triggering its rebuild and
|
|
282
289
|
* cascading invalidations to its dependents.
|
|
283
|
-
* @param replace If `true`, forces immediate rebuild without debounce.
|
|
290
|
+
* @param replace If `true`, forces immediate rebuild without debounce delay.
|
|
291
|
+
* @param fatal If `true`, the artifact will not be rebuilt until next resolve
|
|
292
|
+
* regardless of the lazy option during registration.
|
|
293
|
+
*/
|
|
294
|
+
invalidate(replace?: boolean, fatal?: boolean): Promise<void>;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* State of an artifact that is successfully built and ready for use.
|
|
298
|
+
* The instance is guaranteed to be present.
|
|
299
|
+
* @template TArtifact The type of the resolved artifact instance.
|
|
300
|
+
*/
|
|
301
|
+
interface ReadyArtifact<TArtifact> extends ResolvedArtifactBase {
|
|
302
|
+
/** The successfully resolved instance of the artifact. */
|
|
303
|
+
instance: TArtifact;
|
|
304
|
+
/** Indicates that the artifact is ready and has an instance. Always true. */
|
|
305
|
+
ready: true;
|
|
306
|
+
/** Must be undefined in a ready state. */
|
|
307
|
+
error?: undefined;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* State of an artifact that failed to build due to an external error.
|
|
311
|
+
* The instance is guaranteed to be absent.
|
|
312
|
+
*/
|
|
313
|
+
interface ErrorArtifact extends ResolvedArtifactBase {
|
|
314
|
+
/** The instance is absent when an error occurs. Always undefined. */
|
|
315
|
+
instance?: undefined;
|
|
316
|
+
/** Indicates that the artifact failed to build. Always false. */
|
|
317
|
+
ready: false;
|
|
318
|
+
/**
|
|
319
|
+
* Any runtime or external error that occurred during the artifact's factory
|
|
320
|
+
* execution (e.g., network fetch failed).
|
|
284
321
|
*/
|
|
285
|
-
|
|
322
|
+
error: any;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* State of an artifact that is pending, idle, or currently building.
|
|
326
|
+
* Both instance and error are absent.
|
|
327
|
+
*/
|
|
328
|
+
interface PendingArtifact extends ResolvedArtifactBase {
|
|
329
|
+
/** The instance is absent while pending or idle. Always undefined. */
|
|
330
|
+
instance?: undefined;
|
|
331
|
+
/** Indicates that the artifact is not yet ready. Always false. */
|
|
332
|
+
ready: false;
|
|
333
|
+
/** Must be undefined in a pending state. */
|
|
334
|
+
error?: undefined;
|
|
286
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* The result of an artifact resolution. This is a union type representing
|
|
338
|
+
* the artifact in one of three possible states: Ready, Error, or Pending/Idle.
|
|
339
|
+
*
|
|
340
|
+
* This structure allows consuming code to narrow the type based on the
|
|
341
|
+
* boolean flag `ready` or the presence of the `error` property.
|
|
342
|
+
*
|
|
343
|
+
* @template TArtifact The type of the resolved artifact instance.
|
|
344
|
+
*/
|
|
345
|
+
type ResolvedArtifact<TArtifact> = ReadyArtifact<TArtifact> | ErrorArtifact | PendingArtifact;
|
|
287
346
|
/**
|
|
288
347
|
* The factory function responsible for creating an artifact's instance.
|
|
289
348
|
* It receives an `ArtifactFactoryContext` to interact with the container
|
|
290
349
|
* and declare dependencies.
|
|
291
350
|
* @template TRegistry The type mapping artifact keys to their artifact types.
|
|
292
351
|
* @template TState The type of the global state managed by the DataStore.
|
|
293
|
-
* @template
|
|
352
|
+
* @template TArtifact The type of the artifact this factory produces.
|
|
294
353
|
* @param context The context for creating the artifact.
|
|
295
354
|
* @returns The artifact instance or a Promise resolving to it.
|
|
296
355
|
*/
|
|
297
356
|
type ArtifactFactory<TRegistry extends Record<string, any>, TState extends object, TArtifact> = (context: ArtifactFactoryContext<TRegistry, TState, TArtifact>) => TArtifact | Promise<TArtifact>;
|
|
298
357
|
type ArtifactInstance<R> = R extends PromiseLike<infer T> ? T : R;
|
|
299
358
|
/**
|
|
300
|
-
* An interface for observing changes to an artifact without direct resolution
|
|
359
|
+
* An interface for observing changes to an artifact without direct resolution,
|
|
360
|
+
* typically used for UI binding or monitoring.
|
|
301
361
|
* Provides a way to get the current resolved artifact and subscribe to updates.
|
|
302
362
|
* @template TArtifact The type of the artifact being watched.
|
|
303
363
|
*/
|
|
@@ -305,36 +365,38 @@ interface ArtifactObserver<TArtifact> {
|
|
|
305
365
|
/** The unique identifier (key) of the artifact being watched. */
|
|
306
366
|
id: string;
|
|
307
367
|
/**
|
|
308
|
-
* Number of active references to this
|
|
368
|
+
* Number of active references (watchers) to this observer instance.
|
|
309
369
|
* Incremented on each `watch()` call, decremented on each `dispose()` call.
|
|
310
370
|
*/
|
|
311
371
|
count: number;
|
|
312
372
|
/**
|
|
313
373
|
* Retrieves the current `ResolvedArtifact` for the watched key.
|
|
314
|
-
* @returns The resolved artifact.
|
|
374
|
+
* @returns The resolved artifact, including its instance and status.
|
|
315
375
|
*/
|
|
316
376
|
get(): ResolvedArtifact<TArtifact>;
|
|
317
377
|
/**
|
|
318
378
|
* Subscribes a callback function to be invoked whenever the artifact's
|
|
319
|
-
* state (instance or
|
|
320
|
-
* @param callback The function to call on updates.
|
|
321
|
-
* @returns A function to unsubscribe the callback.
|
|
379
|
+
* state (instance, error, or readiness) changes.
|
|
380
|
+
* @param callback The function to call on updates. It receives the new `ResolvedArtifact`.
|
|
381
|
+
* @returns A function to unsubscribe the callback and stop receiving updates.
|
|
322
382
|
*/
|
|
323
383
|
subscribe(callback: (artifact: ResolvedArtifact<TArtifact>) => void): () => void;
|
|
324
384
|
/**
|
|
325
|
-
* Disposes of this
|
|
326
|
-
* When the count reaches zero,
|
|
327
|
-
*
|
|
328
|
-
* this will unregister the cloned singleton when the last reference is disposed.
|
|
385
|
+
* Disposes of this specific observer reference, decrementing the reference count.
|
|
386
|
+
* When the count reaches zero, associated resources (like cloned singletons for Transient artifacts)
|
|
387
|
+
* are cleaned up.
|
|
329
388
|
*/
|
|
330
389
|
dispose(): Promise<void>;
|
|
331
390
|
}
|
|
332
391
|
/**
|
|
333
392
|
* Configuration options for defining an artifact. These options control
|
|
334
393
|
* its lifecycle, instantiation, and error handling behavior.
|
|
394
|
+
* @template TState The type of the global state.
|
|
395
|
+
* @template TArtifact The resolved type of the artifact instance.
|
|
396
|
+
* @template TRegistry The type mapping of all artifacts in the container.
|
|
335
397
|
*/
|
|
336
398
|
interface ArtifactTemplate<TState extends object, TArtifact, TRegistry extends object = any> {
|
|
337
|
-
/** The unique key identifying this artifact. */
|
|
399
|
+
/** The unique key identifying this artifact within the registry. */
|
|
338
400
|
key: keyof TRegistry;
|
|
339
401
|
/** The factory function responsible for creating the artifact's instance. */
|
|
340
402
|
factory: ArtifactFactory<TRegistry, TState, TArtifact>;
|
|
@@ -345,8 +407,8 @@ interface ArtifactTemplate<TState extends object, TArtifact, TRegistry extends o
|
|
|
345
407
|
scope?: ArtifactScope;
|
|
346
408
|
/**
|
|
347
409
|
* If `true` (default), the artifact's factory is executed only when the artifact
|
|
348
|
-
* is first requested. If `false`, the artifact is built
|
|
349
|
-
* (only applies to Singleton scopes).
|
|
410
|
+
* is first requested (lazy instantiation). If `false`, the artifact is built
|
|
411
|
+
* immediately upon registration (only applies to Singleton scopes).
|
|
350
412
|
*/
|
|
351
413
|
lazy?: boolean;
|
|
352
414
|
/**
|
|
@@ -356,60 +418,60 @@ interface ArtifactTemplate<TState extends object, TArtifact, TRegistry extends o
|
|
|
356
418
|
timeout?: number;
|
|
357
419
|
/**
|
|
358
420
|
* Number of times to retry the artifact's factory on failure due to an
|
|
359
|
-
* external (runtime) error.
|
|
421
|
+
* external (runtime) error (e.g., an exception in an async dependency).
|
|
422
|
+
* SystemErrors (e.g., key not found) are not retried. Defaults to `0`.
|
|
360
423
|
*/
|
|
361
424
|
retries?: number;
|
|
362
425
|
/**
|
|
363
426
|
* Base debounce time in milliseconds for invalidation events originating
|
|
364
|
-
* from this artifact. This
|
|
427
|
+
* from this artifact's dependencies. This delays the rebuild process to
|
|
428
|
+
* aggregate multiple rapid changes.
|
|
365
429
|
*/
|
|
366
430
|
debounce?: number;
|
|
367
431
|
}
|
|
368
432
|
/**
|
|
369
|
-
* Extracts the state type from an ArtifactTemplate
|
|
433
|
+
* Extracts the global state type (`TState`) from an `ArtifactTemplate`.
|
|
370
434
|
*/
|
|
371
435
|
type ArtifactStateType<T> = T extends ArtifactTemplate<infer TState, any, any> ? TState : never;
|
|
372
436
|
/**
|
|
373
|
-
* Extracts the registry type from an ArtifactTemplate
|
|
437
|
+
* Extracts the full artifact registry type (`TRegistry`) from an `ArtifactTemplate`.
|
|
374
438
|
*/
|
|
375
439
|
type ArtifactRegistryType<T> = T extends ArtifactTemplate<any, any, infer TRegistry> ? TRegistry : never;
|
|
376
440
|
/**
|
|
377
|
-
* Extracts the key from an ArtifactTemplate (as a string literal if possible)
|
|
441
|
+
* Extracts the key type (`K`) from an `ArtifactTemplate` (as a string literal if possible).
|
|
378
442
|
*/
|
|
379
443
|
type ArtifactKey<T> = T extends {
|
|
380
444
|
key: infer K;
|
|
381
445
|
} ? K : never;
|
|
382
446
|
/**
|
|
383
|
-
* Extracts the scope from an ArtifactTemplate
|
|
447
|
+
* Extracts the scope type (`S`) from an `ArtifactTemplate`, defaulting to `ArtifactScope` if undefined.
|
|
384
448
|
*/
|
|
385
449
|
type ArtifactScopeType<T> = T extends {
|
|
386
450
|
scope: infer S;
|
|
387
451
|
} ? S extends ArtifactScope ? S : ArtifactScope : ArtifactScope;
|
|
388
452
|
/**
|
|
389
|
-
* Helper type that creates a properly typed template map
|
|
390
|
-
*
|
|
453
|
+
* Helper type that creates a properly typed template map where keys correspond to artifact names
|
|
454
|
+
* and values are their corresponding templates.
|
|
455
|
+
* @template TState The type of the global state.
|
|
456
|
+
* @template TRegistry The map of all artifact keys to their resolved types.
|
|
391
457
|
*/
|
|
392
458
|
type ArtifactTemplateMap<TState extends object, TRegistry extends Record<string, any> = any> = {
|
|
393
459
|
[K in keyof TRegistry]: ArtifactTemplate<TState, TRegistry[K], TRegistry>;
|
|
394
460
|
};
|
|
395
461
|
/**
|
|
396
|
-
* Extracts the artifact's resolved value type from an object that structurally
|
|
397
|
-
* resembles an ArtifactTemplate (
|
|
398
|
-
*
|
|
399
|
-
* It infers TArtifact from the second generic argument of the factory function,
|
|
400
|
-
* which is the resolved artifact type.
|
|
462
|
+
* Extracts the artifact's resolved value type (`TArtifact`) from an object that structurally
|
|
463
|
+
* resembles an `ArtifactTemplate` (by inspecting the `factory` function's generic arguments).
|
|
401
464
|
*
|
|
402
|
-
* @template T The type that
|
|
465
|
+
* @template T The type that contains a factory property.
|
|
403
466
|
*/
|
|
404
467
|
type ArtifactValue<T> = T extends {
|
|
405
468
|
factory: ArtifactFactory<any, any, infer TArtifact>;
|
|
406
469
|
} ? TArtifact : never;
|
|
407
470
|
/**
|
|
408
|
-
* Infers the complete Artifact Registry type from a map of artifact
|
|
471
|
+
* Infers the complete Artifact Registry type from a map of artifact configuration objects.
|
|
409
472
|
*
|
|
410
|
-
* This
|
|
411
|
-
*
|
|
412
|
-
* of the 'factory' property to determine the final type.
|
|
473
|
+
* This utility uses the `ArtifactValue` type to determine the resolved type for each key
|
|
474
|
+
* based on the `factory` function defined in the configuration.
|
|
413
475
|
*
|
|
414
476
|
* @template T A map where keys are artifact names and values are their configurations.
|
|
415
477
|
*/
|
|
@@ -527,4 +589,4 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
|
|
|
527
589
|
dispose(): void;
|
|
528
590
|
}
|
|
529
591
|
|
|
530
|
-
export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type InferRegistry, type ResolvedArtifact, type UseDependencyContext };
|
|
592
|
+
export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type ErrorArtifact, type InferRegistry, type PendingArtifact, type ReadyArtifact, type ResolvedArtifact, type ResolvedArtifactBase, type UseDependencyContext };
|
package/index.d.ts
CHANGED
|
@@ -91,22 +91,30 @@ interface DataStore<T extends object> {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Defines the lifecycle and sharing strategy for an artifact.
|
|
94
|
+
* Defines the lifecycle and sharing strategy for an artifact within the container.
|
|
95
95
|
*/
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Defines the lifecycle and sharing strategy for an artifact.
|
|
99
|
+
*/
|
|
97
100
|
type ArtifactScope =
|
|
98
101
|
/**
|
|
99
|
-
* A single instance of the artifact is created and shared across all resolutions
|
|
100
|
-
* within the container. It is created once and reused.
|
|
102
|
+
* **Singleton:** A single instance of the artifact is created and shared across all resolutions
|
|
103
|
+
* within the container. It is created once (often lazily) and reused until invalidated.
|
|
101
104
|
*/
|
|
102
105
|
"singleton"
|
|
103
106
|
/**
|
|
104
|
-
* A new instance of the artifact is created every time it is resolved.
|
|
105
|
-
* Transient artifacts do not participate in caching or shared state.
|
|
107
|
+
* **Transient:** A new instance of the artifact is created every time it is resolved.
|
|
108
|
+
* Transient artifacts do not participate in caching or shared state management.
|
|
106
109
|
*/
|
|
107
110
|
| "transient";
|
|
111
|
+
/**
|
|
112
|
+
* Enumeration of standard artifact scopes for strongly typed configuration.
|
|
113
|
+
*/
|
|
108
114
|
declare enum ArtifactScopes {
|
|
115
|
+
/** A single instance is shared globally. */
|
|
109
116
|
Singleton = "singleton",
|
|
117
|
+
/** A new instance is created on every resolution. */
|
|
110
118
|
Transient = "transient"
|
|
111
119
|
}
|
|
112
120
|
/**
|
|
@@ -120,19 +128,20 @@ interface ArtifactDebugNode {
|
|
|
120
128
|
scope: ArtifactScope;
|
|
121
129
|
/**
|
|
122
130
|
* The current status of the artifact, indicating its lifecycle phase.
|
|
123
|
-
* - 'active'
|
|
124
|
-
* - 'error'
|
|
125
|
-
* - 'idle'
|
|
126
|
-
* - 'building'
|
|
127
|
-
* - '
|
|
128
|
-
*/
|
|
129
|
-
status: "active" | "error" | "idle" | "
|
|
131
|
+
* - `'active'`: The artifact is successfully built and its instance is available.
|
|
132
|
+
* - `'error'`: The artifact failed to build due to an external (runtime) error.
|
|
133
|
+
* - `'idle'`: The artifact has not yet been built (for lazy singletons) or has been disposed.
|
|
134
|
+
* - `'building'`: The artifact's factory is currently executing.
|
|
135
|
+
* - `'pending'`: The artifact is waiting to be built, often after an invalidation and before any debounce.
|
|
136
|
+
*/
|
|
137
|
+
status: "active" | "error" | "idle" | "building" | "pending" | "debouncing";
|
|
138
|
+
/** A list of artifact keys that this artifact directly depends on. */
|
|
130
139
|
dependencies: string[];
|
|
131
|
-
/** A list of artifact keys that directly depend on this artifact. */
|
|
140
|
+
/** A list of artifact keys that directly depend on this artifact (its consumers). */
|
|
132
141
|
dependents: string[];
|
|
133
142
|
/** A list of state paths (selectors) that this artifact depends on. */
|
|
134
143
|
stateDependencies: string[];
|
|
135
|
-
/** The number of times this artifact's factory has been successfully executed. */
|
|
144
|
+
/** The number of times this artifact's factory has been successfully executed/rebuilt. */
|
|
136
145
|
renderCount: number;
|
|
137
146
|
}
|
|
138
147
|
/**
|
|
@@ -143,54 +152,62 @@ interface ArtifactDebugNode {
|
|
|
143
152
|
*/
|
|
144
153
|
interface UseDependencyContext<TRegistry extends Record<string, any>, TState extends object> {
|
|
145
154
|
/**
|
|
146
|
-
* Resolves another artifact from the container.
|
|
147
|
-
*
|
|
148
|
-
* changes, this artifact will be invalidated and rebuilt.
|
|
155
|
+
* Resolves another artifact from the container and registers a dependency on it.
|
|
156
|
+
* If the dependency changes, the current artifact will be invalidated and rebuilt.
|
|
149
157
|
* @template K The key of the artifact to resolve.
|
|
150
158
|
* @param key The key of the artifact to resolve.
|
|
151
159
|
* @returns A Promise that resolves to a `ResolvedArtifact` containing the instance
|
|
152
|
-
*
|
|
160
|
+
* or an external error.
|
|
153
161
|
* @throws {SystemError} if the key is missing or if resolving creates a circular dependency.
|
|
154
162
|
*/
|
|
155
163
|
resolve<K extends keyof TRegistry>(key: K): Promise<ResolvedArtifact<TRegistry[K]>>;
|
|
156
164
|
/**
|
|
157
|
-
* Selects a slice of the global state.
|
|
158
|
-
*
|
|
159
|
-
*
|
|
165
|
+
* Selects a slice of the global state and registers a dependency on it.
|
|
166
|
+
* If the selected state slice changes (based on a deep comparison), the current
|
|
167
|
+
* artifact will be invalidated and rebuilt.
|
|
160
168
|
* @template S The type of the selected state slice.
|
|
161
|
-
* @param selector A function that takes the full state and returns a slice.
|
|
169
|
+
* @param selector A function that takes the full state and returns a slice of state.
|
|
162
170
|
* @returns The selected slice of state.
|
|
163
171
|
*/
|
|
164
172
|
select<S>(selector: (state: TState) => S): S;
|
|
165
173
|
}
|
|
166
174
|
/**
|
|
167
|
-
* Context object provided to an artifact stream producer function.
|
|
168
|
-
* It contains methods and properties necessary for managing the stream
|
|
169
|
-
*
|
|
175
|
+
* Context object provided to an artifact stream producer function (`ctx.stream` callback).
|
|
176
|
+
* It contains methods and properties necessary for managing the stream and communicating
|
|
177
|
+
* new artifact values to the container and its consumers.
|
|
170
178
|
*
|
|
179
|
+
* @template TState The type of the global state.
|
|
171
180
|
* @template TArtifact The type of the artifact being streamed.
|
|
172
181
|
*/
|
|
173
182
|
type ArtifactStreamContext<TState, TArtifact> = {
|
|
174
183
|
/**
|
|
175
184
|
* The current value of the artifact. This is `undefined` before the first value is emitted.
|
|
176
185
|
* Useful for diffing or migrating state during an update.
|
|
186
|
+
* @returns The current artifact value or `undefined`.
|
|
177
187
|
*/
|
|
178
188
|
value: () => TArtifact | undefined;
|
|
179
189
|
/**
|
|
180
190
|
* An AbortSignal that indicates if the stream has been cancelled or aborted
|
|
181
|
-
* from the consumer side.
|
|
182
|
-
* processing when it is set.
|
|
191
|
+
* from the consumer side (e.g., due to container disposal or artifact invalidation).
|
|
192
|
+
* Producers should check this signal and stop processing when it is set to prevent leaks.
|
|
183
193
|
*/
|
|
184
194
|
signal: AbortSignal;
|
|
185
195
|
/**
|
|
186
|
-
* A function to asynchronously emit a new value of the artifact to the
|
|
187
|
-
* Calling this function updates the
|
|
188
|
-
*
|
|
196
|
+
* A function to asynchronously emit a new value of the artifact to the container.
|
|
197
|
+
* Calling this function updates the artifact's resolved value, triggers invalidation
|
|
198
|
+
* for its dependents, and updates the `value()` property for subsequent emissions.
|
|
189
199
|
*
|
|
190
200
|
* @param value The new artifact value to emit.
|
|
191
|
-
* @returns A Promise that resolves when the value has been sent.
|
|
201
|
+
* @returns A Promise that resolves when the value has been sent and dependents have been notified.
|
|
192
202
|
*/
|
|
193
203
|
emit: (value: TArtifact) => Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* Dispatches a state update to the global store, analogous to a standard `setState`.
|
|
206
|
+
* **Note:** This does not automatically register a dependency for the current artifact.
|
|
207
|
+
* @param update A `StateUpdater` function or a partial state object.
|
|
208
|
+
* @param options Optional settings for the update, including `force` and `actionId`.
|
|
209
|
+
* @returns A Promise that resolves when the state update is complete.
|
|
210
|
+
*/
|
|
194
211
|
set(update: StateUpdater<TState>, options?: {
|
|
195
212
|
force?: boolean;
|
|
196
213
|
actionId?: string;
|
|
@@ -208,13 +225,14 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
|
|
|
208
225
|
/**
|
|
209
226
|
* Returns the current global state object. This is a non-reactive read;
|
|
210
227
|
* changes to the state will not automatically invalidate the artifact
|
|
211
|
-
* unless explicitly selected via `ctx.
|
|
228
|
+
* unless explicitly selected via `ctx.use` and `ctx.select`.
|
|
212
229
|
* @returns The current global state.
|
|
213
230
|
*/
|
|
214
231
|
state(): TState;
|
|
215
232
|
/**
|
|
216
|
-
* The previous instance of the artifact if it's a Singleton and is being rebuilt
|
|
217
|
-
*
|
|
233
|
+
* The previous instance of the artifact if it's a Singleton and is being rebuilt
|
|
234
|
+
* after an invalidation. This is `undefined` on the initial build.
|
|
235
|
+
* Useful for diffing, migrating state, or reusing resources during an update.
|
|
218
236
|
*/
|
|
219
237
|
previous?: TArtifact;
|
|
220
238
|
/**
|
|
@@ -223,81 +241,123 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
|
|
|
223
241
|
* dependencies for the current artifact.
|
|
224
242
|
* @template R The return type of the callback.
|
|
225
243
|
* @param callback The function to execute to resolve dependencies.
|
|
226
|
-
* @param options Optional settings for this dependency block, like debounce.
|
|
227
244
|
* @returns A Promise resolving to the result of the callback.
|
|
228
245
|
*/
|
|
229
246
|
use<R>(callback: (ctx: UseDependencyContext<TRegistry, TState>) => R | Promise<R>): Promise<R>;
|
|
230
247
|
/**
|
|
231
|
-
* Registers a cleanup function to be executed when the
|
|
232
|
-
* invalidated and before its new instance is built. This is useful
|
|
233
|
-
* for releasing resources specific to the *previous* instance.
|
|
248
|
+
* Registers a cleanup function to be executed when the **current instance** of the
|
|
249
|
+
* artifact is invalidated and before its new instance is built. This is useful
|
|
250
|
+
* for releasing resources (e.g., event listeners) specific to the *previous* instance.
|
|
234
251
|
* @param cleanup The cleanup function.
|
|
235
252
|
*/
|
|
236
253
|
onCleanup(cleanup: ArtifactCleanup): void;
|
|
237
254
|
/**
|
|
238
255
|
* Registers a dispose function to be executed when the artifact is
|
|
239
256
|
* permanently removed from the container or the container itself is disposed.
|
|
240
|
-
* This is for final resource release.
|
|
257
|
+
* This is for final, permanent resource release.
|
|
241
258
|
* @param callback The dispose function.
|
|
242
259
|
*/
|
|
243
260
|
onDispose(callback: ArtifactCleanup): void;
|
|
244
261
|
/**
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
* for
|
|
248
|
-
*
|
|
249
|
-
* @param value The new value for the artifact.
|
|
262
|
+
* Starts a stream process for a Singleton artifact, allowing it to emit
|
|
263
|
+
* multiple values over time. The callback receives an `ArtifactStreamContext`
|
|
264
|
+
* for emitting values and managing the stream lifecycle.
|
|
265
|
+
* @param callback The function that implements the streaming logic.
|
|
250
266
|
* @throws {SystemError} if called on a Transient artifact, as Transient artifacts
|
|
251
|
-
*
|
|
267
|
+
* do not maintain a persistent value.
|
|
252
268
|
*/
|
|
253
269
|
stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => void | Promise<void>): void;
|
|
254
270
|
}
|
|
255
271
|
/**
|
|
256
|
-
* A function that performs cleanup logic for an artifact, potentially asynchronously.
|
|
272
|
+
* A function that performs cleanup or disposal logic for an artifact, potentially asynchronously.
|
|
257
273
|
* Used for `onCleanup` and `onDispose` callbacks.
|
|
258
274
|
*/
|
|
259
275
|
type ArtifactCleanup = () => void | Promise<void>;
|
|
260
276
|
/**
|
|
261
|
-
*
|
|
262
|
-
* cleanup functionality, and details about any external errors.
|
|
277
|
+
* Common properties shared across all possible states of a resolved artifact.
|
|
263
278
|
* @template TArtifact The type of the resolved artifact instance.
|
|
264
279
|
*/
|
|
265
|
-
interface
|
|
266
|
-
/** The successfully resolved instance of the artifact, if no error occurred. */
|
|
267
|
-
instance?: TArtifact;
|
|
280
|
+
interface ResolvedArtifactBase {
|
|
268
281
|
/**
|
|
269
282
|
* A function to manually trigger cleanup associated with this specific
|
|
270
|
-
* resolved instance. This is typically only relevant for Transient artifacts
|
|
283
|
+
* resolved instance. This is typically only relevant for Transient artifacts
|
|
284
|
+
* where the consumer is responsible for cleanup.
|
|
271
285
|
*/
|
|
272
286
|
cleanup?: ArtifactCleanup;
|
|
273
|
-
/**
|
|
274
|
-
* Any runtime or external error that occurred during the artifact's factory
|
|
275
|
-
* execution (e.g., fetch failed, timeout). SystemErrors are explicitly
|
|
276
|
-
* thrown and will not appear here.
|
|
277
|
-
*/
|
|
278
|
-
error?: any;
|
|
279
|
-
ready: boolean;
|
|
280
287
|
/**
|
|
281
288
|
* Manually invalidates this artifact, triggering its rebuild and
|
|
282
289
|
* cascading invalidations to its dependents.
|
|
283
|
-
* @param replace If `true`, forces immediate rebuild without debounce.
|
|
290
|
+
* @param replace If `true`, forces immediate rebuild without debounce delay.
|
|
291
|
+
* @param fatal If `true`, the artifact will not be rebuilt until next resolve
|
|
292
|
+
* regardless of the lazy option during registration.
|
|
293
|
+
*/
|
|
294
|
+
invalidate(replace?: boolean, fatal?: boolean): Promise<void>;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* State of an artifact that is successfully built and ready for use.
|
|
298
|
+
* The instance is guaranteed to be present.
|
|
299
|
+
* @template TArtifact The type of the resolved artifact instance.
|
|
300
|
+
*/
|
|
301
|
+
interface ReadyArtifact<TArtifact> extends ResolvedArtifactBase {
|
|
302
|
+
/** The successfully resolved instance of the artifact. */
|
|
303
|
+
instance: TArtifact;
|
|
304
|
+
/** Indicates that the artifact is ready and has an instance. Always true. */
|
|
305
|
+
ready: true;
|
|
306
|
+
/** Must be undefined in a ready state. */
|
|
307
|
+
error?: undefined;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* State of an artifact that failed to build due to an external error.
|
|
311
|
+
* The instance is guaranteed to be absent.
|
|
312
|
+
*/
|
|
313
|
+
interface ErrorArtifact extends ResolvedArtifactBase {
|
|
314
|
+
/** The instance is absent when an error occurs. Always undefined. */
|
|
315
|
+
instance?: undefined;
|
|
316
|
+
/** Indicates that the artifact failed to build. Always false. */
|
|
317
|
+
ready: false;
|
|
318
|
+
/**
|
|
319
|
+
* Any runtime or external error that occurred during the artifact's factory
|
|
320
|
+
* execution (e.g., network fetch failed).
|
|
284
321
|
*/
|
|
285
|
-
|
|
322
|
+
error: any;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* State of an artifact that is pending, idle, or currently building.
|
|
326
|
+
* Both instance and error are absent.
|
|
327
|
+
*/
|
|
328
|
+
interface PendingArtifact extends ResolvedArtifactBase {
|
|
329
|
+
/** The instance is absent while pending or idle. Always undefined. */
|
|
330
|
+
instance?: undefined;
|
|
331
|
+
/** Indicates that the artifact is not yet ready. Always false. */
|
|
332
|
+
ready: false;
|
|
333
|
+
/** Must be undefined in a pending state. */
|
|
334
|
+
error?: undefined;
|
|
286
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* The result of an artifact resolution. This is a union type representing
|
|
338
|
+
* the artifact in one of three possible states: Ready, Error, or Pending/Idle.
|
|
339
|
+
*
|
|
340
|
+
* This structure allows consuming code to narrow the type based on the
|
|
341
|
+
* boolean flag `ready` or the presence of the `error` property.
|
|
342
|
+
*
|
|
343
|
+
* @template TArtifact The type of the resolved artifact instance.
|
|
344
|
+
*/
|
|
345
|
+
type ResolvedArtifact<TArtifact> = ReadyArtifact<TArtifact> | ErrorArtifact | PendingArtifact;
|
|
287
346
|
/**
|
|
288
347
|
* The factory function responsible for creating an artifact's instance.
|
|
289
348
|
* It receives an `ArtifactFactoryContext` to interact with the container
|
|
290
349
|
* and declare dependencies.
|
|
291
350
|
* @template TRegistry The type mapping artifact keys to their artifact types.
|
|
292
351
|
* @template TState The type of the global state managed by the DataStore.
|
|
293
|
-
* @template
|
|
352
|
+
* @template TArtifact The type of the artifact this factory produces.
|
|
294
353
|
* @param context The context for creating the artifact.
|
|
295
354
|
* @returns The artifact instance or a Promise resolving to it.
|
|
296
355
|
*/
|
|
297
356
|
type ArtifactFactory<TRegistry extends Record<string, any>, TState extends object, TArtifact> = (context: ArtifactFactoryContext<TRegistry, TState, TArtifact>) => TArtifact | Promise<TArtifact>;
|
|
298
357
|
type ArtifactInstance<R> = R extends PromiseLike<infer T> ? T : R;
|
|
299
358
|
/**
|
|
300
|
-
* An interface for observing changes to an artifact without direct resolution
|
|
359
|
+
* An interface for observing changes to an artifact without direct resolution,
|
|
360
|
+
* typically used for UI binding or monitoring.
|
|
301
361
|
* Provides a way to get the current resolved artifact and subscribe to updates.
|
|
302
362
|
* @template TArtifact The type of the artifact being watched.
|
|
303
363
|
*/
|
|
@@ -305,36 +365,38 @@ interface ArtifactObserver<TArtifact> {
|
|
|
305
365
|
/** The unique identifier (key) of the artifact being watched. */
|
|
306
366
|
id: string;
|
|
307
367
|
/**
|
|
308
|
-
* Number of active references to this
|
|
368
|
+
* Number of active references (watchers) to this observer instance.
|
|
309
369
|
* Incremented on each `watch()` call, decremented on each `dispose()` call.
|
|
310
370
|
*/
|
|
311
371
|
count: number;
|
|
312
372
|
/**
|
|
313
373
|
* Retrieves the current `ResolvedArtifact` for the watched key.
|
|
314
|
-
* @returns The resolved artifact.
|
|
374
|
+
* @returns The resolved artifact, including its instance and status.
|
|
315
375
|
*/
|
|
316
376
|
get(): ResolvedArtifact<TArtifact>;
|
|
317
377
|
/**
|
|
318
378
|
* Subscribes a callback function to be invoked whenever the artifact's
|
|
319
|
-
* state (instance or
|
|
320
|
-
* @param callback The function to call on updates.
|
|
321
|
-
* @returns A function to unsubscribe the callback.
|
|
379
|
+
* state (instance, error, or readiness) changes.
|
|
380
|
+
* @param callback The function to call on updates. It receives the new `ResolvedArtifact`.
|
|
381
|
+
* @returns A function to unsubscribe the callback and stop receiving updates.
|
|
322
382
|
*/
|
|
323
383
|
subscribe(callback: (artifact: ResolvedArtifact<TArtifact>) => void): () => void;
|
|
324
384
|
/**
|
|
325
|
-
* Disposes of this
|
|
326
|
-
* When the count reaches zero,
|
|
327
|
-
*
|
|
328
|
-
* this will unregister the cloned singleton when the last reference is disposed.
|
|
385
|
+
* Disposes of this specific observer reference, decrementing the reference count.
|
|
386
|
+
* When the count reaches zero, associated resources (like cloned singletons for Transient artifacts)
|
|
387
|
+
* are cleaned up.
|
|
329
388
|
*/
|
|
330
389
|
dispose(): Promise<void>;
|
|
331
390
|
}
|
|
332
391
|
/**
|
|
333
392
|
* Configuration options for defining an artifact. These options control
|
|
334
393
|
* its lifecycle, instantiation, and error handling behavior.
|
|
394
|
+
* @template TState The type of the global state.
|
|
395
|
+
* @template TArtifact The resolved type of the artifact instance.
|
|
396
|
+
* @template TRegistry The type mapping of all artifacts in the container.
|
|
335
397
|
*/
|
|
336
398
|
interface ArtifactTemplate<TState extends object, TArtifact, TRegistry extends object = any> {
|
|
337
|
-
/** The unique key identifying this artifact. */
|
|
399
|
+
/** The unique key identifying this artifact within the registry. */
|
|
338
400
|
key: keyof TRegistry;
|
|
339
401
|
/** The factory function responsible for creating the artifact's instance. */
|
|
340
402
|
factory: ArtifactFactory<TRegistry, TState, TArtifact>;
|
|
@@ -345,8 +407,8 @@ interface ArtifactTemplate<TState extends object, TArtifact, TRegistry extends o
|
|
|
345
407
|
scope?: ArtifactScope;
|
|
346
408
|
/**
|
|
347
409
|
* If `true` (default), the artifact's factory is executed only when the artifact
|
|
348
|
-
* is first requested. If `false`, the artifact is built
|
|
349
|
-
* (only applies to Singleton scopes).
|
|
410
|
+
* is first requested (lazy instantiation). If `false`, the artifact is built
|
|
411
|
+
* immediately upon registration (only applies to Singleton scopes).
|
|
350
412
|
*/
|
|
351
413
|
lazy?: boolean;
|
|
352
414
|
/**
|
|
@@ -356,60 +418,60 @@ interface ArtifactTemplate<TState extends object, TArtifact, TRegistry extends o
|
|
|
356
418
|
timeout?: number;
|
|
357
419
|
/**
|
|
358
420
|
* Number of times to retry the artifact's factory on failure due to an
|
|
359
|
-
* external (runtime) error.
|
|
421
|
+
* external (runtime) error (e.g., an exception in an async dependency).
|
|
422
|
+
* SystemErrors (e.g., key not found) are not retried. Defaults to `0`.
|
|
360
423
|
*/
|
|
361
424
|
retries?: number;
|
|
362
425
|
/**
|
|
363
426
|
* Base debounce time in milliseconds for invalidation events originating
|
|
364
|
-
* from this artifact. This
|
|
427
|
+
* from this artifact's dependencies. This delays the rebuild process to
|
|
428
|
+
* aggregate multiple rapid changes.
|
|
365
429
|
*/
|
|
366
430
|
debounce?: number;
|
|
367
431
|
}
|
|
368
432
|
/**
|
|
369
|
-
* Extracts the state type from an ArtifactTemplate
|
|
433
|
+
* Extracts the global state type (`TState`) from an `ArtifactTemplate`.
|
|
370
434
|
*/
|
|
371
435
|
type ArtifactStateType<T> = T extends ArtifactTemplate<infer TState, any, any> ? TState : never;
|
|
372
436
|
/**
|
|
373
|
-
* Extracts the registry type from an ArtifactTemplate
|
|
437
|
+
* Extracts the full artifact registry type (`TRegistry`) from an `ArtifactTemplate`.
|
|
374
438
|
*/
|
|
375
439
|
type ArtifactRegistryType<T> = T extends ArtifactTemplate<any, any, infer TRegistry> ? TRegistry : never;
|
|
376
440
|
/**
|
|
377
|
-
* Extracts the key from an ArtifactTemplate (as a string literal if possible)
|
|
441
|
+
* Extracts the key type (`K`) from an `ArtifactTemplate` (as a string literal if possible).
|
|
378
442
|
*/
|
|
379
443
|
type ArtifactKey<T> = T extends {
|
|
380
444
|
key: infer K;
|
|
381
445
|
} ? K : never;
|
|
382
446
|
/**
|
|
383
|
-
* Extracts the scope from an ArtifactTemplate
|
|
447
|
+
* Extracts the scope type (`S`) from an `ArtifactTemplate`, defaulting to `ArtifactScope` if undefined.
|
|
384
448
|
*/
|
|
385
449
|
type ArtifactScopeType<T> = T extends {
|
|
386
450
|
scope: infer S;
|
|
387
451
|
} ? S extends ArtifactScope ? S : ArtifactScope : ArtifactScope;
|
|
388
452
|
/**
|
|
389
|
-
* Helper type that creates a properly typed template map
|
|
390
|
-
*
|
|
453
|
+
* Helper type that creates a properly typed template map where keys correspond to artifact names
|
|
454
|
+
* and values are their corresponding templates.
|
|
455
|
+
* @template TState The type of the global state.
|
|
456
|
+
* @template TRegistry The map of all artifact keys to their resolved types.
|
|
391
457
|
*/
|
|
392
458
|
type ArtifactTemplateMap<TState extends object, TRegistry extends Record<string, any> = any> = {
|
|
393
459
|
[K in keyof TRegistry]: ArtifactTemplate<TState, TRegistry[K], TRegistry>;
|
|
394
460
|
};
|
|
395
461
|
/**
|
|
396
|
-
* Extracts the artifact's resolved value type from an object that structurally
|
|
397
|
-
* resembles an ArtifactTemplate (
|
|
398
|
-
*
|
|
399
|
-
* It infers TArtifact from the second generic argument of the factory function,
|
|
400
|
-
* which is the resolved artifact type.
|
|
462
|
+
* Extracts the artifact's resolved value type (`TArtifact`) from an object that structurally
|
|
463
|
+
* resembles an `ArtifactTemplate` (by inspecting the `factory` function's generic arguments).
|
|
401
464
|
*
|
|
402
|
-
* @template T The type that
|
|
465
|
+
* @template T The type that contains a factory property.
|
|
403
466
|
*/
|
|
404
467
|
type ArtifactValue<T> = T extends {
|
|
405
468
|
factory: ArtifactFactory<any, any, infer TArtifact>;
|
|
406
469
|
} ? TArtifact : never;
|
|
407
470
|
/**
|
|
408
|
-
* Infers the complete Artifact Registry type from a map of artifact
|
|
471
|
+
* Infers the complete Artifact Registry type from a map of artifact configuration objects.
|
|
409
472
|
*
|
|
410
|
-
* This
|
|
411
|
-
*
|
|
412
|
-
* of the 'factory' property to determine the final type.
|
|
473
|
+
* This utility uses the `ArtifactValue` type to determine the resolved type for each key
|
|
474
|
+
* based on the `factory` function defined in the configuration.
|
|
413
475
|
*
|
|
414
476
|
* @template T A map where keys are artifact names and values are their configurations.
|
|
415
477
|
*/
|
|
@@ -527,4 +589,4 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
|
|
|
527
589
|
dispose(): void;
|
|
528
590
|
}
|
|
529
591
|
|
|
530
|
-
export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type InferRegistry, type ResolvedArtifact, type UseDependencyContext };
|
|
592
|
+
export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type ErrorArtifact, type InferRegistry, type PendingArtifact, type ReadyArtifact, type ResolvedArtifact, type ResolvedArtifactBase, type UseDependencyContext };
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t,r=Object.create,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,c=(e={"src/store/node_modules/@asaidimu/events/index.js"(e,t){var r,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(o,{createEventBus:()=>c}),t.exports=(r=o,((e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))a.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(o=n(t,c))||o.enumerable});return e})(s({},"__esModule",{value:!0}),r));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let r=[],s=0,n=0;const i=new Map,a=new Map;let o=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?o=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{s++,n+=t,i.set(e,(i.get(e)||0)+1)},h=()=>{const t=r;r=[],t.forEach((({name:t,payload:r})=>{const s=performance.now();try{(a.get(t)||[]).forEach((e=>e(r)))}catch(s){e.errorHandler({...s,eventName:t,payload:r})}c(t,performance.now()-s)}))},d=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(h,e.batchDelay)}})(),l=e=>{const r=t.get(e);r?a.set(e,Array.from(r)):a.delete(e)};return o&&(o.onmessage=e=>{const{name:t,payload:r}=e.data;(a.get(t)||[]).forEach((e=>e(r)))}),{subscribe:(e,r)=>{t.has(e)||t.set(e,new Set);const s=t.get(e);return s.add(r),l(e),()=>{s.delete(r),0===s.size?(t.delete(e),a.delete(e)):l(e)}},emit:({name:t,payload:s})=>{if(e.async)return r.push({name:t,payload:s}),r.length>=e.batchSize?h():d(),void(o&&o.postMessage({name:t,payload:s}));const n=performance.now();try{(a.get(t)||[]).forEach((e=>e(s))),o&&o.postMessage({name:t,payload:s})}catch(r){e.errorHandler({...r,eventName:t,payload:s})}c(t,performance.now()-n)},getMetrics:()=>({totalEvents:s,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:i,averageEmitDuration:s>0?n/s:0}),clear:()=>{t.clear(),a.clear(),r=[],s=0,n=0,i.clear(),o&&(o.close(),o=null)}}}}},function(){return t||(0,e[i(e)[0]])((t={exports:{}}).exports,t),t.exports}),h=(e=>(e.Singleton="singleton",e.Transient="transient",e))(h||{}),d=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},l=class extends d{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system")}},u=class extends d{constructor(e){super(`[ArtifactContainer] Artifact with key:${e} has already been disposed`,"system")}},p=class extends d{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`,"system")}},g=class extends d{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system")}},f=class extends d{constructor(){super("[Serializer] The serializer has been marked as done!","system")}},y=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...s}){if(this.artifacts.has(e))throw new g(String(e));const{scope:n,...i}=s,a={key:e,factory:t,scope:s.scope??"singleton",lazy:void 0===r||r,...i};return this.artifacts.set(e,a),()=>this.unregister(e)}get(e){if(!this.has(e))throw new l(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}};((e,t,c)=>{c=null!=e?r(a(e)):{},((e,t,r,a)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))o.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(a=n(t,c))||a.enumerable})})(e&&e.__esModule?c:s(c,"default",{value:e,enumerable:!0}),e)})(c());var m=class{_locked=!1;_capacity;waiters=[];constructor(e){this._capacity=e?.capacity??1/0}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null!=e)try{await Promise.race([r,new Promise(((r,s)=>setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),s(new p("Mutex lock timed out"))}),e)))])}catch(e){throw e}else await r}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},w=class{constructor(e=!1,t=!1){this.retry=e,this.throws=t}mutex=new m;promise=null;_value=null;_error;_done=!1;async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{const t=await e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}running(){return null!==this.promise&&!this._done}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){this._done=!1,this.promise=null,this._value=null,this._error=void 0}resolved(){return this.promise}done(){return this._done}_awaitWithTimeout(e,t,r="Operation timed out"){return null==t?e:Promise.race([e,new Promise(((e,s)=>setTimeout((()=>s(new p(r))),t)))])}},v=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;constructor(e){this.mutex=new m({capacity:e?.capacity??1e3})}async do(e,t){if(this._done)return{value:null,error:new f};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new f;s=await e(),this._lastValue=s,this._lastError=void 0}catch(e){r=e,this._lastError=e}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},b=class{constructor(e,t,r,s,n){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=n}async build(e,t){const r=this.registry.get(e);if(!r)throw new d(`Template not found for artifact "${String(e)}"`,"system");const s=t?new Set(t):new Set;if(s.has(e))throw new d(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(s).join(" -> ")}`,"system");s.add(e);let n=this.cache.get(e);n||(n=this.createCachedArtifact(r),this.cache.set(e,n));const i=await("transient"===r.scope?this.executeBuild(r,n,s):n.buildOnce.do((()=>this.executeBuild(r,n,s))));if("transient"===r.scope)return i;const a=this.cache.package(e,(t=>this.invalidate(e,t)));return n.stream&&n.streamOnce.do(n.stream),a}async executeBuild(e,t,r){const s=e.key;t.buildCount++;const n=[],i=[];let a=!0;t.activeDebounceMs=e.debounce??0,n.push((()=>{a=!1}));const o=new Set,c=new Set,h=new Map,l={state:()=>this.store.get(!0),previous:t.instance,onCleanup:e=>n.push(e),onDispose:e=>i.push(e),use:async e=>e({resolve:async e=>{if(e===s)throw new d(`Artifact "${String(s)}" depends on itself.`,"system");const t=this.graph.wouldCreateCycle(s,e,r);if(t)throw new d(`Adding dependency "${String(e)}" to "${String(s)}" would create a cycle: ${t.join(" -> ")}`,"system");c.add(e);const n=await this.build(e,r),i=this.cache.get(e);return i&&h.set(e,i.version),n},select:e=>(function(e,t="."){const r=new Set,s=(e=[])=>new Proxy({},{get:(n,i)=>{if("symbol"==typeof i)return;const a=[...e,i],o=a.join(t);return r.add(o),s(a)}});try{e(s())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}const n=Array.from(r);return n.filter((e=>!n.some((r=>r!==e&&r.startsWith(e+t)))))}(e).forEach((e=>o.add(e))),e(this.store.get(!0)))}),stream:async r=>{if("transient"===e.scope)throw new d(`[ArtifactManager] Illegal stream on transient artifact "${String(s)}"`,"system");const n=async(e,r=void 0)=>{await t.streamSerializer.do((async()=>{void 0!==t.stream&&(t.instance=e,t.error=r,t.version++,this.cache.invalidatePackage(s),await this.processStream(s))}))},i={value:()=>t.instance,signal:t.streamController.signal,set:(...e)=>this.store.set(...e),emit:e=>n(e)};t.stream=async()=>{try{await r(i)}catch(e){await n(void 0,e),this.invalidate(s,!1,!0)}}}};let u,p,g=0;const f=(e.retries??0)+1;for(;g<f;)try{const t=e.factory(l);if(e.timeout){const r=new Promise(((t,r)=>setTimeout((()=>r(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)));u=await Promise.race([t,r])}else u=await t;break}catch(e){if(e instanceof d)throw e;g++,g>=f&&(p=e)}if(a){for(const[e,t]of h){const r=this.cache.get(e);r&&r.version!==t&&(p=new d(`Build stale on arrival: Dependency "${String(e)}" changed during build.`,"system"))}if("singleton"===e.scope&&this.updateDependencyGraph(s,c,o),"singleton"===e.scope&&(t.cleanupFunctions=n,t.disposeFunctions=i),p?t.error=p:t.instance=u,t.version++,this.cache.invalidatePackage(s),"transient"===e.scope)return{instance:u,cleanup:this.createCompositeCleanup(n),error:p,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(s)}"`)}}else{const e=this.createCompositeCleanup(n);e&&await e()}}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise((n=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(n).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&(await s.invalidationOnce.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.getDependents(e);await Promise.all(n.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const i=this.registry.get(e);!i||!t&&i.lazy&&!this.hasWatchers(e)||r||await this.build(e),this.observer.notify(e)})),s.invalidationOnce.reset())}async dispose(e){const t=this.cache.get(e);t&&(t.streamController.abort(),t.buildOnce.running()&&await t.buildOnce.resolved(),t.invalidationOnce.running()&&await t.invalidationOnce.resolved(),t.streamOnce.running()&&await t.streamOnce.resolved(),await this.cache.invalidateInstance(e),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.getDependents(e);await Promise.all(t.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&s.stateUnsubscribe(),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){return{instance:void 0,version:0,streamController:new AbortController,error:void 0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,buildOnce:new w(!0,!0),streamOnce:new w(!0,!0),streamSerializer:new v,activeDebounceMs:e.debounce??0,invalidationOnce:new w(!0,!1)}}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},C=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),n=new Map;for(;r.length>0;){const i=r.shift();if(i===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=n.get(s);return r.reverse(),[e,...r]}const a=this.dependencies.get(i);if(a)for(const e of a)s.has(e)||(s.add(e),n.set(e,i),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const n=this.dependents.get(t);if(n)for(const t of n){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,n=new Set,i=[e];n.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;i.length>0;){const e=i.shift(),t=a.get(e);if(t)for(const e of t)n.has(e)||(n.add(e),s.add(e),i.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},A=class{graph;constructor(){this.graph=new C}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),n=e.slice(s);return n.push(t),n}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},_=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return{instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:t};if(r.packagedArtifact)return this.updatePackagedArtifact(r,r.packagedArtifact,t),r.packagedArtifact;const s={instance:r.instance,error:r.error,ready:r.buildOnce.done()&&!r.buildOnce.running(),cleanup:this.createCompositeCleanup(r.cleanupFunctions),invalidate:t};return r.packagedArtifact=s,s}async invalidatePackage(e){const t=this.get(e);t&&(t.packagedArtifact=void 0)}async invalidateInstance(e){const t=this.get(e);if(t){t.stateUnsubscribe&&(t.stateUnsubscribe(),t.stateUnsubscribe=void 0),t.debounceTimer&&(clearTimeout(t.debounceTimer),t.debounceTimer=void 0),t.streamController.abort(),await t.streamOnce.resolved(),t.streamOnce.reset(),t.streamSerializer.close();for(let e=t.cleanupFunctions.length-1;e>=0;e--)try{await t.cleanupFunctions[e]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}for(let e=t.disposeFunctions.length-1;e>=0;e--)try{await t.disposeFunctions[e]()}catch(e){console.error("[ArtifactManager] Dispose error:",e)}t.instance=void 0,t.error=void 0,t.cleanupFunctions=[],t.disposeFunctions=[],t.buildOnce.reset(),t.stream=void 0,t.streamSerializer=new v,t.streamController=new AbortController}}updatePackagedArtifact(e,t,r){t.instance=e.instance,t.error=e.error,t.ready=e.buildOnce.done()&&!e.buildOnce.running(),t.cleanup=this.createCompositeCleanup(e.cleanupFunctions),t.invalidate=r}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactCache] Cleanup error:",e)}}}},k=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);let s=t;if("transient"===r.scope&&(s=`${t}__watched`,this.registry.has(s)||this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})),this.watcherCache.has(s)){const e=this.watcherCache.get(s);return e.count++,e}let n=!1;const i={id:t,count:1,get:()=>{if(!this.cache.get(s))return this.cache.package(s,(e=>this.container.invalidate(s,e)));const e=this.cache.package(s,(e=>this.container.invalidate(s,e)));return n?{...e,ready:!1,instance:void 0,error:new u(t),cleanup:()=>{},invalidate:()=>Promise.resolve()}:e},subscribe:e=>{this.listeners.has(s)||this.listeners.set(s,new Set);const t=()=>e(i.get());return this.listeners.get(s).add(t),this.container.resolve(s).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e)})).then(t),()=>this.listeners.get(s)?.delete(t)},dispose:async()=>{i.count--,i.count<=0&&(this.watcherCache.delete(s),"transient"===r.scope&&(await this.registry.unregister(s),this.cache.delete(s)),n=!0,this.notify(s),this.listeners.delete(s))}};return this.watcherCache.set(s,i),i}notify(e){const t=this.listeners.get(e);t&&t.forEach((t=>{try{t()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}))}hasWatchers(e){return this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}};exports.ArtifactContainer=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new y,this.cache=new _,this.graph=new A,this.observer=new k(this.registry,this.cache,this),this.manager=new b(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;const n=s?s.buildOnce.running()?"pending":s.error?"error":void 0!==s.instance?"active":"idle":"idle";e.push({id:t,scope:r.scope??"singleton",status:n,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],renderCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new l(e);return this.manager.build(e)}watch(e){if(!this.registry.has(e))throw new l(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}dispose(){this.registry.keys().forEach((e=>{this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))})),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}},exports.ArtifactScopes=h;
|
|
1
|
+
"use strict";var e,t,r=Object.create,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,c=(e={"src/store/node_modules/@asaidimu/events/index.js"(e,t){var r,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(o,{createEventBus:()=>c}),t.exports=(r=o,((e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))a.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(o=n(t,c))||o.enumerable});return e})(s({},"__esModule",{value:!0}),r));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let r=[],s=0,n=0;const i=new Map,a=new Map;let o=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?o=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{s++,n+=t,i.set(e,(i.get(e)||0)+1)},h=()=>{const t=r;r=[],t.forEach((({name:t,payload:r})=>{const s=performance.now();try{(a.get(t)||[]).forEach((e=>e(r)))}catch(s){e.errorHandler({...s,eventName:t,payload:r})}c(t,performance.now()-s)}))},d=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(h,e.batchDelay)}})(),l=e=>{const r=t.get(e);r?a.set(e,Array.from(r)):a.delete(e)};return o&&(o.onmessage=e=>{const{name:t,payload:r}=e.data;(a.get(t)||[]).forEach((e=>e(r)))}),{subscribe:(e,r)=>{t.has(e)||t.set(e,new Set);const s=t.get(e);return s.add(r),l(e),()=>{s.delete(r),0===s.size?(t.delete(e),a.delete(e)):l(e)}},emit:({name:t,payload:s})=>{if(e.async)return r.push({name:t,payload:s}),r.length>=e.batchSize?h():d(),void(o&&o.postMessage({name:t,payload:s}));const n=performance.now();try{(a.get(t)||[]).forEach((e=>e(s))),o&&o.postMessage({name:t,payload:s})}catch(r){e.errorHandler({...r,eventName:t,payload:s})}c(t,performance.now()-n)},getMetrics:()=>({totalEvents:s,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:i,averageEmitDuration:s>0?n/s:0}),clear:()=>{t.clear(),a.clear(),r=[],s=0,n=0,i.clear(),o&&(o.close(),o=null)}}}}},function(){return t||(0,e[i(e)[0]])((t={exports:{}}).exports,t),t.exports}),h=(e=>(e.Singleton="singleton",e.Transient="transient",e))(h||{}),d=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},l=class extends d{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system")}},u=class extends d{constructor(e){super(`[ArtifactContainer] Artifact with key:${e} has already been disposed`,"system")}},p=class extends d{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`,"system")}},g=class extends d{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system")}},f=class extends d{constructor(){super("[Serializer] The serializer has been marked as done!","system")}},y=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...s}){if(this.artifacts.has(e))throw new g(String(e));const{scope:n,...i}=s,a={key:e,factory:t,scope:s.scope??"singleton",lazy:void 0===r||r,...i};return this.artifacts.set(e,a),()=>this.unregister(e)}get(e){if(!this.has(e))throw new l(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}};((e,t,c)=>{c=null!=e?r(a(e)):{},((e,t,r,a)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))o.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(a=n(t,c))||a.enumerable})})(e&&e.__esModule?c:s(c,"default",{value:e,enumerable:!0}),e)})(c());var m=class{_locked=!1;_capacity;waiters=[];constructor(e){this._capacity=e?.capacity??1/0}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null!=e)try{await Promise.race([r,new Promise(((r,s)=>setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),s(new p("Mutex lock timed out"))}),e)))])}catch(e){throw e}else await r}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},w=class{constructor(e=!1,t=!1){this.retry=e,this.throws=t}mutex=new m;promise=null;_value=null;_error;_done=!1;async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{const t=await e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}running(){return null!==this.promise&&!this._done}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){this._done=!1,this.promise=null,this._value=null,this._error=void 0}resolved(){return this.promise}done(){return this._done}_awaitWithTimeout(e,t,r="Operation timed out"){return null==t?e:Promise.race([e,new Promise(((e,s)=>setTimeout((()=>s(new p(r))),t)))])}},v=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;constructor(e){this.mutex=new m({capacity:e?.capacity??1e3})}async do(e,t){if(this._done)return{value:null,error:new f};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new f;s=await e(),this._lastValue=s,this._lastError=void 0}catch(e){r=e,this._lastError=e}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},b=class{constructor(e,t,r,s,n){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=n}async build(e,t){const r=this.registry.get(e);if(!r)throw new d(`Template not found for artifact "${String(e)}"`,"system");const s=t?new Set(t):new Set;if(s.has(e))throw new d(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(s).join(" -> ")}`,"system");s.add(e);let n=this.cache.get(e);n||(n=this.createCachedArtifact(r),this.cache.set(e,n));const i=await("transient"===r.scope?this.executeBuild(r,n,s):n.buildOnce.do((()=>this.executeBuild(r,n,s))));if("transient"===r.scope)return i;const a=this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));return n.stream&&n.streamOnce.do(n.stream),a}async executeBuild(e,t,r){const s=e.key;t.buildCount++;const n=[],i=[];let a=!0;t.activeDebounceMs=e.debounce??0,n.push((()=>{a=!1}));const o=new Set,c=new Set,h=new Map,l={state:()=>this.store.get(!0),previous:t.instance,onCleanup:e=>n.push(e),onDispose:e=>i.push(e),use:async e=>e({resolve:async e=>{if(e===s)throw new d(`Artifact "${String(s)}" depends on itself.`,"system");const t=this.graph.wouldCreateCycle(s,e,r);if(t)throw new d(`Adding dependency "${String(e)}" to "${String(s)}" would create a cycle: ${t.join(" -> ")}`,"system");c.add(e);const n=await this.build(e,r),i=this.cache.get(e);return i&&h.set(e,i.version),n},select:e=>(function(e,t="."){const r=new Set,s=(e=[])=>new Proxy({},{get:(n,i)=>{if("symbol"==typeof i)return;const a=[...e,i],o=a.join(t);return r.add(o),s(a)}});try{e(s())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}const n=Array.from(r);return n.filter((e=>!n.some((r=>r!==e&&r.startsWith(e+t)))))}(e).forEach((e=>o.add(e))),e(this.store.get(!0)))}),stream:async r=>{if("transient"===e.scope)throw new d(`[ArtifactManager] Illegal stream on transient artifact "${String(s)}"`,"system");const n=async(e,r=void 0)=>{await t.streamSerializer.do((async()=>{void 0!==t.stream&&(t.instance=e,t.error=r,t.version++,this.cache.invalidatePackage(s),await this.processStream(s))}))},i={value:()=>t.instance,signal:t.streamController.signal,set:(...e)=>this.store.set(...e),emit:e=>n(e)};t.stream=async()=>{try{await r(i)}catch(e){await n(void 0,e),this.invalidate(s,!1,!0)}}}};let u,p,g=0;const f=(e.retries??0)+1;for(;g<f;)try{const t=e.factory(l);if(e.timeout){const r=new Promise(((t,r)=>setTimeout((()=>r(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)));u=await Promise.race([t,r])}else u=await t;break}catch(e){if(e instanceof d)throw e;g++,g>=f&&(p=e)}if(a){for(const[e,t]of h){const r=this.cache.get(e);r&&r.version!==t&&(p=new d(`Build stale on arrival: Dependency "${String(e)}" changed during build.`,"system"))}if("singleton"===e.scope&&this.updateDependencyGraph(s,c,o),"singleton"===e.scope&&(t.cleanupFunctions=n,t.disposeFunctions=i),p?t.error=p:t.instance=u,t.version++,this.cache.invalidatePackage(s),"transient"===e.scope)return{instance:u,cleanup:this.createCompositeCleanup(n),error:p,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(s)}"`)}}else{const e=this.createCompositeCleanup(n);e&&await e()}}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise((n=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(n).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&(await s.invalidationOnce.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.getDependents(e);await Promise.all(n.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const i=this.registry.get(e);!i||!t&&i.lazy&&!this.hasWatchers(e)||r||await this.build(e),this.observer.notify(e)})),s.invalidationOnce.reset())}async dispose(e){const t=this.cache.get(e);t&&(t.streamController.abort(),t.buildOnce.running()&&await t.buildOnce.resolved(),t.invalidationOnce.running()&&await t.invalidationOnce.resolved(),t.streamOnce.running()&&await t.streamOnce.resolved(),await this.cache.invalidateInstance(e),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.getDependents(e);await Promise.all(t.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&s.stateUnsubscribe(),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){return{instance:void 0,version:0,streamController:new AbortController,error:void 0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,buildOnce:new w(!0,!0),streamOnce:new w(!0,!0),streamSerializer:new v,activeDebounceMs:e.debounce??0,invalidationOnce:new w(!0,!1)}}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},C=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),n=new Map;for(;r.length>0;){const i=r.shift();if(i===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=n.get(s);return r.reverse(),[e,...r]}const a=this.dependencies.get(i);if(a)for(const e of a)s.has(e)||(s.add(e),n.set(e,i),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const n=this.dependents.get(t);if(n)for(const t of n){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,n=new Set,i=[e];n.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;i.length>0;){const e=i.shift(),t=a.get(e);if(t)for(const e of t)n.has(e)||(n.add(e),s.add(e),i.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},A=class{graph;constructor(){this.graph=new C}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),n=e.slice(s);return n.push(t),n}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},_=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return{instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:t};if(r.packagedArtifact)return this.updatePackagedArtifact(r,r.packagedArtifact,t),r.packagedArtifact;const s={instance:r.instance,error:r.error,ready:r.buildOnce.done()&&!r.buildOnce.running(),cleanup:this.createCompositeCleanup(r.cleanupFunctions),invalidate:t};return r.packagedArtifact=s,s}async invalidatePackage(e){const t=this.get(e);t&&(t.packagedArtifact=void 0)}async invalidateInstance(e){const t=this.get(e);if(t){t.stateUnsubscribe&&(t.stateUnsubscribe(),t.stateUnsubscribe=void 0),t.debounceTimer&&(clearTimeout(t.debounceTimer),t.debounceTimer=void 0),t.streamController.abort(),await t.streamOnce.resolved(),t.streamOnce.reset(),t.streamSerializer.close();for(let e=t.cleanupFunctions.length-1;e>=0;e--)try{await t.cleanupFunctions[e]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}for(let e=t.disposeFunctions.length-1;e>=0;e--)try{await t.disposeFunctions[e]()}catch(e){console.error("[ArtifactManager] Dispose error:",e)}t.instance=void 0,t.error=void 0,t.cleanupFunctions=[],t.disposeFunctions=[],t.buildOnce.reset(),t.stream=void 0,t.streamSerializer=new v,t.streamController=new AbortController}}updatePackagedArtifact(e,t,r){t.instance=e.instance,t.error=e.error,t.ready=e.buildOnce.done()&&!e.buildOnce.running(),t.cleanup=this.createCompositeCleanup(e.cleanupFunctions),t.invalidate=r}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactCache] Cleanup error:",e)}}}},k=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);let s=t;if("transient"===r.scope&&(s=`${t}__watched`,this.registry.has(s)||this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})),this.watcherCache.has(s)){const e=this.watcherCache.get(s);return e.count++,e}let n=!1;const i={id:t,count:1,get:()=>{if(!this.cache.get(s))return this.cache.package(s,(e=>this.container.invalidate(s,e)));const e=this.cache.package(s,(e=>this.container.invalidate(s,e)));return n?{...e,ready:!1,instance:void 0,error:new u(t),cleanup:()=>{},invalidate:()=>Promise.resolve()}:e},subscribe:e=>{this.listeners.has(s)||this.listeners.set(s,new Set);const t=()=>e(i.get());return this.listeners.get(s).add(t),this.container.resolve(s).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e)})).then(t),()=>this.listeners.get(s)?.delete(t)},dispose:async()=>{i.count--,i.count<=0&&(this.watcherCache.delete(s),"transient"===r.scope&&(await this.registry.unregister(s),this.cache.delete(s)),n=!0,this.notify(s),this.listeners.delete(s))}};return this.watcherCache.set(s,i),i}notify(e){const t=this.listeners.get(e);t&&t.forEach((t=>{try{t()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}))}hasWatchers(e){return this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}};exports.ArtifactContainer=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new y,this.cache=new _,this.graph=new A,this.observer=new k(this.registry,this.cache,this),this.manager=new b(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;const n=s?s.buildOnce.running()?"pending":s.error?"error":void 0!==s.instance?"active":"idle":"idle";e.push({id:t,scope:r.scope??"singleton",status:n,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],renderCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new l(e);return this.manager.build(e)}watch(e){if(!this.registry.has(e))throw new l(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}dispose(){this.registry.keys().forEach((e=>{this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))})),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}},exports.ArtifactScopes=h;
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e,t,r=Object.create,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,c=(e={"src/store/node_modules/@asaidimu/events/index.js"(e,t){var r,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(o,{createEventBus:()=>c}),t.exports=(r=o,((e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))a.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(o=n(t,c))||o.enumerable});return e})(s({},"__esModule",{value:!0}),r));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let r=[],s=0,n=0;const i=new Map,a=new Map;let o=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?o=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{s++,n+=t,i.set(e,(i.get(e)||0)+1)},h=()=>{const t=r;r=[],t.forEach((({name:t,payload:r})=>{const s=performance.now();try{(a.get(t)||[]).forEach((e=>e(r)))}catch(s){e.errorHandler({...s,eventName:t,payload:r})}c(t,performance.now()-s)}))},d=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(h,e.batchDelay)}})(),l=e=>{const r=t.get(e);r?a.set(e,Array.from(r)):a.delete(e)};return o&&(o.onmessage=e=>{const{name:t,payload:r}=e.data;(a.get(t)||[]).forEach((e=>e(r)))}),{subscribe:(e,r)=>{t.has(e)||t.set(e,new Set);const s=t.get(e);return s.add(r),l(e),()=>{s.delete(r),0===s.size?(t.delete(e),a.delete(e)):l(e)}},emit:({name:t,payload:s})=>{if(e.async)return r.push({name:t,payload:s}),r.length>=e.batchSize?h():d(),void(o&&o.postMessage({name:t,payload:s}));const n=performance.now();try{(a.get(t)||[]).forEach((e=>e(s))),o&&o.postMessage({name:t,payload:s})}catch(r){e.errorHandler({...r,eventName:t,payload:s})}c(t,performance.now()-n)},getMetrics:()=>({totalEvents:s,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:i,averageEmitDuration:s>0?n/s:0}),clear:()=>{t.clear(),a.clear(),r=[],s=0,n=0,i.clear(),o&&(o.close(),o=null)}}}}},function(){return t||(0,e[i(e)[0]])((t={exports:{}}).exports,t),t.exports}),h=(e=>(e.Singleton="singleton",e.Transient="transient",e))(h||{}),d=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},l=class extends d{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system")}},u=class extends d{constructor(e){super(`[ArtifactContainer] Artifact with key:${e} has already been disposed`,"system")}},p=class extends d{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`,"system")}},g=class extends d{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system")}},f=class extends d{constructor(){super("[Serializer] The serializer has been marked as done!","system")}},y=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...s}){if(this.artifacts.has(e))throw new g(String(e));const{scope:n,...i}=s,a={key:e,factory:t,scope:s.scope??"singleton",lazy:void 0===r||r,...i};return this.artifacts.set(e,a),()=>this.unregister(e)}get(e){if(!this.has(e))throw new l(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}};((e,t,c)=>{c=null!=e?r(a(e)):{},((e,t,r,a)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))o.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(a=n(t,c))||a.enumerable})})(e&&e.__esModule?c:s(c,"default",{value:e,enumerable:!0}),e)})(c());var m=class{_locked=!1;_capacity;waiters=[];constructor(e){this._capacity=e?.capacity??1/0}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null!=e)try{await Promise.race([r,new Promise(((r,s)=>setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),s(new p("Mutex lock timed out"))}),e)))])}catch(e){throw e}else await r}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},w=class{constructor(e=!1,t=!1){this.retry=e,this.throws=t}mutex=new m;promise=null;_value=null;_error;_done=!1;async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{const t=await e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}running(){return null!==this.promise&&!this._done}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){this._done=!1,this.promise=null,this._value=null,this._error=void 0}resolved(){return this.promise}done(){return this._done}_awaitWithTimeout(e,t,r="Operation timed out"){return null==t?e:Promise.race([e,new Promise(((e,s)=>setTimeout((()=>s(new p(r))),t)))])}},v=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;constructor(e){this.mutex=new m({capacity:e?.capacity??1e3})}async do(e,t){if(this._done)return{value:null,error:new f};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new f;s=await e(),this._lastValue=s,this._lastError=void 0}catch(e){r=e,this._lastError=e}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},b=class{constructor(e,t,r,s,n){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=n}async build(e,t){const r=this.registry.get(e);if(!r)throw new d(`Template not found for artifact "${String(e)}"`,"system");const s=t?new Set(t):new Set;if(s.has(e))throw new d(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(s).join(" -> ")}`,"system");s.add(e);let n=this.cache.get(e);n||(n=this.createCachedArtifact(r),this.cache.set(e,n));const i=await("transient"===r.scope?this.executeBuild(r,n,s):n.buildOnce.do((()=>this.executeBuild(r,n,s))));if("transient"===r.scope)return i;const a=this.cache.package(e,(t=>this.invalidate(e,t)));return n.stream&&n.streamOnce.do(n.stream),a}async executeBuild(e,t,r){const s=e.key;t.buildCount++;const n=[],i=[];let a=!0;t.activeDebounceMs=e.debounce??0,n.push((()=>{a=!1}));const o=new Set,c=new Set,h=new Map,l={state:()=>this.store.get(!0),previous:t.instance,onCleanup:e=>n.push(e),onDispose:e=>i.push(e),use:async e=>e({resolve:async e=>{if(e===s)throw new d(`Artifact "${String(s)}" depends on itself.`,"system");const t=this.graph.wouldCreateCycle(s,e,r);if(t)throw new d(`Adding dependency "${String(e)}" to "${String(s)}" would create a cycle: ${t.join(" -> ")}`,"system");c.add(e);const n=await this.build(e,r),i=this.cache.get(e);return i&&h.set(e,i.version),n},select:e=>(function(e,t="."){const r=new Set,s=(e=[])=>new Proxy({},{get:(n,i)=>{if("symbol"==typeof i)return;const a=[...e,i],o=a.join(t);return r.add(o),s(a)}});try{e(s())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}const n=Array.from(r);return n.filter((e=>!n.some((r=>r!==e&&r.startsWith(e+t)))))}(e).forEach((e=>o.add(e))),e(this.store.get(!0)))}),stream:async r=>{if("transient"===e.scope)throw new d(`[ArtifactManager] Illegal stream on transient artifact "${String(s)}"`,"system");const n=async(e,r=void 0)=>{await t.streamSerializer.do((async()=>{void 0!==t.stream&&(t.instance=e,t.error=r,t.version++,this.cache.invalidatePackage(s),await this.processStream(s))}))},i={value:()=>t.instance,signal:t.streamController.signal,set:(...e)=>this.store.set(...e),emit:e=>n(e)};t.stream=async()=>{try{await r(i)}catch(e){await n(void 0,e),this.invalidate(s,!1,!0)}}}};let u,p,g=0;const f=(e.retries??0)+1;for(;g<f;)try{const t=e.factory(l);if(e.timeout){const r=new Promise(((t,r)=>setTimeout((()=>r(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)));u=await Promise.race([t,r])}else u=await t;break}catch(e){if(e instanceof d)throw e;g++,g>=f&&(p=e)}if(a){for(const[e,t]of h){const r=this.cache.get(e);r&&r.version!==t&&(p=new d(`Build stale on arrival: Dependency "${String(e)}" changed during build.`,"system"))}if("singleton"===e.scope&&this.updateDependencyGraph(s,c,o),"singleton"===e.scope&&(t.cleanupFunctions=n,t.disposeFunctions=i),p?t.error=p:t.instance=u,t.version++,this.cache.invalidatePackage(s),"transient"===e.scope)return{instance:u,cleanup:this.createCompositeCleanup(n),error:p,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(s)}"`)}}else{const e=this.createCompositeCleanup(n);e&&await e()}}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise((n=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(n).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&(await s.invalidationOnce.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.getDependents(e);await Promise.all(n.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const i=this.registry.get(e);!i||!t&&i.lazy&&!this.hasWatchers(e)||r||await this.build(e),this.observer.notify(e)})),s.invalidationOnce.reset())}async dispose(e){const t=this.cache.get(e);t&&(t.streamController.abort(),t.buildOnce.running()&&await t.buildOnce.resolved(),t.invalidationOnce.running()&&await t.invalidationOnce.resolved(),t.streamOnce.running()&&await t.streamOnce.resolved(),await this.cache.invalidateInstance(e),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.getDependents(e);await Promise.all(t.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&s.stateUnsubscribe(),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){return{instance:void 0,version:0,streamController:new AbortController,error:void 0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,buildOnce:new w(!0,!0),streamOnce:new w(!0,!0),streamSerializer:new v,activeDebounceMs:e.debounce??0,invalidationOnce:new w(!0,!1)}}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},C=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),n=new Map;for(;r.length>0;){const i=r.shift();if(i===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=n.get(s);return r.reverse(),[e,...r]}const a=this.dependencies.get(i);if(a)for(const e of a)s.has(e)||(s.add(e),n.set(e,i),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const n=this.dependents.get(t);if(n)for(const t of n){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,n=new Set,i=[e];n.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;i.length>0;){const e=i.shift(),t=a.get(e);if(t)for(const e of t)n.has(e)||(n.add(e),s.add(e),i.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},A=class{graph;constructor(){this.graph=new C}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),n=e.slice(s);return n.push(t),n}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},_=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return{instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:t};if(r.packagedArtifact)return this.updatePackagedArtifact(r,r.packagedArtifact,t),r.packagedArtifact;const s={instance:r.instance,error:r.error,ready:r.buildOnce.done()&&!r.buildOnce.running(),cleanup:this.createCompositeCleanup(r.cleanupFunctions),invalidate:t};return r.packagedArtifact=s,s}async invalidatePackage(e){const t=this.get(e);t&&(t.packagedArtifact=void 0)}async invalidateInstance(e){const t=this.get(e);if(t){t.stateUnsubscribe&&(t.stateUnsubscribe(),t.stateUnsubscribe=void 0),t.debounceTimer&&(clearTimeout(t.debounceTimer),t.debounceTimer=void 0),t.streamController.abort(),await t.streamOnce.resolved(),t.streamOnce.reset(),t.streamSerializer.close();for(let e=t.cleanupFunctions.length-1;e>=0;e--)try{await t.cleanupFunctions[e]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}for(let e=t.disposeFunctions.length-1;e>=0;e--)try{await t.disposeFunctions[e]()}catch(e){console.error("[ArtifactManager] Dispose error:",e)}t.instance=void 0,t.error=void 0,t.cleanupFunctions=[],t.disposeFunctions=[],t.buildOnce.reset(),t.stream=void 0,t.streamSerializer=new v,t.streamController=new AbortController}}updatePackagedArtifact(e,t,r){t.instance=e.instance,t.error=e.error,t.ready=e.buildOnce.done()&&!e.buildOnce.running(),t.cleanup=this.createCompositeCleanup(e.cleanupFunctions),t.invalidate=r}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactCache] Cleanup error:",e)}}}},k=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);let s=t;if("transient"===r.scope&&(s=`${t}__watched`,this.registry.has(s)||this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})),this.watcherCache.has(s)){const e=this.watcherCache.get(s);return e.count++,e}let n=!1;const i={id:t,count:1,get:()=>{if(!this.cache.get(s))return this.cache.package(s,(e=>this.container.invalidate(s,e)));const e=this.cache.package(s,(e=>this.container.invalidate(s,e)));return n?{...e,ready:!1,instance:void 0,error:new u(t),cleanup:()=>{},invalidate:()=>Promise.resolve()}:e},subscribe:e=>{this.listeners.has(s)||this.listeners.set(s,new Set);const t=()=>e(i.get());return this.listeners.get(s).add(t),this.container.resolve(s).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e)})).then(t),()=>this.listeners.get(s)?.delete(t)},dispose:async()=>{i.count--,i.count<=0&&(this.watcherCache.delete(s),"transient"===r.scope&&(await this.registry.unregister(s),this.cache.delete(s)),n=!0,this.notify(s),this.listeners.delete(s))}};return this.watcherCache.set(s,i),i}notify(e){const t=this.listeners.get(e);t&&t.forEach((t=>{try{t()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}))}hasWatchers(e){return this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}},S=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new y,this.cache=new _,this.graph=new A,this.observer=new k(this.registry,this.cache,this),this.manager=new b(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;const n=s?s.buildOnce.running()?"pending":s.error?"error":void 0!==s.instance?"active":"idle":"idle";e.push({id:t,scope:r.scope??"singleton",status:n,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],renderCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new l(e);return this.manager.build(e)}watch(e){if(!this.registry.has(e))throw new l(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}dispose(){this.registry.keys().forEach((e=>{this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))})),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}};export{S as ArtifactContainer,h as ArtifactScopes};
|
|
1
|
+
var e,t,r=Object.create,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,c=(e={"src/store/node_modules/@asaidimu/events/index.js"(e,t){var r,s=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(o,{createEventBus:()=>c}),t.exports=(r=o,((e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))a.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(o=n(t,c))||o.enumerable});return e})(s({},"__esModule",{value:!0}),r));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let r=[],s=0,n=0;const i=new Map,a=new Map;let o=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?o=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{s++,n+=t,i.set(e,(i.get(e)||0)+1)},h=()=>{const t=r;r=[],t.forEach((({name:t,payload:r})=>{const s=performance.now();try{(a.get(t)||[]).forEach((e=>e(r)))}catch(s){e.errorHandler({...s,eventName:t,payload:r})}c(t,performance.now()-s)}))},d=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(h,e.batchDelay)}})(),l=e=>{const r=t.get(e);r?a.set(e,Array.from(r)):a.delete(e)};return o&&(o.onmessage=e=>{const{name:t,payload:r}=e.data;(a.get(t)||[]).forEach((e=>e(r)))}),{subscribe:(e,r)=>{t.has(e)||t.set(e,new Set);const s=t.get(e);return s.add(r),l(e),()=>{s.delete(r),0===s.size?(t.delete(e),a.delete(e)):l(e)}},emit:({name:t,payload:s})=>{if(e.async)return r.push({name:t,payload:s}),r.length>=e.batchSize?h():d(),void(o&&o.postMessage({name:t,payload:s}));const n=performance.now();try{(a.get(t)||[]).forEach((e=>e(s))),o&&o.postMessage({name:t,payload:s})}catch(r){e.errorHandler({...r,eventName:t,payload:s})}c(t,performance.now()-n)},getMetrics:()=>({totalEvents:s,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:i,averageEmitDuration:s>0?n/s:0}),clear:()=>{t.clear(),a.clear(),r=[],s=0,n=0,i.clear(),o&&(o.close(),o=null)}}}}},function(){return t||(0,e[i(e)[0]])((t={exports:{}}).exports,t),t.exports}),h=(e=>(e.Singleton="singleton",e.Transient="transient",e))(h||{}),d=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},l=class extends d{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system")}},u=class extends d{constructor(e){super(`[ArtifactContainer] Artifact with key:${e} has already been disposed`,"system")}},p=class extends d{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`,"system")}},g=class extends d{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system")}},f=class extends d{constructor(){super("[Serializer] The serializer has been marked as done!","system")}},y=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...s}){if(this.artifacts.has(e))throw new g(String(e));const{scope:n,...i}=s,a={key:e,factory:t,scope:s.scope??"singleton",lazy:void 0===r||r,...i};return this.artifacts.set(e,a),()=>this.unregister(e)}get(e){if(!this.has(e))throw new l(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}};((e,t,c)=>{c=null!=e?r(a(e)):{},((e,t,r,a)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))o.call(e,c)||c===r||s(e,c,{get:()=>t[c],enumerable:!(a=n(t,c))||a.enumerable})})(e&&e.__esModule?c:s(c,"default",{value:e,enumerable:!0}),e)})(c());var m=class{_locked=!1;_capacity;waiters=[];constructor(e){this._capacity=e?.capacity??1/0}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null!=e)try{await Promise.race([r,new Promise(((r,s)=>setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),s(new p("Mutex lock timed out"))}),e)))])}catch(e){throw e}else await r}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},w=class{constructor(e=!1,t=!1){this.retry=e,this.throws=t}mutex=new m;promise=null;_value=null;_error;_done=!1;async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{const t=await e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}running(){return null!==this.promise&&!this._done}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){this._done=!1,this.promise=null,this._value=null,this._error=void 0}resolved(){return this.promise}done(){return this._done}_awaitWithTimeout(e,t,r="Operation timed out"){return null==t?e:Promise.race([e,new Promise(((e,s)=>setTimeout((()=>s(new p(r))),t)))])}},v=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;constructor(e){this.mutex=new m({capacity:e?.capacity??1e3})}async do(e,t){if(this._done)return{value:null,error:new f};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new f;s=await e(),this._lastValue=s,this._lastError=void 0}catch(e){r=e,this._lastError=e}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},b=class{constructor(e,t,r,s,n){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=n}async build(e,t){const r=this.registry.get(e);if(!r)throw new d(`Template not found for artifact "${String(e)}"`,"system");const s=t?new Set(t):new Set;if(s.has(e))throw new d(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(s).join(" -> ")}`,"system");s.add(e);let n=this.cache.get(e);n||(n=this.createCachedArtifact(r),this.cache.set(e,n));const i=await("transient"===r.scope?this.executeBuild(r,n,s):n.buildOnce.do((()=>this.executeBuild(r,n,s))));if("transient"===r.scope)return i;const a=this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));return n.stream&&n.streamOnce.do(n.stream),a}async executeBuild(e,t,r){const s=e.key;t.buildCount++;const n=[],i=[];let a=!0;t.activeDebounceMs=e.debounce??0,n.push((()=>{a=!1}));const o=new Set,c=new Set,h=new Map,l={state:()=>this.store.get(!0),previous:t.instance,onCleanup:e=>n.push(e),onDispose:e=>i.push(e),use:async e=>e({resolve:async e=>{if(e===s)throw new d(`Artifact "${String(s)}" depends on itself.`,"system");const t=this.graph.wouldCreateCycle(s,e,r);if(t)throw new d(`Adding dependency "${String(e)}" to "${String(s)}" would create a cycle: ${t.join(" -> ")}`,"system");c.add(e);const n=await this.build(e,r),i=this.cache.get(e);return i&&h.set(e,i.version),n},select:e=>(function(e,t="."){const r=new Set,s=(e=[])=>new Proxy({},{get:(n,i)=>{if("symbol"==typeof i)return;const a=[...e,i],o=a.join(t);return r.add(o),s(a)}});try{e(s())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}const n=Array.from(r);return n.filter((e=>!n.some((r=>r!==e&&r.startsWith(e+t)))))}(e).forEach((e=>o.add(e))),e(this.store.get(!0)))}),stream:async r=>{if("transient"===e.scope)throw new d(`[ArtifactManager] Illegal stream on transient artifact "${String(s)}"`,"system");const n=async(e,r=void 0)=>{await t.streamSerializer.do((async()=>{void 0!==t.stream&&(t.instance=e,t.error=r,t.version++,this.cache.invalidatePackage(s),await this.processStream(s))}))},i={value:()=>t.instance,signal:t.streamController.signal,set:(...e)=>this.store.set(...e),emit:e=>n(e)};t.stream=async()=>{try{await r(i)}catch(e){await n(void 0,e),this.invalidate(s,!1,!0)}}}};let u,p,g=0;const f=(e.retries??0)+1;for(;g<f;)try{const t=e.factory(l);if(e.timeout){const r=new Promise(((t,r)=>setTimeout((()=>r(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)));u=await Promise.race([t,r])}else u=await t;break}catch(e){if(e instanceof d)throw e;g++,g>=f&&(p=e)}if(a){for(const[e,t]of h){const r=this.cache.get(e);r&&r.version!==t&&(p=new d(`Build stale on arrival: Dependency "${String(e)}" changed during build.`,"system"))}if("singleton"===e.scope&&this.updateDependencyGraph(s,c,o),"singleton"===e.scope&&(t.cleanupFunctions=n,t.disposeFunctions=i),p?t.error=p:t.instance=u,t.version++,this.cache.invalidatePackage(s),"transient"===e.scope)return{instance:u,cleanup:this.createCompositeCleanup(n),error:p,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(s)}"`)}}else{const e=this.createCompositeCleanup(n);e&&await e()}}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise((n=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(n).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&(await s.invalidationOnce.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.getDependents(e);await Promise.all(n.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const i=this.registry.get(e);!i||!t&&i.lazy&&!this.hasWatchers(e)||r||await this.build(e),this.observer.notify(e)})),s.invalidationOnce.reset())}async dispose(e){const t=this.cache.get(e);t&&(t.streamController.abort(),t.buildOnce.running()&&await t.buildOnce.resolved(),t.invalidationOnce.running()&&await t.invalidationOnce.resolved(),t.streamOnce.running()&&await t.streamOnce.resolved(),await this.cache.invalidateInstance(e),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.getDependents(e);await Promise.all(t.map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&s.stateUnsubscribe(),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){return{instance:void 0,version:0,streamController:new AbortController,error:void 0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,buildOnce:new w(!0,!0),streamOnce:new w(!0,!0),streamSerializer:new v,activeDebounceMs:e.debounce??0,invalidationOnce:new w(!0,!1)}}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},C=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),n=new Map;for(;r.length>0;){const i=r.shift();if(i===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=n.get(s);return r.reverse(),[e,...r]}const a=this.dependencies.get(i);if(a)for(const e of a)s.has(e)||(s.add(e),n.set(e,i),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const n=this.dependents.get(t);if(n)for(const t of n){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,n=new Set,i=[e];n.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;i.length>0;){const e=i.shift(),t=a.get(e);if(t)for(const e of t)n.has(e)||(n.add(e),s.add(e),i.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},A=class{graph;constructor(){this.graph=new C}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),n=e.slice(s);return n.push(t),n}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},_=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return{instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:t};if(r.packagedArtifact)return this.updatePackagedArtifact(r,r.packagedArtifact,t),r.packagedArtifact;const s={instance:r.instance,error:r.error,ready:r.buildOnce.done()&&!r.buildOnce.running(),cleanup:this.createCompositeCleanup(r.cleanupFunctions),invalidate:t};return r.packagedArtifact=s,s}async invalidatePackage(e){const t=this.get(e);t&&(t.packagedArtifact=void 0)}async invalidateInstance(e){const t=this.get(e);if(t){t.stateUnsubscribe&&(t.stateUnsubscribe(),t.stateUnsubscribe=void 0),t.debounceTimer&&(clearTimeout(t.debounceTimer),t.debounceTimer=void 0),t.streamController.abort(),await t.streamOnce.resolved(),t.streamOnce.reset(),t.streamSerializer.close();for(let e=t.cleanupFunctions.length-1;e>=0;e--)try{await t.cleanupFunctions[e]()}catch(e){console.error("[ArtifactManager] Cleanup error:",e)}for(let e=t.disposeFunctions.length-1;e>=0;e--)try{await t.disposeFunctions[e]()}catch(e){console.error("[ArtifactManager] Dispose error:",e)}t.instance=void 0,t.error=void 0,t.cleanupFunctions=[],t.disposeFunctions=[],t.buildOnce.reset(),t.stream=void 0,t.streamSerializer=new v,t.streamController=new AbortController}}updatePackagedArtifact(e,t,r){t.instance=e.instance,t.error=e.error,t.ready=e.buildOnce.done()&&!e.buildOnce.running(),t.cleanup=this.createCompositeCleanup(e.cleanupFunctions),t.invalidate=r}createCompositeCleanup(e){if(e.length)return async()=>{for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error("[ArtifactCache] Cleanup error:",e)}}}},k=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);let s=t;if("transient"===r.scope&&(s=`${t}__watched`,this.registry.has(s)||this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})),this.watcherCache.has(s)){const e=this.watcherCache.get(s);return e.count++,e}let n=!1;const i={id:t,count:1,get:()=>{if(!this.cache.get(s))return this.cache.package(s,(e=>this.container.invalidate(s,e)));const e=this.cache.package(s,(e=>this.container.invalidate(s,e)));return n?{...e,ready:!1,instance:void 0,error:new u(t),cleanup:()=>{},invalidate:()=>Promise.resolve()}:e},subscribe:e=>{this.listeners.has(s)||this.listeners.set(s,new Set);const t=()=>e(i.get());return this.listeners.get(s).add(t),this.container.resolve(s).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e)})).then(t),()=>this.listeners.get(s)?.delete(t)},dispose:async()=>{i.count--,i.count<=0&&(this.watcherCache.delete(s),"transient"===r.scope&&(await this.registry.unregister(s),this.cache.delete(s)),n=!0,this.notify(s),this.listeners.delete(s))}};return this.watcherCache.set(s,i),i}notify(e){const t=this.listeners.get(e);t&&t.forEach((t=>{try{t()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}))}hasWatchers(e){return this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}},S=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new y,this.cache=new _,this.graph=new A,this.observer=new k(this.registry,this.cache,this),this.manager=new b(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;const n=s?s.buildOnce.running()?"pending":s.error?"error":void 0!==s.instance?"active":"idle":"idle";e.push({id:t,scope:r.scope??"singleton",status:n,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],renderCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new l(e);return this.manager.build(e)}watch(e){if(!this.registry.has(e))throw new l(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}dispose(){this.registry.keys().forEach((e=>{this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))})),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}};export{S as ArtifactContainer,h as ArtifactScopes};
|