@asaidimu/utils-pipeline 1.0.3 → 1.0.5
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 +297 -2
- package/index.d.ts +297 -2
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +1 -1
package/index.d.mts
CHANGED
|
@@ -414,7 +414,7 @@ declare class Pipeline {
|
|
|
414
414
|
/**
|
|
415
415
|
* Utility type for representing partial updates to the state, allowing deep nesting.
|
|
416
416
|
* It makes all properties optional and applies the same transformation recursively
|
|
417
|
-
* to nested objects
|
|
417
|
+
* to nested objects, allowing for selective updates while
|
|
418
418
|
* preserving the original structure. It also includes the original type T and
|
|
419
419
|
* undefined as possibilities for the top level and nested values.
|
|
420
420
|
*/
|
|
@@ -1242,6 +1242,8 @@ interface PipelineCheckpoint {
|
|
|
1242
1242
|
}
|
|
1243
1243
|
/** Factory-internal namespace for all checkpoint data. */
|
|
1244
1244
|
declare const PIPELINE_DATA_KEY: "__pipeline_data__";
|
|
1245
|
+
/** Factory-internal namespace for run id */
|
|
1246
|
+
declare const PIPELINE_RUN_ID_KEY: "__pipeline_id__";
|
|
1245
1247
|
/**
|
|
1246
1248
|
* Run-scoped context injected into every step action as a second argument.
|
|
1247
1249
|
*
|
|
@@ -1553,6 +1555,7 @@ interface RunContext<S extends object> {
|
|
|
1553
1555
|
interface EngineLogger {
|
|
1554
1556
|
info: (msg: string, ctx?: any) => void;
|
|
1555
1557
|
error: (msg: string, ctx?: any) => void;
|
|
1558
|
+
warn: (msg: string, ctx?: any) => void;
|
|
1556
1559
|
}
|
|
1557
1560
|
/**
|
|
1558
1561
|
* Configuration for {@link PipelineFactory}.
|
|
@@ -1594,6 +1597,7 @@ interface PipelineFactoryOptions<S extends object = State> {
|
|
|
1594
1597
|
* the factory remains decoupled from the registry's full surface.
|
|
1595
1598
|
*/
|
|
1596
1599
|
interface PipelineRegistryBinding<S extends object> {
|
|
1600
|
+
has(id: string): boolean;
|
|
1597
1601
|
register(context: RunContext<S>, store: DataStore<S>): void;
|
|
1598
1602
|
/**
|
|
1599
1603
|
* Called by resume() before constructing a new RunContext.
|
|
@@ -1602,6 +1606,8 @@ interface PipelineRegistryBinding<S extends object> {
|
|
|
1602
1606
|
* Returns null if no live context exists and reconstruction is needed.
|
|
1603
1607
|
*/
|
|
1604
1608
|
getLiveContext(runId: string): RunContext<S> | null;
|
|
1609
|
+
/** Returns the checkpoint for a paused run, if available. */
|
|
1610
|
+
getCheckpoint(runId: string): PipelineCheckpoint | null;
|
|
1605
1611
|
}
|
|
1606
1612
|
/**
|
|
1607
1613
|
* A pure factory for creating and resuming pipeline runs.
|
|
@@ -1729,4 +1735,293 @@ declare function readCheckpoint(store: DataStore<any>, pipelineId: string | unde
|
|
|
1729
1735
|
*/
|
|
1730
1736
|
declare function clearCheckpoint(store: DataStore<any>, pipelineId: string, runId: string): Promise<void>;
|
|
1731
1737
|
|
|
1732
|
-
|
|
1738
|
+
/**
|
|
1739
|
+
* @file pipeline-registry.ts
|
|
1740
|
+
* @description Stateful coordination layer for pipeline runs.
|
|
1741
|
+
*
|
|
1742
|
+
* The registry is the single source of truth for live run state. It owns:
|
|
1743
|
+
*
|
|
1744
|
+
* 1. Strong references to RunContext instances — it decides when a context
|
|
1745
|
+
* becomes GC-eligible by nulling the reference inside its RunRecord.
|
|
1746
|
+
*
|
|
1747
|
+
* 2. Pause timers — armed when a pipeline pauses, cancelled when resume()
|
|
1748
|
+
* is called before expiry.
|
|
1749
|
+
*
|
|
1750
|
+
* 3. Deferred container export — on timer expiry the registry exports the
|
|
1751
|
+
* ArtifactContainer and writes the bundle into the persisted checkpoint
|
|
1752
|
+
* via writeCheckpoint(), then nulls the context reference.
|
|
1753
|
+
*
|
|
1754
|
+
* 4. A WeakRef index — allows external observers to list and watch runs
|
|
1755
|
+
* without the registry preventing GC of completed or expired records.
|
|
1756
|
+
*
|
|
1757
|
+
* 5. A FinalizationRegistry — passively removes stale WeakRef entries from
|
|
1758
|
+
* the index after GC collects a context nobody else held.
|
|
1759
|
+
*
|
|
1760
|
+
* GC eligibility rules:
|
|
1761
|
+
* - Completed runs (succeeded / failed): the registry nulls the strong ref
|
|
1762
|
+
* immediately on the terminal event. If no external caller holds a reference
|
|
1763
|
+
* the context is GC-eligible right away.
|
|
1764
|
+
* - Paused runs: the registry holds the strong ref for `pauseTimeout` ms
|
|
1765
|
+
* (from the PauseInstruction, or the registry default). During that window
|
|
1766
|
+
* resume() returns the live context directly — zero reconstruction cost.
|
|
1767
|
+
* When the timer fires the registry exports, updates the checkpoint, nulls
|
|
1768
|
+
* the ref, and fires onExpired.
|
|
1769
|
+
*
|
|
1770
|
+
* Named instances:
|
|
1771
|
+
* PipelineRegistry.default — module-level singleton, importable from anywhere.
|
|
1772
|
+
* PipelineRegistry.get(name) — named registries for test isolation or domain
|
|
1773
|
+
* separation within the same process.
|
|
1774
|
+
*/
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
* The status of a run as tracked by the registry.
|
|
1778
|
+
* Mirrors PipelineRunResult["status"] but adds "running" for in-flight runs.
|
|
1779
|
+
*/
|
|
1780
|
+
type RunStatus = "prepared" | "running" | "paused" | "succeeded" | "failed";
|
|
1781
|
+
/**
|
|
1782
|
+
* A read-only snapshot of a run's metadata, returned by list() and get().
|
|
1783
|
+
*
|
|
1784
|
+
* `context` is the live RunContext if the registry still holds a strong
|
|
1785
|
+
* reference (i.e. the run has not completed/expired). It is null once the
|
|
1786
|
+
* context has been released. Callers who receive a non-null context should
|
|
1787
|
+
* not store it long-term — they will prevent GC if they do.
|
|
1788
|
+
*/
|
|
1789
|
+
interface RunInfo<S extends object> {
|
|
1790
|
+
readonly runId: string;
|
|
1791
|
+
readonly pipelineId: string;
|
|
1792
|
+
readonly status: RunStatus;
|
|
1793
|
+
readonly startedAt: string;
|
|
1794
|
+
readonly pausedAt: string | undefined;
|
|
1795
|
+
readonly checkpoint: PipelineCheckpoint | undefined;
|
|
1796
|
+
readonly context: RunContext<S> | null;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Configuration for a {@link PipelineRegistry} instance.
|
|
1800
|
+
*/
|
|
1801
|
+
interface PipelineRegistryOptions {
|
|
1802
|
+
/**
|
|
1803
|
+
* Default pause timeout in milliseconds.
|
|
1804
|
+
* Used when a PauseInstruction carries no explicit `timeout` field.
|
|
1805
|
+
* Defaults to 5 minutes (300_000 ms).
|
|
1806
|
+
*/
|
|
1807
|
+
defaultPauseTimeout?: number;
|
|
1808
|
+
/**
|
|
1809
|
+
* Called when a paused run's timeout fires and the context is about to
|
|
1810
|
+
* be released. Receives the runId and the final checkpoint (which now
|
|
1811
|
+
* includes the containerBundle if export succeeded).
|
|
1812
|
+
*
|
|
1813
|
+
* Use this to notify external systems (e.g. send a "run expired" webhook,
|
|
1814
|
+
* update a database record, schedule a retry).
|
|
1815
|
+
*/
|
|
1816
|
+
onExpired?: (runId: string, checkpoint: PipelineCheckpoint) => void;
|
|
1817
|
+
/**
|
|
1818
|
+
* Called when a container export fails at timeout expiry.
|
|
1819
|
+
* The checkpoint is cleared from the store and the context is still
|
|
1820
|
+
* released, but without a containerBundle — a subsequent resume() would
|
|
1821
|
+
* need to rebuild the container from scratch via the factory's slow path.
|
|
1822
|
+
*/
|
|
1823
|
+
onExportFailed?: (runId: string, error: unknown) => void;
|
|
1824
|
+
/** Logger. Defaults to console. */
|
|
1825
|
+
logger?: EngineLogger;
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Stateful coordination layer for pipeline runs.
|
|
1829
|
+
*
|
|
1830
|
+
* @typeParam S - The state shape. Use the base `State` type when the registry
|
|
1831
|
+
* manages runs across multiple pipeline definitions with different
|
|
1832
|
+
* state shapes (the common case for a module-level singleton).
|
|
1833
|
+
*
|
|
1834
|
+
* @example
|
|
1835
|
+
* ```ts
|
|
1836
|
+
* // Module-level singleton — importable from anywhere
|
|
1837
|
+
* import { PipelineRegistry } from "./pipeline-registry";
|
|
1838
|
+
*
|
|
1839
|
+
* // In your factory setup:
|
|
1840
|
+
* const factory = new PipelineFactory(definition, {
|
|
1841
|
+
* storeFactory,
|
|
1842
|
+
* registry: PipelineRegistry.default,
|
|
1843
|
+
* });
|
|
1844
|
+
*
|
|
1845
|
+
* // From anywhere in the app:
|
|
1846
|
+
* const runs = PipelineRegistry.default.list();
|
|
1847
|
+
* const info = PipelineRegistry.default.get(runId);
|
|
1848
|
+
* ```
|
|
1849
|
+
*/
|
|
1850
|
+
declare class PipelineRegistry<S extends object = State> implements PipelineRegistryBinding<S> {
|
|
1851
|
+
private static readonly instances;
|
|
1852
|
+
/**
|
|
1853
|
+
* The module-level default registry.
|
|
1854
|
+
* Importable from anywhere in the process. Manages runs across all pipeline
|
|
1855
|
+
* factories that reference it.
|
|
1856
|
+
*/
|
|
1857
|
+
static readonly default: PipelineRegistry<any>;
|
|
1858
|
+
/**
|
|
1859
|
+
* Returns a named registry, creating it on first access.
|
|
1860
|
+
* Useful for test isolation (each test suite gets its own registry) or
|
|
1861
|
+
* domain separation (one registry per bounded context).
|
|
1862
|
+
*
|
|
1863
|
+
* @param name - A stable identifier for the registry instance.
|
|
1864
|
+
* @param options - Applied only on first creation; ignored on subsequent calls.
|
|
1865
|
+
*/
|
|
1866
|
+
static get<S extends object = State>(name: string, options?: PipelineRegistryOptions): PipelineRegistry<S>;
|
|
1867
|
+
/**
|
|
1868
|
+
* Destroys a named registry instance, cancelling all active timers and
|
|
1869
|
+
* releasing all strong references. The instance is removed from the
|
|
1870
|
+
* static map so the next call to get(name) creates a fresh registry.
|
|
1871
|
+
*
|
|
1872
|
+
* Primarily useful in tests.
|
|
1873
|
+
*/
|
|
1874
|
+
static destroy(name: string): void;
|
|
1875
|
+
private readonly defaultPauseTimeout;
|
|
1876
|
+
private readonly onExpired;
|
|
1877
|
+
private readonly onExportFailed;
|
|
1878
|
+
private readonly logger;
|
|
1879
|
+
/**
|
|
1880
|
+
* Strong-reference map. The registry is the last strong holder of each
|
|
1881
|
+
* RunContext. Nulling record.context is the moment GC eligibility begins.
|
|
1882
|
+
*/
|
|
1883
|
+
private readonly records;
|
|
1884
|
+
/**
|
|
1885
|
+
* Weak-reference index. Allows external callers to observe runs without
|
|
1886
|
+
* the registry preventing GC of completed or expired contexts.
|
|
1887
|
+
* Entries are added in register() and removed either explicitly in
|
|
1888
|
+
* releaseContext() or passively by the FinalizationRegistry callback.
|
|
1889
|
+
*/
|
|
1890
|
+
private readonly weakIndex;
|
|
1891
|
+
/**
|
|
1892
|
+
* Passively cleans up stale WeakRef entries after GC collects a context.
|
|
1893
|
+
* The held value is the runId so the callback can remove the correct entry.
|
|
1894
|
+
*/
|
|
1895
|
+
private readonly finalizer;
|
|
1896
|
+
constructor(options?: PipelineRegistryOptions);
|
|
1897
|
+
/**
|
|
1898
|
+
* Registers a new RunContext with the registry.
|
|
1899
|
+
*
|
|
1900
|
+
* Called by PipelineFactory.prepare() and PipelineFactory.resume() (slow
|
|
1901
|
+
* path) immediately after constructing a RunContext. The store is passed
|
|
1902
|
+
* here so the registry never needs to reach back into the factory.
|
|
1903
|
+
*
|
|
1904
|
+
* The registry wires pipeline:paused, pipeline:success, and pipeline:failure
|
|
1905
|
+
* listeners onto the context's event bus. These listeners drive all
|
|
1906
|
+
* subsequent state transitions (arming timers, releasing refs, etc.).
|
|
1907
|
+
*
|
|
1908
|
+
* `container` is extracted from the context via the RegistrableRunContext
|
|
1909
|
+
* interface — a narrow extension of RunContext that RunContextImpl satisfies
|
|
1910
|
+
* by exposing its container reference for registry use only.
|
|
1911
|
+
*
|
|
1912
|
+
* @param context - The RunContext to track.
|
|
1913
|
+
* @param store - The run's DataStore (owned by the run, borrowed by registry).
|
|
1914
|
+
*/
|
|
1915
|
+
register(context: RunContext<S>, store: DataStore<S>): void;
|
|
1916
|
+
getCheckpoint(runId: string): PipelineCheckpoint | null;
|
|
1917
|
+
/**
|
|
1918
|
+
* Returns the live RunContext for a paused run if the registry still holds
|
|
1919
|
+
* a strong reference (i.e. the pause timeout has not yet fired).
|
|
1920
|
+
*
|
|
1921
|
+
* Called by PipelineFactory.resume() as the fast path check. If this
|
|
1922
|
+
* returns non-null, the factory skips store reconstruction entirely.
|
|
1923
|
+
*
|
|
1924
|
+
* The timer is cancelled here — the caller (factory) takes responsibility
|
|
1925
|
+
* for the context from this point and will re-register it via register()
|
|
1926
|
+
* after wiring new event listeners.
|
|
1927
|
+
*
|
|
1928
|
+
* @param runId - The run identifier to look up.
|
|
1929
|
+
* @returns The live RunContext, or null if not found / already released.
|
|
1930
|
+
*/
|
|
1931
|
+
getLiveContext(runId: string): RunContext<S> | null;
|
|
1932
|
+
/**
|
|
1933
|
+
* Returns a snapshot of all tracked runs regardless of status.
|
|
1934
|
+
* Completed and expired runs remain in the map until explicitly pruned
|
|
1935
|
+
* via prune() or dispose().
|
|
1936
|
+
*/
|
|
1937
|
+
list(): RunInfo<S>[];
|
|
1938
|
+
/**
|
|
1939
|
+
* Returns runs matching a given status.
|
|
1940
|
+
*
|
|
1941
|
+
* @param status - Filter by run status.
|
|
1942
|
+
*/
|
|
1943
|
+
listByStatus(status: RunStatus): RunInfo<S>[];
|
|
1944
|
+
/**
|
|
1945
|
+
* Checks if a run id is registered
|
|
1946
|
+
* @param runId - The run identifier.
|
|
1947
|
+
*/
|
|
1948
|
+
has(runId: string): boolean;
|
|
1949
|
+
/**
|
|
1950
|
+
* Returns the RunInfo for a specific run, or undefined if not tracked.
|
|
1951
|
+
*
|
|
1952
|
+
* @param runId - The run identifier.
|
|
1953
|
+
*/
|
|
1954
|
+
get(runId: string): RunInfo<S> | undefined;
|
|
1955
|
+
/**
|
|
1956
|
+
* Removes all terminal runs (succeeded / failed) and expired paused runs
|
|
1957
|
+
* (context already null) from the records map.
|
|
1958
|
+
*
|
|
1959
|
+
* Call periodically or on a schedule to prevent unbounded memory growth in
|
|
1960
|
+
* long-running processes.
|
|
1961
|
+
*/
|
|
1962
|
+
prune(): void;
|
|
1963
|
+
/**
|
|
1964
|
+
* Cancels all active timers, releases all strong context references, and
|
|
1965
|
+
* unsubscribes all event listeners.
|
|
1966
|
+
*
|
|
1967
|
+
* Does not clear the records map — call prune() afterward if needed.
|
|
1968
|
+
* After dispose() the registry should not be used further.
|
|
1969
|
+
*/
|
|
1970
|
+
dispose(): void;
|
|
1971
|
+
private onRun;
|
|
1972
|
+
private onPaused;
|
|
1973
|
+
private onSucceeded;
|
|
1974
|
+
private onFailed;
|
|
1975
|
+
/**
|
|
1976
|
+
* Runs when the pause timeout fires (or immediately when timeout === 0).
|
|
1977
|
+
*
|
|
1978
|
+
* Sequence:
|
|
1979
|
+
* 1. Export the ArtifactContainer to get the bundle.
|
|
1980
|
+
* 2. Write the bundle into the persisted checkpoint via writeCheckpoint().
|
|
1981
|
+
* 3. Null the strong context reference → GC-eligible.
|
|
1982
|
+
* 4. Call onExpired callback.
|
|
1983
|
+
*
|
|
1984
|
+
* On export failure:
|
|
1985
|
+
* 1. Log the error and call onExportFailed.
|
|
1986
|
+
* 2. Clear the checkpoint from the store entirely (no partial bundle).
|
|
1987
|
+
* 3. Null the strong ref anyway — we cannot hold it indefinitely.
|
|
1988
|
+
*
|
|
1989
|
+
* The store is not closed here — the registry borrowed it from the run;
|
|
1990
|
+
* the storeFactory caller owns its lifecycle.
|
|
1991
|
+
*/
|
|
1992
|
+
private runExpirySequence;
|
|
1993
|
+
private cancelTimer;
|
|
1994
|
+
private unwire;
|
|
1995
|
+
/**
|
|
1996
|
+
* Nulls the strong context reference and removes the WeakRef from the index.
|
|
1997
|
+
* After this call the context is GC-eligible if no external holder remains.
|
|
1998
|
+
*/
|
|
1999
|
+
private releaseContext;
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* A narrow extension of RunContext that RunContextImpl satisfies internally.
|
|
2003
|
+
*
|
|
2004
|
+
* These two fields are the only things the registry needs from the context
|
|
2005
|
+
* beyond the public RunContext interface. They are not part of the public
|
|
2006
|
+
* surface — callers accessing a RunContext never see them. The registry casts
|
|
2007
|
+
* to this interface inside register() to extract them.
|
|
2008
|
+
*
|
|
2009
|
+
* RunContextImpl must be updated to expose these two fields so the registry
|
|
2010
|
+
* can access them. Since RunContextImpl is package-private, this coupling is
|
|
2011
|
+
* contained within the package and does not leak to consumers.
|
|
2012
|
+
*/
|
|
2013
|
+
interface RegistrableRunContext<S extends object> extends RunContext<S> {
|
|
2014
|
+
/**
|
|
2015
|
+
* The shared ArtifactContainer for this run.
|
|
2016
|
+
* Used by the registry for deferred export at pause timeout.
|
|
2017
|
+
* Tagged with double-underscore to signal it is registry-internal.
|
|
2018
|
+
*/
|
|
2019
|
+
readonly __registryContainer: ArtifactContainer<any, S>;
|
|
2020
|
+
/**
|
|
2021
|
+
* The pipeline definition id this run belongs to.
|
|
2022
|
+
* Used by the registry to populate RunRecord.pipelineId.
|
|
2023
|
+
*/
|
|
2024
|
+
readonly __registryPipelineId: string;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
export { type EngineLogger, type EntryAddress, type EventPath, PIPELINE_DATA_KEY, PIPELINE_RUN_ID_KEY, type PathNode, type PauseInstruction, Pipeline, type PipelineCheckpoint, type PipelineContext, type PipelineDefinition, type PipelineEventMap, PipelineFactory, type PipelineFactoryOptions, PipelineRegistry, type PipelineRegistryBinding, type PipelineRegistryOptions, type PipelineRunResult, type PipelineStageRouter, type PipelineStep, type PipelineStepDefinition, type RegistrableRunContext, Result, type RoutingInstruction, type RoutingPipelineDefinition, type RunContext, type RunEventHandler, type RunEventMap, type RunInfo, type RunStatus, SequentialExecutionContext, type Stage, type StageCarry, type State, type Step, type StepStageRouter, type SubPipelineAddress, clearCheckpoint, isPauseInstruction, readCheckpoint, writeCheckpoint };
|
package/index.d.ts
CHANGED
|
@@ -414,7 +414,7 @@ declare class Pipeline {
|
|
|
414
414
|
/**
|
|
415
415
|
* Utility type for representing partial updates to the state, allowing deep nesting.
|
|
416
416
|
* It makes all properties optional and applies the same transformation recursively
|
|
417
|
-
* to nested objects
|
|
417
|
+
* to nested objects, allowing for selective updates while
|
|
418
418
|
* preserving the original structure. It also includes the original type T and
|
|
419
419
|
* undefined as possibilities for the top level and nested values.
|
|
420
420
|
*/
|
|
@@ -1242,6 +1242,8 @@ interface PipelineCheckpoint {
|
|
|
1242
1242
|
}
|
|
1243
1243
|
/** Factory-internal namespace for all checkpoint data. */
|
|
1244
1244
|
declare const PIPELINE_DATA_KEY: "__pipeline_data__";
|
|
1245
|
+
/** Factory-internal namespace for run id */
|
|
1246
|
+
declare const PIPELINE_RUN_ID_KEY: "__pipeline_id__";
|
|
1245
1247
|
/**
|
|
1246
1248
|
* Run-scoped context injected into every step action as a second argument.
|
|
1247
1249
|
*
|
|
@@ -1553,6 +1555,7 @@ interface RunContext<S extends object> {
|
|
|
1553
1555
|
interface EngineLogger {
|
|
1554
1556
|
info: (msg: string, ctx?: any) => void;
|
|
1555
1557
|
error: (msg: string, ctx?: any) => void;
|
|
1558
|
+
warn: (msg: string, ctx?: any) => void;
|
|
1556
1559
|
}
|
|
1557
1560
|
/**
|
|
1558
1561
|
* Configuration for {@link PipelineFactory}.
|
|
@@ -1594,6 +1597,7 @@ interface PipelineFactoryOptions<S extends object = State> {
|
|
|
1594
1597
|
* the factory remains decoupled from the registry's full surface.
|
|
1595
1598
|
*/
|
|
1596
1599
|
interface PipelineRegistryBinding<S extends object> {
|
|
1600
|
+
has(id: string): boolean;
|
|
1597
1601
|
register(context: RunContext<S>, store: DataStore<S>): void;
|
|
1598
1602
|
/**
|
|
1599
1603
|
* Called by resume() before constructing a new RunContext.
|
|
@@ -1602,6 +1606,8 @@ interface PipelineRegistryBinding<S extends object> {
|
|
|
1602
1606
|
* Returns null if no live context exists and reconstruction is needed.
|
|
1603
1607
|
*/
|
|
1604
1608
|
getLiveContext(runId: string): RunContext<S> | null;
|
|
1609
|
+
/** Returns the checkpoint for a paused run, if available. */
|
|
1610
|
+
getCheckpoint(runId: string): PipelineCheckpoint | null;
|
|
1605
1611
|
}
|
|
1606
1612
|
/**
|
|
1607
1613
|
* A pure factory for creating and resuming pipeline runs.
|
|
@@ -1729,4 +1735,293 @@ declare function readCheckpoint(store: DataStore<any>, pipelineId: string | unde
|
|
|
1729
1735
|
*/
|
|
1730
1736
|
declare function clearCheckpoint(store: DataStore<any>, pipelineId: string, runId: string): Promise<void>;
|
|
1731
1737
|
|
|
1732
|
-
|
|
1738
|
+
/**
|
|
1739
|
+
* @file pipeline-registry.ts
|
|
1740
|
+
* @description Stateful coordination layer for pipeline runs.
|
|
1741
|
+
*
|
|
1742
|
+
* The registry is the single source of truth for live run state. It owns:
|
|
1743
|
+
*
|
|
1744
|
+
* 1. Strong references to RunContext instances — it decides when a context
|
|
1745
|
+
* becomes GC-eligible by nulling the reference inside its RunRecord.
|
|
1746
|
+
*
|
|
1747
|
+
* 2. Pause timers — armed when a pipeline pauses, cancelled when resume()
|
|
1748
|
+
* is called before expiry.
|
|
1749
|
+
*
|
|
1750
|
+
* 3. Deferred container export — on timer expiry the registry exports the
|
|
1751
|
+
* ArtifactContainer and writes the bundle into the persisted checkpoint
|
|
1752
|
+
* via writeCheckpoint(), then nulls the context reference.
|
|
1753
|
+
*
|
|
1754
|
+
* 4. A WeakRef index — allows external observers to list and watch runs
|
|
1755
|
+
* without the registry preventing GC of completed or expired records.
|
|
1756
|
+
*
|
|
1757
|
+
* 5. A FinalizationRegistry — passively removes stale WeakRef entries from
|
|
1758
|
+
* the index after GC collects a context nobody else held.
|
|
1759
|
+
*
|
|
1760
|
+
* GC eligibility rules:
|
|
1761
|
+
* - Completed runs (succeeded / failed): the registry nulls the strong ref
|
|
1762
|
+
* immediately on the terminal event. If no external caller holds a reference
|
|
1763
|
+
* the context is GC-eligible right away.
|
|
1764
|
+
* - Paused runs: the registry holds the strong ref for `pauseTimeout` ms
|
|
1765
|
+
* (from the PauseInstruction, or the registry default). During that window
|
|
1766
|
+
* resume() returns the live context directly — zero reconstruction cost.
|
|
1767
|
+
* When the timer fires the registry exports, updates the checkpoint, nulls
|
|
1768
|
+
* the ref, and fires onExpired.
|
|
1769
|
+
*
|
|
1770
|
+
* Named instances:
|
|
1771
|
+
* PipelineRegistry.default — module-level singleton, importable from anywhere.
|
|
1772
|
+
* PipelineRegistry.get(name) — named registries for test isolation or domain
|
|
1773
|
+
* separation within the same process.
|
|
1774
|
+
*/
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
* The status of a run as tracked by the registry.
|
|
1778
|
+
* Mirrors PipelineRunResult["status"] but adds "running" for in-flight runs.
|
|
1779
|
+
*/
|
|
1780
|
+
type RunStatus = "prepared" | "running" | "paused" | "succeeded" | "failed";
|
|
1781
|
+
/**
|
|
1782
|
+
* A read-only snapshot of a run's metadata, returned by list() and get().
|
|
1783
|
+
*
|
|
1784
|
+
* `context` is the live RunContext if the registry still holds a strong
|
|
1785
|
+
* reference (i.e. the run has not completed/expired). It is null once the
|
|
1786
|
+
* context has been released. Callers who receive a non-null context should
|
|
1787
|
+
* not store it long-term — they will prevent GC if they do.
|
|
1788
|
+
*/
|
|
1789
|
+
interface RunInfo<S extends object> {
|
|
1790
|
+
readonly runId: string;
|
|
1791
|
+
readonly pipelineId: string;
|
|
1792
|
+
readonly status: RunStatus;
|
|
1793
|
+
readonly startedAt: string;
|
|
1794
|
+
readonly pausedAt: string | undefined;
|
|
1795
|
+
readonly checkpoint: PipelineCheckpoint | undefined;
|
|
1796
|
+
readonly context: RunContext<S> | null;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Configuration for a {@link PipelineRegistry} instance.
|
|
1800
|
+
*/
|
|
1801
|
+
interface PipelineRegistryOptions {
|
|
1802
|
+
/**
|
|
1803
|
+
* Default pause timeout in milliseconds.
|
|
1804
|
+
* Used when a PauseInstruction carries no explicit `timeout` field.
|
|
1805
|
+
* Defaults to 5 minutes (300_000 ms).
|
|
1806
|
+
*/
|
|
1807
|
+
defaultPauseTimeout?: number;
|
|
1808
|
+
/**
|
|
1809
|
+
* Called when a paused run's timeout fires and the context is about to
|
|
1810
|
+
* be released. Receives the runId and the final checkpoint (which now
|
|
1811
|
+
* includes the containerBundle if export succeeded).
|
|
1812
|
+
*
|
|
1813
|
+
* Use this to notify external systems (e.g. send a "run expired" webhook,
|
|
1814
|
+
* update a database record, schedule a retry).
|
|
1815
|
+
*/
|
|
1816
|
+
onExpired?: (runId: string, checkpoint: PipelineCheckpoint) => void;
|
|
1817
|
+
/**
|
|
1818
|
+
* Called when a container export fails at timeout expiry.
|
|
1819
|
+
* The checkpoint is cleared from the store and the context is still
|
|
1820
|
+
* released, but without a containerBundle — a subsequent resume() would
|
|
1821
|
+
* need to rebuild the container from scratch via the factory's slow path.
|
|
1822
|
+
*/
|
|
1823
|
+
onExportFailed?: (runId: string, error: unknown) => void;
|
|
1824
|
+
/** Logger. Defaults to console. */
|
|
1825
|
+
logger?: EngineLogger;
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Stateful coordination layer for pipeline runs.
|
|
1829
|
+
*
|
|
1830
|
+
* @typeParam S - The state shape. Use the base `State` type when the registry
|
|
1831
|
+
* manages runs across multiple pipeline definitions with different
|
|
1832
|
+
* state shapes (the common case for a module-level singleton).
|
|
1833
|
+
*
|
|
1834
|
+
* @example
|
|
1835
|
+
* ```ts
|
|
1836
|
+
* // Module-level singleton — importable from anywhere
|
|
1837
|
+
* import { PipelineRegistry } from "./pipeline-registry";
|
|
1838
|
+
*
|
|
1839
|
+
* // In your factory setup:
|
|
1840
|
+
* const factory = new PipelineFactory(definition, {
|
|
1841
|
+
* storeFactory,
|
|
1842
|
+
* registry: PipelineRegistry.default,
|
|
1843
|
+
* });
|
|
1844
|
+
*
|
|
1845
|
+
* // From anywhere in the app:
|
|
1846
|
+
* const runs = PipelineRegistry.default.list();
|
|
1847
|
+
* const info = PipelineRegistry.default.get(runId);
|
|
1848
|
+
* ```
|
|
1849
|
+
*/
|
|
1850
|
+
declare class PipelineRegistry<S extends object = State> implements PipelineRegistryBinding<S> {
|
|
1851
|
+
private static readonly instances;
|
|
1852
|
+
/**
|
|
1853
|
+
* The module-level default registry.
|
|
1854
|
+
* Importable from anywhere in the process. Manages runs across all pipeline
|
|
1855
|
+
* factories that reference it.
|
|
1856
|
+
*/
|
|
1857
|
+
static readonly default: PipelineRegistry<any>;
|
|
1858
|
+
/**
|
|
1859
|
+
* Returns a named registry, creating it on first access.
|
|
1860
|
+
* Useful for test isolation (each test suite gets its own registry) or
|
|
1861
|
+
* domain separation (one registry per bounded context).
|
|
1862
|
+
*
|
|
1863
|
+
* @param name - A stable identifier for the registry instance.
|
|
1864
|
+
* @param options - Applied only on first creation; ignored on subsequent calls.
|
|
1865
|
+
*/
|
|
1866
|
+
static get<S extends object = State>(name: string, options?: PipelineRegistryOptions): PipelineRegistry<S>;
|
|
1867
|
+
/**
|
|
1868
|
+
* Destroys a named registry instance, cancelling all active timers and
|
|
1869
|
+
* releasing all strong references. The instance is removed from the
|
|
1870
|
+
* static map so the next call to get(name) creates a fresh registry.
|
|
1871
|
+
*
|
|
1872
|
+
* Primarily useful in tests.
|
|
1873
|
+
*/
|
|
1874
|
+
static destroy(name: string): void;
|
|
1875
|
+
private readonly defaultPauseTimeout;
|
|
1876
|
+
private readonly onExpired;
|
|
1877
|
+
private readonly onExportFailed;
|
|
1878
|
+
private readonly logger;
|
|
1879
|
+
/**
|
|
1880
|
+
* Strong-reference map. The registry is the last strong holder of each
|
|
1881
|
+
* RunContext. Nulling record.context is the moment GC eligibility begins.
|
|
1882
|
+
*/
|
|
1883
|
+
private readonly records;
|
|
1884
|
+
/**
|
|
1885
|
+
* Weak-reference index. Allows external callers to observe runs without
|
|
1886
|
+
* the registry preventing GC of completed or expired contexts.
|
|
1887
|
+
* Entries are added in register() and removed either explicitly in
|
|
1888
|
+
* releaseContext() or passively by the FinalizationRegistry callback.
|
|
1889
|
+
*/
|
|
1890
|
+
private readonly weakIndex;
|
|
1891
|
+
/**
|
|
1892
|
+
* Passively cleans up stale WeakRef entries after GC collects a context.
|
|
1893
|
+
* The held value is the runId so the callback can remove the correct entry.
|
|
1894
|
+
*/
|
|
1895
|
+
private readonly finalizer;
|
|
1896
|
+
constructor(options?: PipelineRegistryOptions);
|
|
1897
|
+
/**
|
|
1898
|
+
* Registers a new RunContext with the registry.
|
|
1899
|
+
*
|
|
1900
|
+
* Called by PipelineFactory.prepare() and PipelineFactory.resume() (slow
|
|
1901
|
+
* path) immediately after constructing a RunContext. The store is passed
|
|
1902
|
+
* here so the registry never needs to reach back into the factory.
|
|
1903
|
+
*
|
|
1904
|
+
* The registry wires pipeline:paused, pipeline:success, and pipeline:failure
|
|
1905
|
+
* listeners onto the context's event bus. These listeners drive all
|
|
1906
|
+
* subsequent state transitions (arming timers, releasing refs, etc.).
|
|
1907
|
+
*
|
|
1908
|
+
* `container` is extracted from the context via the RegistrableRunContext
|
|
1909
|
+
* interface — a narrow extension of RunContext that RunContextImpl satisfies
|
|
1910
|
+
* by exposing its container reference for registry use only.
|
|
1911
|
+
*
|
|
1912
|
+
* @param context - The RunContext to track.
|
|
1913
|
+
* @param store - The run's DataStore (owned by the run, borrowed by registry).
|
|
1914
|
+
*/
|
|
1915
|
+
register(context: RunContext<S>, store: DataStore<S>): void;
|
|
1916
|
+
getCheckpoint(runId: string): PipelineCheckpoint | null;
|
|
1917
|
+
/**
|
|
1918
|
+
* Returns the live RunContext for a paused run if the registry still holds
|
|
1919
|
+
* a strong reference (i.e. the pause timeout has not yet fired).
|
|
1920
|
+
*
|
|
1921
|
+
* Called by PipelineFactory.resume() as the fast path check. If this
|
|
1922
|
+
* returns non-null, the factory skips store reconstruction entirely.
|
|
1923
|
+
*
|
|
1924
|
+
* The timer is cancelled here — the caller (factory) takes responsibility
|
|
1925
|
+
* for the context from this point and will re-register it via register()
|
|
1926
|
+
* after wiring new event listeners.
|
|
1927
|
+
*
|
|
1928
|
+
* @param runId - The run identifier to look up.
|
|
1929
|
+
* @returns The live RunContext, or null if not found / already released.
|
|
1930
|
+
*/
|
|
1931
|
+
getLiveContext(runId: string): RunContext<S> | null;
|
|
1932
|
+
/**
|
|
1933
|
+
* Returns a snapshot of all tracked runs regardless of status.
|
|
1934
|
+
* Completed and expired runs remain in the map until explicitly pruned
|
|
1935
|
+
* via prune() or dispose().
|
|
1936
|
+
*/
|
|
1937
|
+
list(): RunInfo<S>[];
|
|
1938
|
+
/**
|
|
1939
|
+
* Returns runs matching a given status.
|
|
1940
|
+
*
|
|
1941
|
+
* @param status - Filter by run status.
|
|
1942
|
+
*/
|
|
1943
|
+
listByStatus(status: RunStatus): RunInfo<S>[];
|
|
1944
|
+
/**
|
|
1945
|
+
* Checks if a run id is registered
|
|
1946
|
+
* @param runId - The run identifier.
|
|
1947
|
+
*/
|
|
1948
|
+
has(runId: string): boolean;
|
|
1949
|
+
/**
|
|
1950
|
+
* Returns the RunInfo for a specific run, or undefined if not tracked.
|
|
1951
|
+
*
|
|
1952
|
+
* @param runId - The run identifier.
|
|
1953
|
+
*/
|
|
1954
|
+
get(runId: string): RunInfo<S> | undefined;
|
|
1955
|
+
/**
|
|
1956
|
+
* Removes all terminal runs (succeeded / failed) and expired paused runs
|
|
1957
|
+
* (context already null) from the records map.
|
|
1958
|
+
*
|
|
1959
|
+
* Call periodically or on a schedule to prevent unbounded memory growth in
|
|
1960
|
+
* long-running processes.
|
|
1961
|
+
*/
|
|
1962
|
+
prune(): void;
|
|
1963
|
+
/**
|
|
1964
|
+
* Cancels all active timers, releases all strong context references, and
|
|
1965
|
+
* unsubscribes all event listeners.
|
|
1966
|
+
*
|
|
1967
|
+
* Does not clear the records map — call prune() afterward if needed.
|
|
1968
|
+
* After dispose() the registry should not be used further.
|
|
1969
|
+
*/
|
|
1970
|
+
dispose(): void;
|
|
1971
|
+
private onRun;
|
|
1972
|
+
private onPaused;
|
|
1973
|
+
private onSucceeded;
|
|
1974
|
+
private onFailed;
|
|
1975
|
+
/**
|
|
1976
|
+
* Runs when the pause timeout fires (or immediately when timeout === 0).
|
|
1977
|
+
*
|
|
1978
|
+
* Sequence:
|
|
1979
|
+
* 1. Export the ArtifactContainer to get the bundle.
|
|
1980
|
+
* 2. Write the bundle into the persisted checkpoint via writeCheckpoint().
|
|
1981
|
+
* 3. Null the strong context reference → GC-eligible.
|
|
1982
|
+
* 4. Call onExpired callback.
|
|
1983
|
+
*
|
|
1984
|
+
* On export failure:
|
|
1985
|
+
* 1. Log the error and call onExportFailed.
|
|
1986
|
+
* 2. Clear the checkpoint from the store entirely (no partial bundle).
|
|
1987
|
+
* 3. Null the strong ref anyway — we cannot hold it indefinitely.
|
|
1988
|
+
*
|
|
1989
|
+
* The store is not closed here — the registry borrowed it from the run;
|
|
1990
|
+
* the storeFactory caller owns its lifecycle.
|
|
1991
|
+
*/
|
|
1992
|
+
private runExpirySequence;
|
|
1993
|
+
private cancelTimer;
|
|
1994
|
+
private unwire;
|
|
1995
|
+
/**
|
|
1996
|
+
* Nulls the strong context reference and removes the WeakRef from the index.
|
|
1997
|
+
* After this call the context is GC-eligible if no external holder remains.
|
|
1998
|
+
*/
|
|
1999
|
+
private releaseContext;
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* A narrow extension of RunContext that RunContextImpl satisfies internally.
|
|
2003
|
+
*
|
|
2004
|
+
* These two fields are the only things the registry needs from the context
|
|
2005
|
+
* beyond the public RunContext interface. They are not part of the public
|
|
2006
|
+
* surface — callers accessing a RunContext never see them. The registry casts
|
|
2007
|
+
* to this interface inside register() to extract them.
|
|
2008
|
+
*
|
|
2009
|
+
* RunContextImpl must be updated to expose these two fields so the registry
|
|
2010
|
+
* can access them. Since RunContextImpl is package-private, this coupling is
|
|
2011
|
+
* contained within the package and does not leak to consumers.
|
|
2012
|
+
*/
|
|
2013
|
+
interface RegistrableRunContext<S extends object> extends RunContext<S> {
|
|
2014
|
+
/**
|
|
2015
|
+
* The shared ArtifactContainer for this run.
|
|
2016
|
+
* Used by the registry for deferred export at pause timeout.
|
|
2017
|
+
* Tagged with double-underscore to signal it is registry-internal.
|
|
2018
|
+
*/
|
|
2019
|
+
readonly __registryContainer: ArtifactContainer<any, S>;
|
|
2020
|
+
/**
|
|
2021
|
+
* The pipeline definition id this run belongs to.
|
|
2022
|
+
* Used by the registry to populate RunRecord.pipelineId.
|
|
2023
|
+
*/
|
|
2024
|
+
readonly __registryPipelineId: string;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
export { type EngineLogger, type EntryAddress, type EventPath, PIPELINE_DATA_KEY, PIPELINE_RUN_ID_KEY, type PathNode, type PauseInstruction, Pipeline, type PipelineCheckpoint, type PipelineContext, type PipelineDefinition, type PipelineEventMap, PipelineFactory, type PipelineFactoryOptions, PipelineRegistry, type PipelineRegistryBinding, type PipelineRegistryOptions, type PipelineRunResult, type PipelineStageRouter, type PipelineStep, type PipelineStepDefinition, type RegistrableRunContext, Result, type RoutingInstruction, type RoutingPipelineDefinition, type RunContext, type RunEventHandler, type RunEventMap, type RunInfo, type RunStatus, SequentialExecutionContext, type Stage, type StageCarry, type State, type Step, type StepStageRouter, type SubPipelineAddress, clearCheckpoint, isPauseInstruction, readCheckpoint, writeCheckpoint };
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@asaidimu/utils-events"),t=require("uuid"),s={VALIDATION_FAILED:{code:"VAL-001",name:"VALIDATION_FAILED",description:"Input validation failed due to one or more invalid fields",category:"validation",httpStatus:400,logLevel:"warn"},REQUIRED_FIELD_MISSING:{code:"VAL-002",name:"REQUIRED_FIELD_MISSING",description:"A required field was not provided in the request",category:"validation",httpStatus:400,logLevel:"warn"},INVALID_FORMAT:{code:"VAL-003",name:"INVALID_FORMAT",description:"Field value does not match expected format",category:"validation",httpStatus:400,logLevel:"warn"},NOT_FOUND:{code:"DB-001-NF",name:"NOT_FOUND",description:"The requested resource could not be found",category:"database",httpStatus:404,logLevel:"info",action:"Verify the resource identifier exists before accessing"},DUPLICATE_KEY:{code:"DB-002-DUP",name:"DUPLICATE_KEY",description:"A unique constraint violation occurred",category:"database",httpStatus:409,logLevel:"warn",action:"Check if the resource already exists before creation"},RESOURCE_LOCKED:{code:"DB-003-LOCK",name:"RESOURCE_LOCKED",description:"The resource is currently locked by another operation",category:"database",httpStatus:409,logLevel:"warn",action:"Retry the operation after a brief delay"},PERMISSION_DENIED:{code:"AUTH-001-DENIED",name:"PERMISSION_DENIED",description:"The authenticated user lacks permission for this operation",category:"auth",httpStatus:403,logLevel:"warn",action:"Check user roles and permissions"},UNAUTHENTICATED:{code:"AUTH-002-UNAUTH",name:"UNAUTHENTICATED",description:"Authentication is required for this operation",category:"auth",httpStatus:401,logLevel:"info",action:"Provide valid authentication credentials"},INVALID_COMMAND:{code:"BUS-001",name:"INVALID_COMMAND",description:"The command or operation is invalid for the current state",category:"business",httpStatus:400,logLevel:"warn"},OPERATION_ABORTED:{code:"BUS-002-ABORT",name:"OPERATION_ABORTED",description:"The operation was explicitly aborted",category:"business",httpStatus:409,logLevel:"info"},INTERNAL_ERROR:{code:"SYS-001",name:"INTERNAL_ERROR",description:"An unexpected internal error occurred",category:"system",httpStatus:500,logLevel:"error",action:"Check system logs for stack traces and diagnostic information"},BACKEND_ERROR:{code:"SYS-002",name:"BACKEND_ERROR",description:"An error occurred in a backend service",category:"system",httpStatus:502,logLevel:"error"},CONCURRENCY_ERROR:{code:"CON-001",name:"CONCURRENCY_ERROR",description:"A concurrency conflict occurred during the operation",category:"concurrency",httpStatus:409,logLevel:"warn",action:"Retry the operation with updated data"}},i=new Map;var r=class e extends Error{code;codeMetadata;severity;path;operation;issues;cause;constructor(t){const r={...function(e){const t=Object.values(s).find((t=>t.code===e));if(t)return t;return i.get(e)||{code:e,name:e.replace(/-/g,"_"),description:`Unknown error: ${e}`,category:"custom",httpStatus:500,logLevel:"error",action:"Check if this error code is properly registered or handle as unknown error"}}(t.code),...t.metadata,code:t.code};super(t.message??r.description),this.name="SystemError",this.code=t.code,this.codeMetadata=r,this.severity=t.severity??"error",this.path=t.path,this.operation=t.operation,this.issues=t.issues??[],this.cause=t.cause,Object.setPrototypeOf(this,e.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,e)}withPath(t){return new e({code:this.code,message:this.message,severity:this.severity,path:t,operation:this.operation,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withOperation(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:t,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withIssue(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,t],cause:this.cause,metadata:this.codeMetadata})}withIssues(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,...t],cause:this.cause,metadata:this.codeMetadata})}withCause(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:this.issues,cause:t,metadata:this.codeMetadata})}getHttpStatus(){return this.codeMetadata.httpStatus}toLogEntry(){return{name:this.name,code:this.code,category:this.codeMetadata.category,message:this.message,path:this.path,operation:this.operation,issues:this.issues,cause:this.cause instanceof Error?this.cause.message:this.cause,stack:this.stack,timestamp:(new Date).toISOString()}}toString(){let e=`[${this.code}] ${this.message} (${this.codeMetadata.category})`;return this.path&&(e+=` at '${this.path}'`),this.operation&&(e+=` during '${this.operation}'`),this.issues.length>0&&(e+="\nIssues:\n"+this.issues.map(((e,t)=>` ${t+1}. ${e.message} [${e.code}]`)).join("\n")),this.cause&&(e+=`\nCause: ${this.cause instanceof Error?this.cause.message:String(this.cause)}`),e}},n="SYS-001",a=(e,t)=>new r({code:n,message:t,cause:e}),o=e=>({ok:!0,value:e}),c=e=>({ok:!1,error:e}),h=class e extends r{constructor(t,s){super({code:"SYNC_ERROR",message:t,cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},d=class e extends h{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},u=class e extends h{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},l=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}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 s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,r)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),r(new d("Mutex lock timed out"))}),e)}))])}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?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},p=class{mutex=new l({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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{this._value=await e(),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")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}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(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,r)=>{i=setTimeout((()=>r(new d(s))),t)}))])}},g=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new l({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new u};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,i=null;try{if(this._done)throw new u;i=await e(),this._lastValue=i,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:i,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},f=class{constructor(t,s,i,r,n){this.pipeline=t,this.stepKey=s,this.params=i,r&&(r.aborted&&this.controller.abort(),r.addEventListener("abort",(()=>this.controller.abort()))),this.localBus=n??e.createEventBus()}id=Math.random().toString(36).substring(2,9);localBus;controller=new AbortController;once=new p({retry:!1,throws:!1});get signal(){return this.controller.signal}on(e,t){return this.localBus.subscribe(e,t)}abort(){this.controller.abort()}async run(){const{value:e,error:t}=await this.once.do((()=>this._run()));return t?c(t):e}async _run(){const e=this.pipeline.getSteps().get(this.stepKey);if(!e)return{ok:!1,error:new r({code:s.INVALID_COMMAND.code,message:`No step registered with key "${this.stepKey}"`,operation:this.stepKey})};if(this.signal.aborted)return this.failCancelled("Pipeline execution aborted before initialization",this.stepKey);const t=this.pipeline.groupByOrder(),i=Array.from(t.entries()).sort((([e],[t])=>e-t)),n=e.order;this.emit("start",{stepKey:this.stepKey,executionId:this.id});let a={[this.stepKey]:this.params},o=a,c=!0;for(const[e,t]of i){if(e<n)continue;if(this.signal.aborted)return this.failCancelled(`Pipeline runtime aborted at stage ${e}`,this.stepKey);const s=c?t.filter((e=>e.key===this.stepKey)):t;if(c=!1,0===s.length)continue;const i=await this.runStage(s,a);if(!i.ok)return i;o=i.value,a={...a,...o},this.emit("stage:success",{order:e,executionId:this.id,carry:o})}return this.emit("terminate",{carry:o,executionId:this.id}),{ok:!0,value:o}}async runStage(e,t){const s=await Promise.all(e.map((async e=>{try{if(this.signal.aborted)return{step:e,result:this.failCancelled("Aborted mid-flight execution sequence",e.key)};const s=await e.action(t,this.signal);return{step:e,result:s}}catch(t){return{step:e,result:{ok:!1,error:t instanceof r?t:a(t,t instanceof Error?t.message:"Unexpected exception raised during step run")}}}}))),i={};let n=null;for(const{step:e,result:t}of s)if(t.ok)this.emit("step:success",{stepKey:e.key,executionId:this.id,result:t.value}),i[e.key]=t.value;else{const s=t.error.withOperation(e.key);this.emit("step:failure",{stepKey:e.key,executionId:this.id,error:s}),n||(n={ok:!1,error:s},this.emit("failure",{stepKey:e.key,executionId:this.id,error:s}))}return n||{ok:!0,value:i}}emit(e,t){this.localBus.emit({name:e,payload:t})}failCancelled(e,t){return{ok:!1,error:new r({code:"CANCELLED",message:e,operation:t})}}},y=class{constructor(e,t,s={}){this.factory=e,this.onCleanup=t,this.options=s}_count=0;init=new p({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask((()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())}))):void(this.cleanupTimer=setTimeout((()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()}),e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}};function m(e,t){if(!e.length)return;const s=e.slice(),i=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=s.length-1;e>=0;e--)try{await s[e]()}catch(t){console.error(`${i} Cleanup error at index ${e}:`,t)}}}async function w(e,t){const s=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${s} Cleanup error at index ${t}:`,e)}}function v(e){return`${e}__watched`}var b=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function S(e,t){let s;const i=new Promise(((e,i)=>{s=setTimeout((()=>i(new Error(`Timeout: ${t}ms`))),t)}));try{return Promise.race([e,i])}finally{clearTimeout(s)}}async function k(e){const t=(new TextEncoder).encode(e),s=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(s)).map((e=>e.toString(16).padStart(2,"0"))).join("")}var I=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,s){const i=this.get(e);if(!i)return b;if(i.package)return i.package;const r=e,n=m(i.cleanupFunctions,r),a="singleton"!==i.scope||void 0!==i.instance,o={instance:i.instance,error:i.error,ready:a,[s||e]:i.instance,cleanup:n,invalidate:t};return i.package=o,o}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const s=this.get(e);if(!s)return;const i=e;"singleton"===s.scope&&(s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),s.controller.abort(),await s.streamOnce.current(),s.streamSerializer.close(),s.stream=void 0,s.streamOnce=new p({retry:!0,throws:!0}),t||(s.streamSerializer=new g,s.controller=new AbortController)),await w(s.cleanupFunctions,i),await w(s.disposeFunctions,i),s.cleanupFunctions=[],s.disposeFunctions=[],"singleton"===s.scope&&(s.buildOnce=new p({retry:!0,throws:!0})),s.instance=void 0,s.error=void 0}},A=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const s of t)this.dependents.get(s)?.delete(e);const s=this.dependents.get(e);if(s)for(const t of s)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.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}iterDependents(e){return this.dependents.get(e)??_}setDependencies(e,t){this.registerNode(e);const s=this.dependencies.get(e),i=new Set(t);for(const t of s)i.has(t)||this.removeDependency(e,t);for(const t of i)s.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const s=[t],i=new Set([t]),r=new Map;for(;s.length>0;){const n=s.shift();if(n===e){const s=[];let i=e;for(;void 0!==i&&(s.push(i),i!==t);)i=r.get(i);return s.reverse(),s.unshift(e),s}const a=this.dependencies.get(n);if(a)for(const e of a)i.has(e)||(i.add(e),r.set(e,n),s.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const s of t)e.set(s,this.dependencies.get(s)?.size??0);const s=[];for(const[t,i]of e)0===i&&s.push(t);const i=[];for(;s.length>0;){const t=s.shift();i.push(t);const r=this.dependents.get(t);if(r)for(const t of r){const i=(e.get(t)||0)-1;e.set(t,i),0===i&&s.push(t)}}if(i.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return i}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,s){const i=new Set,r=new Set,n=[e];r.add(e),s&&i.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=a.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),i.add(e),n.push(e))}return i}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const s=Array.from(t).join(", ");return`${String(e)} → [${s||"∅"}]`})).join("\n")}},_=new Set,E=class{graph;constructor(){this.graph=new A}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){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}setDependencies(e,t){const s=Array.from(t).map((e=>e));this.graph.setDependencies(e,s)}wouldCreateCycle(e,t,s){if(s?.has(t)){const e=Array.from(s),i=e.indexOf(t),r=e.slice(i);return r.push(t),r}const i=this.graph.wouldCreateCycle(e,t);return i||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()}},O=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];var x=class e extends Error{category;constructor(t,s,i){super(t,{cause:i}),this.name="ArtifactError",this.category=s,Object.setPrototypeOf(this,e.prototype)}},C=class extends x{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},$=class extends x{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},D=class extends x{constructor(e){super(e,"system"),this.name="InvalidImportError"}},R=class extends x{constructor(e){super(`Artifact "${e}" instance is not JSON-serializable (POJO are required for persistence)`,"system"),this.name="InvalidExportOperationError"}},N=(new AbortController).signal,P=class{constructor(e,t,s,i,r){this.registry=e,this.cache=t,this.graph=s,this.store=i,this.observer=r}async build(e,t,s){const i=this.cache.get(e);if("singleton"===i?.scope&&i.buildOnce.done())return this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s);const r=this.registry.getByString(e);if(!r)throw new C(e);const n=t??[];if(n.includes(e))throw new x(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${[...n,e].join(" -> ")}`,"system");n.push(e);let a=i;a||(a=this.createCachedArtifact(r),this.cache.set(e,a));try{if("transient"===a.scope)return this.executeBuild(r,a,n);const i=a;try{await i.buildOnce.do((()=>this.executeBuild(r,i,n)))}catch(i){if(i instanceof $)return this.build(e,t,s);throw i}return i.stream&&i.streamOnce.do(i.stream),this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s)}finally{n.pop()}}async executeBuild(e,t,s){const i=e.key,r=String(i),n="transient"===t.scope;t.buildCount++,"singleton"===t.scope&&(t.activeDebounceMs=e.debounce??0);const a={cleanupFunctions:[],disposeFunctions:[],capturedArtifactDeps:new Set,capturedStateSelectors:[],dependencyVersions:new Map},o=this.buildContext(e,t,s,r,a),c=await this.runWithRetries(e,o,a.dependencyVersions);if(this.commitResult(i,t,n,c,a),n){const e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[i]:e,cleanup:m(a.cleanupFunctions,r),invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${r}"`)}}}buildContext(e,t,s,i,r){const n=e.key,a="transient"===t.scope,{cleanupFunctions:o,disposeFunctions:c,capturedArtifactDeps:h,dependencyVersions:d,capturedStateSelectors:u}=r,l=async(e,t)=>{const r=t?this.computeParamKey(e,t):e;if(r===n)throw new x(`Artifact "${i}" depends on itself.`,"system");const a=this.graph.wouldCreateCycle(n,r);if(a)throw new x(`Adding dependency "${String(r)}" to "${i}" would create a cycle: ${a.join(" -> ")}`,"system");h.add(r);const o=await(t?this.resolveParameterized(e,t):this.build(e,s)),c=this.cache.get(r);return c&&d.set(r,c.version),o},p="singleton"===t.scope?t.controller.signal:N,g=async(e,t)=>{const s=await l(e,t);if(s.error)throw s.error;return s.instance},f=(e,t)=>{const s=function(e,t="."){const s=new Set,i=new Map,r=(e="")=>{if(i.has(e))return i.get(e);const n=new Proxy((()=>{}),{get:(i,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic, arithmetic, or string operations inside a selector.");if(O.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const a=e?`${e}${t}${n}`:n;return e&&s.delete(e),s.add(a),r(a)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions or methods.")}});return i.set(e,n),n};try{e(r())}catch(e){throw new Error(`Selector failed during path analysis. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(s)}(e);return u.push({paths:s,options:t}),e(this.store.get(!0))};return{state:()=>this.store.get(!0),previous:t.instance,signal:p,onCleanup:e=>o.push(e),onDispose:e=>c.push(e),use:e=>e({resolve:l,require:g,select:f}),stream:e=>{if(a)throw new x(`[ArtifactManager] Illegal stream on transient artifact "${i}"`,"system");const s=t,r=async(e,t=void 0)=>{await s.streamSerializer.do((async()=>{void 0!==s.stream&&(s.instance=e,s.error=t,s.version++,this.cache.invalidatePackage(n),await this.processStream(i))}))},o={value:()=>s.instance,get signal(){return s.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>r(e)};s.stream=async()=>{try{const t=await e(o);t&&s.cleanupFunctions.push(t)}catch(e){await r(void 0,e),await this.invalidate(n,!1,!0)}}}}}async runWithRetries(e,t,s){const i=t.signal,r=(e.retries??0)+1;let n=0;for(;n<r;)try{if(i.aborted)throw new $;const a=e.factory(t);let o;if(o=a instanceof Promise?e.timeout?await S(a,e.timeout):await a:a,i.aborted)throw new $;const c=this.detectStaleness(s);if(c){if(n++,s.clear(),n<r)continue;return{ok:!1,error:new x(`Build stale after all retries: dependency "${String(c)}" changed during build.`,"system")}}return{ok:!0,value:o}}catch(e){if(i.aborted||e instanceof $)throw new $;if(e instanceof x)throw e;if(n++,n>=r)return{ok:!1,error:e}}return{ok:!1,error:new Error("Build exhausted retry budget unexpectedly.")}}commitResult(e,t,s,i,r){const{cleanupFunctions:n,disposeFunctions:a,capturedArtifactDeps:o,capturedStateSelectors:c}=r;s||(this.updateDependencyGraph(e,o,c),t.cleanupFunctions=n,t.disposeFunctions=a,t.artifactDependencies=new Set(o),t.stateGroups=c.map((({paths:e,options:t})=>({paths:e,options:t})))),i.ok?(t.instance=i.value,t.error=void 0):(t.instance=void 0,t.error=i.error),t.version++,this.cache.invalidatePackage(e)}detectStaleness(e){for(const[t,s]of e){const e=this.cache.get(t);if(e&&e.version!==s)return t}return null}async invalidate(e,t=!1,s=!1){const i=this.cache.get(e);if(!i)return;if("singleton"!==i.scope)return this.executeInvalidation(e,t,s);const r=i;return r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0),!t&&r.activeDebounceMs>0?new Promise(((i,n)=>{r.debounceTimer=setTimeout((()=>{r.debounceTimer=void 0,this.executeInvalidation(e,t,s).then(i).catch(n)}),r.activeDebounceMs)})):this.executeInvalidation(e,t,s)}async executeInvalidation(e,t,s=!1){const i=this.cache.get(e);i&&"singleton"===i.scope&&await i.invalidationSerializer.do((async()=>{i.version++,await this.cache.invalidateInstance(e),await this.cascadeInvalidation(this.graph.iterDependents(e));const r=this.registry.get(e),n=r&&(t||!r.lazy||this.observer.hasWatchers(e))&&!s;n&&await this.build(e).catch((t=>{t instanceof $||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),(n||s)&&this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(0===e.size)return;const t=[];for(const s of e)t.push(this.invalidate(s).catch((e=>{console.error(`[ArtifactManager] Cascade failed for "${String(s)}":`,e)})));await Promise.all(t)}updateDependencyGraph(e,t,s){const i=this.cache.get(e);if(!i||"singleton"!==i.scope)return;this.graph.registerNode(e),this.graph.setDependencies(e,t),i.stateDependencies=new Set;for(const{paths:e}of s)for(const t of e)i.stateDependencies.add(t);if(i.stateUnsubscribe&&(i.stateUnsubscribe(),i.stateUnsubscribe=void 0),0===s.length)return;const r=()=>this.invalidate(e),n=new Map;for(const{paths:e,options:t}of s){const s=void 0===t?"undefined":JSON.stringify(t);let i=n.get(s);i||(i={options:t,paths:new Set},n.set(s,i));for(const t of e)i.paths.add(t)}const a=[];for(const{options:e,paths:t}of n.values()){if(0===t.size)continue;const s=Array.from(t);void 0===e?a.push(this.store.watch(s,r)):a.push(this.store.watch(s,r,e))}0===a.length?i.stateUnsubscribe=void 0:1===a.length?i.stateUnsubscribe=a[0]:i.stateUnsubscribe=()=>{for(const e of a)e()}}createCachedArtifact(e){return"transient"===e.scope?{scope:"transient",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:"singleton",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce?e.debounce:0,controller:new AbortController,buildOnce:new p({retry:!0,throws:!0}),streamOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateGroups:[],artifactDependencies:new Set}}resolveStatic(e){if(!this.registry.has(e))throw new C(e);return this.build(e)}async resolveParameterized(e,t){if(!this.registry.has(e))throw new C(String(e));const s=this.registry.get(e);if(!s.paramKey)throw new x(`Artifact "${String(e)}" is not parameterized.`,"external");const i=s.paramKey(t),r=this.registry.getByString(i);if(r&&!r.paramKey&&!r.virtual)throw new x(`Parameterized artifact "${String(e)}" with params ${JSON.stringify(t)} resolves to key "${i}" which is already registered as a static artifact.`,"system");return this.registry.hasString(i)||this.registry.setVirtual(i,{key:i,factory:e=>s.factory({...e,params:t}),scope:s.scope,lazy:s.lazy,timeout:s.timeout,retries:s.retries,debounce:s.debounce,virtual:!0}),this.build(i,void 0,e)}computeParamKey(e,t){const s=this.registry.get(e);if(!s.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);return s.paramKey(t)}},M=class{constructor(e,t,s){this.registry=e,this.cache=t,this.container=s}listeners=new Map;watchers=new Map;watch(e,t=6e4){return this.watchForKey(e,this.registry.get(e),t)}watchParameterized(e,t,s=6e4){const i=this.registry.get(e);if(!i.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);const r=i.paramKey(t);return this.watchForKey(r,i,s,t)}watchForKey(e,t,s,i){const r="transient"===t.scope,n=r?v(e):e,a=this.watchers.get(n);if(a)return a.observer;const o=new y((async()=>{!r&&void 0===i||this.registry.hasString(e)||this.registry.setVirtual(e,{key:e,factory:r?t.factory:e=>t.factory({...e,params:i}),scope:r?"singleton":t.scope,lazy:t.lazy,timeout:t.timeout,retries:t.retries,debounce:t.debounce,paramKey:t.paramKey,virtual:!0})}),(async()=>{r||void 0!==i?(await this.registry.unregister(n).catch((()=>{})),this.cache.delete(n),this.watchers.delete(n)):this.cache.invalidatePackage(n),this.listeners.delete(n)}),{gracePeriod:r&&void 0===i?"sync":s});let c;const h={id:n,get count(){return o.subscribers},get:(t=!1)=>0!==o.subscribers||t?this.cache.package(n,((e,t)=>this.container.invalidate(n,e,t)),e):b,resolve:()=>c||(c=(async()=>{await o.acquire();try{return await this.container.resolve(n)}finally{o.release(),c=void 0}})(),c),subscribe:(e,t=!0)=>{const s=()=>e(h.get());return o.acquire().then((()=>{this.container.resolve(n).then((()=>{this.listeners.has(n)||this.listeners.set(n,new Set),t&&s(),this.listeners.get(n).add(s)}))})).catch((e=>{console.error(`[ArtifactObserver] Resolution failed for "${n}":`,e),this.listeners.get(n)?.add(s)})),()=>{this.listeners.get(n)?.delete(s),o.release()}}};return this.watchers.set(n,{resource:o,observer:h}),h}evictWatcher(e){[e,v(e)].forEach((e=>{const t=this.watchers.get(e);t&&(t.resource.forceCleanup(),this.watchers.delete(e))}))}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const s of t)try{s()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return this.watchers.has(e)||this.watchers.has(v(e))}getWatcherCount(e){const t=this.watchers.get(e)||this.watchers.get(v(e));return t?.resource.subscribers??0}clear(){this.watchers.clear(),this.listeners.clear()}},T=class{artifacts=new Map;register({key:e,factory:t,lazy:s,...i}){const{scope:r,...n}=i,a={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===s||s,...n};return this.artifacts.set(e,a),()=>this.unregister(e)}setVirtual(e,t){this.artifacts.set(e,t)}get(e){if(!this.has(e))throw new C(String(e));return this.artifacts.get(e)}getByString(e){return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}hasString(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()}},L=class e{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t),subset:(...t)=>e.subset(...t)},this.registry=new T,this.cache=new I,this.graph=new E,this.observer=new M(this.registry,this.cache,this),this.manager=new P(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const s=t,i=this.registry.get(s),r=this.cache.get(s);if(!i)return;let n="idle";r&&("singleton"===r.scope&&void 0!==r.debounceTimer?n="debouncing":"singleton"===r.scope&&r.buildOnce.running()?n="building":r.error?n="error":void 0!==r.instance&&(n="active")),e.push({id:s,scope:i.scope??"singleton",status:n,dependencies:this.graph.getDependencies(s).map((e=>String(e))),dependents:this.graph.getDependents(s).map((e=>String(e))),stateDependencies:"singleton"===r?.scope?Array.from(r.stateDependencies):[],buildCount:r?.buildCount??0})})),e}register(e){const{key:t}=e,s=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${s}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${s}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const i=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==i||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${s}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;await this.manager.dispose(s),await this.registry.unregister(s),this.observer.evictWatcher(s)}async resolve(e,t){return void 0===t?this.manager.resolveStatic(e):this.manager.resolveParameterized(e,t)}async require(e,t){const s=await this.resolve(e,t);if(s.error)throw s.error;return s.instance}watch(e,t,s){return void 0===t?this.observer.watch(e,s):this.observer.watchParameterized(e,t,s)}peek(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;return this.cache.get(s)?.instance}async invalidate(e,t){const s=t?.params,i=t?.replace??!1,r=void 0!==s?this.manager.computeParamKey(e,s):e;return this.manager.invalidate(r,i)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((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()}async export(){const e=[];for(const t of this.cache.keys()){const s=this.cache.get(t);if(!s||"singleton"!==s.scope)continue;if(void 0===s.instance)continue;const i=new Set;for(const e of s.stateGroups)for(const t of e.paths)i.add(t);const r=Array.from(i).sort(),n=this.store.subset(r),a=await k(JSON.stringify(n,Object.keys(n).sort()));let o;try{o=structuredClone(s.instance)}catch(e){throw new R(t)}e.push({key:t,instance:o,state:{groups:s.stateGroups.map((e=>({paths:e.paths,options:e.options}))),hash:a},dependencies:Array.from(s.artifactDependencies)})}const t={...{version:"1.0",timestamp:Date.now(),artifacts:e}},s=JSON.stringify(t),i=await k(s);return{...t,checksum:i}}async restore(e){const{checksum:t,...s}=e;if(await k(JSON.stringify(s))!==t)throw new D("Bundle checksum mismatch – data corrupted");if("1.0"!==e.version)throw new D(`Unsupported bundle version: ${e.version}`);const i=new Map;for(const t of e.artifacts)i.set(t.key,t);const r=new Set,n=new Map;for(const t of e.artifacts)for(const e of t.dependencies)n.has(e)||n.set(e,new Set),n.get(e).add(t.key);const a=async e=>{const t=new Set;for(const s of e.state.groups)for(const e of s.paths)t.add(e);const s=Array.from(t).sort(),i=this.store.subset(s);return k(JSON.stringify(i,Object.keys(i).sort()))};for(const t of e.artifacts){await a(t)!==t.state.hash&&r.add(t.key)}const o=Array.from(r);for(;o.length;){const e=o.shift(),t=n.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),o.push(e))}for(const t of e.artifacts){if(r.has(t.key))continue;this.cache.get(t.key)&&await this.cache.invalidateInstance(t.key,!1);const e={scope:"singleton",instance:t.instance,error:void 0,version:1,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set(t.state.groups.flatMap((e=>e.paths))),activeDebounceMs:0,buildOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateUnsubscribe:void 0,debounceTimer:void 0,controller:new AbortController,streamOnce:new p({retry:!0,throws:!0}),stream:void 0,stateGroups:t.state.groups,artifactDependencies:new Set(t.dependencies)};e.buildOnce.resolve(t.instance),this.cache.set(t.key,e);const s=[];for(const e of t.state.groups){const i=this.store.watch(e.paths,(()=>this.invalidate(t.key)),e.options);s.push(i)}e.stateUnsubscribe=()=>{for(const e of s)e()},this.graph.setDependencies(t.key,t.dependencies)}}static async from(t){const s=new e(t.store);if(t.bundle){if("object"!=typeof t.bundle||!t.bundle.version||!Array.isArray(t.bundle.artifacts))throw new D("Invalid bundle: missing version or artifacts array");await s.restore(t.bundle)}for(const e of t.templates)s.register(e);return s}};function F(e){return"object"==typeof e&&null!==e&&"pause"in e}var K="__pipeline_data__";var z={info:()=>{},error:()=>{}},B=class{constructor(e,t,s,i,r,n,a,o,c,h,d,u,l,p){this.pipeline=t,this.entry=s,this.store=i,this.container=r,this.keyPrefix=n,this.bus=a,this.parentPath=o,this.controller=c,this.once=h,this.logger=d,this.definitionId=u,this.index=l,this.factory=p,this.id=e,this.__registryContainer=r,this.__registryPipelineId=u}id;__registryContainer;__registryPipelineId;on(e,t){return this.bus.on(e,t)}abort(){this.controller.abort()}async run(){const e=await this.once.do((()=>this.execute()));return void 0!==e.error?c(new r({code:s.INTERNAL_ERROR.code,message:`Unexpected throw escaped run(): ${Y(e.error)}`,operation:`pipeline:${this.pipeline.id}`,cause:e.error})):e.value}async execute(){this.bus.emit("pipeline:start",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id}),this.logger.info(`Pipeline start: ${this.pipeline.id} [${this.id}]`);const e=this.resolveEntryStage();if(!e.ok)return this.failPipeline(e.error);const{stageMap:t,orderedStages:i,stageOrderIndex:n}=this.index;let a=e.value,c=!0;for(;;){if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted before stage "${a.label}".`,operation:`stage:${a.id}`});return this.failPipeline(e)}const e=c?this.entry:void 0;c=!1;const h=await this.executeStage(a,e);if(!h.ok)return this.failPipeline(h.error);if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted after stage "${a.label}".`,operation:`stage:${a.id}`});return this.failPipeline(e)}const d=h.value,u="pause"===d.kind?void 0:d.nextInstruction,l=n.get(a.id)??-1,p=void 0!==i[l+1],g="pause"===d.kind?"pause":null===u?"terminate":"string"==typeof u?"jump":p?"advance":"natural-end";if(this.bus.emit("router:evaluated",{path:this.parentPath,stageId:a.id,stageLabel:a.label,runId:this.id,instruction:u,interpretation:g}),"pause"===d.kind){const{checkpoint:e,pauseTimeout:t}=d,s=this.store.get(!0);return this.logger.info(`Pipeline paused: ${this.pipeline.id} [${this.id}] at stage "${e.pausedAtStageId}"`+(void 0!==t?` (timeout: ${t}ms)`:"")),this.bus.emit("pipeline:paused",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,checkpoint:e,finalState:s,pauseTimeout:t}),o({status:"paused",runId:this.id,finalState:s,checkpoint:e})}if(null===u)break;if("string"==typeof u){const e=t.get(u);if(!e){const e=new r({code:s.INVALID_COMMAND.code,message:`Router on stage "${a.label}" returned unknown stageId: "${u}"`,operation:`stage:${a.id}`});return this.failPipeline(e)}a=e;continue}const f=i[l+1];if(!f)break;a=f}const h=this.store.get(!0);return this.logger.info(`Pipeline succeeded: ${this.pipeline.id} [${this.id}]`),this.bus.emit("pipeline:success",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,finalState:h}),o({status:"succeeded",runId:this.id,finalState:h})}resolveEntryStage(){const{stageMap:e,orderedStages:t}=this.index;if(this.entry?.stage){const t=e.get(this.entry.stage);return t?o(t):c(new r({code:s.INVALID_COMMAND.code,message:`Entry stage "${this.entry.stage}" not found.`,operation:`pipeline:${this.pipeline.id}`}))}const i=t[0];return i?o(i):c(new r({code:s.INVALID_COMMAND.code,message:"Pipeline has no stages.",operation:`pipeline:${this.pipeline.id}`}))}async executeStage(e,t){const s=e.pipelines&&e.pipelines.length>0?"pipelines":"steps",i=[...this.parentPath,{kind:"stage",id:e.id,label:e.label}];this.bus.emit("stage:start",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,mode:s});const r="pipelines"===s?await this.executePipelinesStage(e,i,t):await this.executeStepsStage(e,i,t);return r.ok?"pause"===r.value.kind?this.bus.emit("stage:paused",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,checkpoint:r.value.checkpoint}):this.bus.emit("stage:success",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,nextInstruction:r.value.nextInstruction}):this.bus.emit("stage:failure",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,error:r.error}),r}async executeStepsStage(e,t,i){const n=Object.values(e.steps??{});if(0===n.length){this.logger.info(`Stage "${e.label}" has no steps — skipping.`);const t=q(e.router,this.store.get(!0),{});return o(W(t))}if(this.controller.signal.aborted)return c(new r({code:s.OPERATION_ABORTED.code,message:`Aborted before resolving steps in stage "${e.label}".`,operation:`stage:${e.id}`}));const a=void 0!==i?.step?n.filter((e=>e.id===i.step)):n;if(void 0!==i?.step&&0===a.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry step "${i.step}" not found in stage "${e.label}".`,operation:`stage:${e.id}`}));for(const e of a)this.bus.emit("step:start",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id});const h=await Promise.all(a.map((async t=>({step:t,result:await this.container.resolve(V(this.keyPrefix,e.id,t.id))})))),d={};for(const{step:e,result:i}of h)i.ready?(this.bus.emit("step:success",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id}),d[e.id]=o(i.instance)):(this.bus.emit("step:failure",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id,error:i.error}),d[e.id]=c(new r({code:s.BACKEND_ERROR.code,message:Y(i.error)})));const u=h.find((({result:e})=>!e.ready));if(u){const e=u.result.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Step "${u.step.label}" failed: ${Y(e)}`,operation:`step:${u.step.id}`,cause:e}))}const l=h.map((({result:e})=>e.instance)).filter((e=>null!=e));let p;try{await this.store.transaction((async()=>{for(const e of l)await this.store.set(e);const t=q(e.router,this.store.get(!0),d);if(F(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await G(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=W(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed during stage "${e.label}": ${Y(t)}`,operation:`stage:${e.id}`,cause:t}))}return o(p)}async executePipelinesStage(e,t,i){const n=e.pipelines,a=void 0!==i?.pipeline?(()=>{const{index:e}=i.pipeline,t=n[e];return t?[{subPipeline:t,originalIndex:e}]:[]})():n.map(((e,t)=>({subPipeline:e,originalIndex:t})));if(void 0!==i?.pipeline&&0===a.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry sub‑pipeline index ${i.pipeline.index} out of bounds.`,operation:`stage:${e.id}`}));this.bus.emit("subpipeline:fork",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,subPipelineIds:a.map((({subPipeline:e})=>e.id))});const h=await Promise.all(a.map((async({subPipeline:s,originalIndex:r})=>{const n=void 0!==i?.pipeline?{stage:i.pipeline.stage,step:i.pipeline.step}:void 0,a=function(e,t,s){const i=`${t}:pipeline-${s}`;return e?`${e}:${i}`:i}(this.keyPrefix,e.id,r);return{subPipeline:s,originalIndex:r,ctx:await this.factory.buildRunContext(this.id,s,n,this.store,this.bus,t,this.container,a)}}))),d=()=>{h.forEach((({ctx:e})=>e.abort()))};this.controller.signal.addEventListener("abort",d,{once:!0});try{if(this.controller.signal.aborted)return d(),c(new r({code:s.OPERATION_ABORTED.code,message:this.controller.signal.reason,operation:`stage:${e.id}`}));const i=await Promise.all(h.map((({ctx:e})=>e.run()))),n={};for(let e=0;e<a.length;e++)n[a[e].subPipeline.id]=i[e];this.bus.emit("subpipeline:join",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,results:n});const u=i.findIndex((e=>!e.ok||"failed"===e.value.status));if(-1!==u){const t=a[u].subPipeline.id,n=i[u],o=n.ok?n.value.error:n.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Sub‑pipeline "${t}" failed: ${Y(o)}`,operation:`stage:${e.id}`,cause:o}))}const l=i.findIndex((e=>e.ok&&"paused"===e.value.status));if(-1!==l){const t=i[l].value,{checkpoint:n}=t,h={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:e.id,pipeline:{index:a[l].originalIndex,stage:n.resumeAt.stage,step:n.resumeAt.step}},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};try{await this.store.transaction((async()=>{await G(this.store,h)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Failed to write parent pause checkpoint for stage "${e.label}".`,operation:`stage:${e.id}`,cause:t}))}return o({kind:"pause",checkpoint:h,pauseTimeout:void 0})}let p;try{await this.store.transaction((async()=>{const t=q(e.pipelinesRouter,this.store.get(!0),n);if(F(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await G(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=W(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed evaluating router for stage "${e.label}": ${Y(t)}`,operation:`stage:${e.id}`,cause:t}))}return o(p)}finally{this.controller.signal.removeEventListener("abort",d)}}failPipeline(e){return this.bus.emit("pipeline:failure",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,error:e}),c(e)}};function U(e){const t=[...e.stages].sort(((e,t)=>e.order-t.order)),s=new Map,i=new Map;for(let e=0;e<t.length;e++){const r=t[e];s.set(r.id,r),i.set(r.id,e)}return{stageMap:s,orderedStages:t,stageOrderIndex:i}}function j(e,t,s){const i=[];for(const r of e.stages)if(r.steps)for(const e of Object.values(r.steps)){const n={runId:s.runId,pipelineId:s.pipelineId,stageId:r.id,stepId:e.id,signal:s.signal};i.push({key:V(t,r.id,e.id),factory:t=>e.action(t,n),scope:e.scope,...void 0!==e.timeout&&{timeout:e.timeout},...void 0!==e.retries&&{retries:e.retries}})}return i}function V(e,t,s){return e?`${e}:${t}:${s}`:`${t}:${s}`}function q(e,t,s){return e?e(t,s):void 0}function W(e){return{kind:"advance",nextInstruction:e}}function Y(e){return e instanceof Error?e.message:String(e)}async function G(e,t){const s=e,i=t.pipelineId,r=t.runId,n=s.get(!0)[K]??{},a={...n,[i]:{...n[i]??{},[r]:t}};await s.set({[K]:a})}function J(e,t,s){const i=e.get(!0)[K];if(t)return i?.[t]?.[s]??null;if(i)for(const e in i){const t=i[e][s];if(t)return t}return null}exports.PIPELINE_DATA_KEY=K,exports.Pipeline=class{steps=new Map;globalBus=e.createEventBus();serializer=new g;executions=new Map;constructor(e){e&&e.forEach(((e,t)=>{(Array.isArray(e)?e:[e]).forEach((e=>this.steps.set(e.key,{...e,order:t})))}))}getSteps(){return this.steps}step(e){return this.steps.set(e.key,e),this}on(e,t){return this.globalBus.subscribe(e,t)}prepare(e,t,s,i){return new f(this,e,t,s?.signal,i)}async execute(e,t,s){const i=s?.disableDeduplication?`${e}:${Date.now()}:${Math.random()}`:this.getDedupeKey(e,t);let r=this.executions.get(i);r||(r=new p({retry:!0,throws:!1}),this.executions.set(i,r));const n=await r.do((async()=>{const i=await this.serializer.do((async()=>{const i=this.prepare(e,t,{signal:s?.signal},this.globalBus);return await i.run()}));if(i.error)throw i.error;return i.value})).finally((()=>{setTimeout((()=>this.executions.delete(i)),0)}));return n.error?c(n.error):n.value}getRegisteredSteps(){return Array.from(this.steps.keys())}validate(){const e=[];return 0===this.steps.size&&e.push("Pipeline has no registered steps"),e}destroy(){this.steps.clear(),this.globalBus.clear(),this.executions.clear()}groupByOrder(){const e=new Map;for(const t of this.steps.values()){const s=e.get(t.order)??[];s.push(t),e.set(t.order,s)}return e}getDedupeKey(e,t){try{return`${e}:${JSON.stringify(this.sortObjectKeys(t))}`}catch{return`${e}:${Date.now()}:${Math.random()}`}}sortObjectKeys(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map((e=>this.sortObjectKeys(e)));const t={};return Object.keys(e).sort().forEach((s=>{t[s]=this.sortObjectKeys(e[s])})),t}},exports.PipelineFactory=class{constructor(e,t){this.definition=e,this.logger=t.logger??z,this.storeFactory=t.storeFactory,this.initialStateFactory=t.initialStateFactory,this.registry=t.registry,this.index=U(e)}logger;storeFactory;initialStateFactory;registry;index;async prepare(e,s){const i=s??t.v7(),r=await this.storeFactory(i);await r.ready();const n=this.initialStateFactory?.()??{};await r.set(n),this.logger.info(`Prepared new run "${i}" for pipeline "${this.definition.id}"`);const a=await this.buildRunContext(i,this.definition,e,r,void 0,[]);return this.registry?.register(a,r),a}async resume(e){const t=this.registry?.getLiveContext(e)??null;if(null!==t)return this.logger.info(`Resuming pipeline "${this.definition.id}" [${e}] from live registry context`),o(t);const i=await this.storeFactory(e),n=J(i,void 0,e);if(!n)return c(new r({code:s.NOT_FOUND.code,message:`No checkpoint found for runId "${e}".`,operation:"resume"}));if(n.pipelineId!==this.definition.id)return c(new r({code:s.INVALID_COMMAND.code,message:`Checkpoint runId "${e}" belongs to pipeline "${n.pipelineId}", not "${this.definition.id}" (mismatch-base).`,operation:"resume"}));this.logger.info(`Resuming pipeline "${this.definition.id}" [${e}] from store checkpoint at stage "${n.pausedAtStageId}"`);const a=await this.buildRunContext(e,this.definition,n.resumeAt,i,void 0,[],void 0,void 0,n.containerBundle);return this.registry?.register(a,i),o(a)}async buildRunContext(t,s,i,r,n,a,o,c,h){const d=void 0===o,u=c??"",l=new AbortController,g={runId:t,pipelineId:s.id,signal:l.signal};let f;h?f=await L.from({store:r,bundle:h,templates:j(s,u,g)}):(f=d?new L(r):o,function(e,t,s,i){for(const r of t.stages)if(r.steps)for(const t of Object.values(r.steps)){const n={runId:i.runId,pipelineId:i.pipelineId,stageId:r.id,stepId:t.id,signal:i.signal};e.register({key:V(s,r.id,t.id),factory:e=>t.action(e,n),scope:t.scope,...void 0!==t.timeout&&{timeout:t.timeout},...void 0!==t.retries&&{retries:t.retries}})}}(f,s,u,g));const y=function(e,t){return{emit(s,i){e.emit({name:s,payload:i}),t?.emit(s,i)},on:(t,s)=>e.subscribe(t,s)}}(e.createEventBus(),n),m=new p({retry:!1,throws:!1}),w=d?this.index:U(s);return new B(t,s,i,r,f,u,y,a,l,m,this.logger,this.definition.id,w,this)}},exports.SequentialExecutionContext=f,exports.clearCheckpoint=async function(e,t,s){const i=e,r=i.get(!0)[K]??{},n={...r[t]??{}};delete n[s];const a={...r,[t]:n};await i.set({[K]:a})},exports.isPauseInstruction=F,exports.readCheckpoint=J,exports.writeCheckpoint=G;
|
|
1
|
+
"use strict";var e=require("@asaidimu/utils-events"),t=require("uuid"),s={VALIDATION_FAILED:{code:"VAL-001",name:"VALIDATION_FAILED",description:"Input validation failed due to one or more invalid fields",category:"validation",httpStatus:400,logLevel:"warn"},REQUIRED_FIELD_MISSING:{code:"VAL-002",name:"REQUIRED_FIELD_MISSING",description:"A required field was not provided in the request",category:"validation",httpStatus:400,logLevel:"warn"},INVALID_FORMAT:{code:"VAL-003",name:"INVALID_FORMAT",description:"Field value does not match expected format",category:"validation",httpStatus:400,logLevel:"warn"},NOT_FOUND:{code:"DB-001-NF",name:"NOT_FOUND",description:"The requested resource could not be found",category:"database",httpStatus:404,logLevel:"info",action:"Verify the resource identifier exists before accessing"},DUPLICATE_KEY:{code:"DB-002-DUP",name:"DUPLICATE_KEY",description:"A unique constraint violation occurred",category:"database",httpStatus:409,logLevel:"warn",action:"Check if the resource already exists before creation"},RESOURCE_LOCKED:{code:"DB-003-LOCK",name:"RESOURCE_LOCKED",description:"The resource is currently locked by another operation",category:"database",httpStatus:409,logLevel:"warn",action:"Retry the operation after a brief delay"},PERMISSION_DENIED:{code:"AUTH-001-DENIED",name:"PERMISSION_DENIED",description:"The authenticated user lacks permission for this operation",category:"auth",httpStatus:403,logLevel:"warn",action:"Check user roles and permissions"},UNAUTHENTICATED:{code:"AUTH-002-UNAUTH",name:"UNAUTHENTICATED",description:"Authentication is required for this operation",category:"auth",httpStatus:401,logLevel:"info",action:"Provide valid authentication credentials"},INVALID_COMMAND:{code:"BUS-001",name:"INVALID_COMMAND",description:"The command or operation is invalid for the current state",category:"business",httpStatus:400,logLevel:"warn"},OPERATION_ABORTED:{code:"BUS-002-ABORT",name:"OPERATION_ABORTED",description:"The operation was explicitly aborted",category:"business",httpStatus:409,logLevel:"info"},INTERNAL_ERROR:{code:"SYS-001",name:"INTERNAL_ERROR",description:"An unexpected internal error occurred",category:"system",httpStatus:500,logLevel:"error",action:"Check system logs for stack traces and diagnostic information"},BACKEND_ERROR:{code:"SYS-002",name:"BACKEND_ERROR",description:"An error occurred in a backend service",category:"system",httpStatus:502,logLevel:"error"},CONCURRENCY_ERROR:{code:"CON-001",name:"CONCURRENCY_ERROR",description:"A concurrency conflict occurred during the operation",category:"concurrency",httpStatus:409,logLevel:"warn",action:"Retry the operation with updated data"}},i=new Map;var r=class e extends Error{code;codeMetadata;severity;path;operation;issues;cause;constructor(t){const r={...function(e){const t=Object.values(s).find((t=>t.code===e));if(t)return t;return i.get(e)||{code:e,name:e.replace(/-/g,"_"),description:`Unknown error: ${e}`,category:"custom",httpStatus:500,logLevel:"error",action:"Check if this error code is properly registered or handle as unknown error"}}(t.code),...t.metadata,code:t.code};super(t.message??r.description),this.name="SystemError",this.code=t.code,this.codeMetadata=r,this.severity=t.severity??"error",this.path=t.path,this.operation=t.operation,this.issues=t.issues??[],this.cause=t.cause,Object.setPrototypeOf(this,e.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,e)}withPath(t){return new e({code:this.code,message:this.message,severity:this.severity,path:t,operation:this.operation,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withOperation(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:t,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withIssue(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,t],cause:this.cause,metadata:this.codeMetadata})}withIssues(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,...t],cause:this.cause,metadata:this.codeMetadata})}withCause(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:this.issues,cause:t,metadata:this.codeMetadata})}getHttpStatus(){return this.codeMetadata.httpStatus}toLogEntry(){return{name:this.name,code:this.code,category:this.codeMetadata.category,message:this.message,path:this.path,operation:this.operation,issues:this.issues,cause:this.cause instanceof Error?this.cause.message:this.cause,stack:this.stack,timestamp:(new Date).toISOString()}}toString(){let e=`[${this.code}] ${this.message} (${this.codeMetadata.category})`;return this.path&&(e+=` at '${this.path}'`),this.operation&&(e+=` during '${this.operation}'`),this.issues.length>0&&(e+="\nIssues:\n"+this.issues.map(((e,t)=>` ${t+1}. ${e.message} [${e.code}]`)).join("\n")),this.cause&&(e+=`\nCause: ${this.cause instanceof Error?this.cause.message:String(this.cause)}`),e}},n="SYS-001",o=(e,t)=>new r({code:n,message:t,cause:e}),a=e=>({ok:!0,value:e}),c=e=>({ok:!1,error:e}),d=class e extends r{constructor(t,s){super({code:"SYNC_ERROR",message:t,cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},h=class e extends d{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},u=class e extends d{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},l=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}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 s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,r)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),r(new h("Mutex lock timed out"))}),e)}))])}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?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},p=class{mutex=new l({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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{this._value=await e(),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")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}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(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,r)=>{i=setTimeout((()=>r(new h(s))),t)}))])}},g=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new l({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new u};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,i=null;try{if(this._done)throw new u;i=await e(),this._lastValue=i,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:i,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},f=class{constructor(t,s,i,r,n){this.pipeline=t,this.stepKey=s,this.params=i,r&&(r.aborted&&this.controller.abort(),r.addEventListener("abort",(()=>this.controller.abort()))),this.localBus=n??e.createEventBus()}id=Math.random().toString(36).substring(2,9);localBus;controller=new AbortController;once=new p({retry:!1,throws:!1});get signal(){return this.controller.signal}on(e,t){return this.localBus.subscribe(e,t)}abort(){this.controller.abort()}async run(){const{value:e,error:t}=await this.once.do((()=>this._run()));return t?c(t):e}async _run(){const e=this.pipeline.getSteps().get(this.stepKey);if(!e)return{ok:!1,error:new r({code:s.INVALID_COMMAND.code,message:`No step registered with key "${this.stepKey}"`,operation:this.stepKey})};if(this.signal.aborted)return this.failCancelled("Pipeline execution aborted before initialization",this.stepKey);const t=this.pipeline.groupByOrder(),i=Array.from(t.entries()).sort((([e],[t])=>e-t)),n=e.order;this.emit("start",{stepKey:this.stepKey,executionId:this.id});let o={[this.stepKey]:this.params},a=o,c=!0;for(const[e,t]of i){if(e<n)continue;if(this.signal.aborted)return this.failCancelled(`Pipeline runtime aborted at stage ${e}`,this.stepKey);const s=c?t.filter((e=>e.key===this.stepKey)):t;if(c=!1,0===s.length)continue;const i=await this.runStage(s,o);if(!i.ok)return i;a=i.value,o={...o,...a},this.emit("stage:success",{order:e,executionId:this.id,carry:a})}return this.emit("terminate",{carry:a,executionId:this.id}),{ok:!0,value:a}}async runStage(e,t){const s=await Promise.all(e.map((async e=>{try{if(this.signal.aborted)return{step:e,result:this.failCancelled("Aborted mid-flight execution sequence",e.key)};const s=await e.action(t,this.signal);return{step:e,result:s}}catch(t){return{step:e,result:{ok:!1,error:t instanceof r?t:o(t,t instanceof Error?t.message:"Unexpected exception raised during step run")}}}}))),i={};let n=null;for(const{step:e,result:t}of s)if(t.ok)this.emit("step:success",{stepKey:e.key,executionId:this.id,result:t.value}),i[e.key]=t.value;else{const s=t.error.withOperation(e.key);this.emit("step:failure",{stepKey:e.key,executionId:this.id,error:s}),n||(n={ok:!1,error:s},this.emit("failure",{stepKey:e.key,executionId:this.id,error:s}))}return n||{ok:!0,value:i}}emit(e,t){this.localBus.emit({name:e,payload:t})}failCancelled(e,t){return{ok:!1,error:new r({code:"CANCELLED",message:e,operation:t})}}},y=class{constructor(e,t,s={}){this.factory=e,this.onCleanup=t,this.options=s}_count=0;init=new p({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask((()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())}))):void(this.cleanupTimer=setTimeout((()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()}),e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}};function m(e,t){if(!e.length)return;const s=e.slice(),i=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=s.length-1;e>=0;e--)try{await s[e]()}catch(t){console.error(`${i} Cleanup error at index ${e}:`,t)}}}async function w(e,t){const s=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${s} Cleanup error at index ${t}:`,e)}}function v(e){return`${e}__watched`}var b=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function k(e,t){let s;const i=new Promise(((e,i)=>{s=setTimeout((()=>i(new Error(`Timeout: ${t}ms`))),t)}));try{return Promise.race([e,i])}finally{clearTimeout(s)}}async function I(e){const t=(new TextEncoder).encode(e),s=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(s)).map((e=>e.toString(16).padStart(2,"0"))).join("")}var S=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,s){const i=this.get(e);if(!i)return b;if(i.package)return i.package;const r=e,n=m(i.cleanupFunctions,r),o="singleton"!==i.scope||void 0!==i.instance,a={instance:i.instance,error:i.error,ready:o,[s||e]:i.instance,cleanup:n,invalidate:t};return i.package=a,a}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const s=this.get(e);if(!s)return;const i=e;"singleton"===s.scope&&(s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),s.controller.abort(),await s.streamOnce.current(),s.streamSerializer.close(),s.stream=void 0,s.streamOnce=new p({retry:!0,throws:!0}),t||(s.streamSerializer=new g,s.controller=new AbortController)),await w(s.cleanupFunctions,i),await w(s.disposeFunctions,i),s.cleanupFunctions=[],s.disposeFunctions=[],"singleton"===s.scope&&(s.buildOnce=new p({retry:!0,throws:!0})),s.instance=void 0,s.error=void 0}},x=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const s of t)this.dependents.get(s)?.delete(e);const s=this.dependents.get(e);if(s)for(const t of s)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.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}iterDependents(e){return this.dependents.get(e)??A}setDependencies(e,t){this.registerNode(e);const s=this.dependencies.get(e),i=new Set(t);for(const t of s)i.has(t)||this.removeDependency(e,t);for(const t of i)s.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const s=[t],i=new Set([t]),r=new Map;for(;s.length>0;){const n=s.shift();if(n===e){const s=[];let i=e;for(;void 0!==i&&(s.push(i),i!==t);)i=r.get(i);return s.reverse(),s.unshift(e),s}const o=this.dependencies.get(n);if(o)for(const e of o)i.has(e)||(i.add(e),r.set(e,n),s.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const s of t)e.set(s,this.dependencies.get(s)?.size??0);const s=[];for(const[t,i]of e)0===i&&s.push(t);const i=[];for(;s.length>0;){const t=s.shift();i.push(t);const r=this.dependents.get(t);if(r)for(const t of r){const i=(e.get(t)||0)-1;e.set(t,i),0===i&&s.push(t)}}if(i.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return i}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,s){const i=new Set,r=new Set,n=[e];r.add(e),s&&i.add(e);const o="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=o.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),i.add(e),n.push(e))}return i}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const s=Array.from(t).join(", ");return`${String(e)} → [${s||"∅"}]`})).join("\n")}},A=new Set,_=class{graph;constructor(){this.graph=new x}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){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}setDependencies(e,t){const s=Array.from(t).map((e=>e));this.graph.setDependencies(e,s)}wouldCreateCycle(e,t,s){if(s?.has(t)){const e=Array.from(s),i=e.indexOf(t),r=e.slice(i);return r.push(t),r}const i=this.graph.wouldCreateCycle(e,t);return i||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()}},E=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];var $=class e extends Error{category;constructor(t,s,i){super(t,{cause:i}),this.name="ArtifactError",this.category=s,Object.setPrototypeOf(this,e.prototype)}},O=class extends ${constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},C=class extends ${constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},D=class extends ${constructor(e){super(e,"system"),this.name="InvalidImportError"}},R=class extends ${constructor(e){super(`Artifact "${e}" instance is not JSON-serializable (POJO are required for persistence)`,"system"),this.name="InvalidExportOperationError"}},P=(new AbortController).signal,T=class{constructor(e,t,s,i,r){this.registry=e,this.cache=t,this.graph=s,this.store=i,this.observer=r}async build(e,t,s){const i=this.cache.get(e);if("singleton"===i?.scope&&i.buildOnce.done())return this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s);const r=this.registry.getByString(e);if(!r)throw new O(e);const n=t??[];if(n.includes(e))throw new $(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${[...n,e].join(" -> ")}`,"system");n.push(e);let o=i;o||(o=this.createCachedArtifact(r),this.cache.set(e,o));try{if("transient"===o.scope)return this.executeBuild(r,o,n);const i=o;try{await i.buildOnce.do((()=>this.executeBuild(r,i,n)))}catch(i){if(i instanceof C)return this.build(e,t,s);throw i}return i.stream&&i.streamOnce.do(i.stream),this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s)}finally{n.pop()}}async executeBuild(e,t,s){const i=e.key,r=String(i),n="transient"===t.scope;t.buildCount++,"singleton"===t.scope&&(t.activeDebounceMs=e.debounce??0);const o={cleanupFunctions:[],disposeFunctions:[],capturedArtifactDeps:new Set,capturedStateSelectors:[],dependencyVersions:new Map},a=this.buildContext(e,t,s,r,o),c=await this.runWithRetries(e,a,o.dependencyVersions);if(this.commitResult(i,t,n,c,o),n){const e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[i]:e,cleanup:m(o.cleanupFunctions,r),invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${r}"`)}}}buildContext(e,t,s,i,r){const n=e.key,o="transient"===t.scope,{cleanupFunctions:a,disposeFunctions:c,capturedArtifactDeps:d,dependencyVersions:h,capturedStateSelectors:u}=r,l=async(e,t)=>{const r=t?this.computeParamKey(e,t):e;if(r===n)throw new $(`Artifact "${i}" depends on itself.`,"system");const o=this.graph.wouldCreateCycle(n,r);if(o)throw new $(`Adding dependency "${String(r)}" to "${i}" would create a cycle: ${o.join(" -> ")}`,"system");d.add(r);const a=await(t?this.resolveParameterized(e,t):this.build(e,s)),c=this.cache.get(r);return c&&h.set(r,c.version),a},p="singleton"===t.scope?t.controller.signal:P,g=async(e,t)=>{const s=await l(e,t);if(s.error)throw s.error;return s.instance},f=(e,t)=>{const s=function(e,t="."){const s=new Set,i=new Map,r=(e="")=>{if(i.has(e))return i.get(e);const n=new Proxy((()=>{}),{get:(i,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic, arithmetic, or string operations inside a selector.");if(E.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const o=e?`${e}${t}${n}`:n;return e&&s.delete(e),s.add(o),r(o)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions or methods.")}});return i.set(e,n),n};try{e(r())}catch(e){throw new Error(`Selector failed during path analysis. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(s)}(e);return u.push({paths:s,options:t}),e(this.store.get(!0))};return{state:()=>this.store.get(!0),previous:t.instance,signal:p,onCleanup:e=>a.push(e),onDispose:e=>c.push(e),use:e=>e({resolve:l,require:g,select:f}),stream:e=>{if(o)throw new $(`[ArtifactManager] Illegal stream on transient artifact "${i}"`,"system");const s=t,r=async(e,t=void 0)=>{await s.streamSerializer.do((async()=>{void 0!==s.stream&&(s.instance=e,s.error=t,s.version++,this.cache.invalidatePackage(n),await this.processStream(i))}))},a={value:()=>s.instance,get signal(){return s.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>r(e)};s.stream=async()=>{try{const t=await e(a);t&&s.cleanupFunctions.push(t)}catch(e){await r(void 0,e),await this.invalidate(n,!1,!0)}}}}}async runWithRetries(e,t,s){const i=t.signal,r=(e.retries??0)+1;let n=0;for(;n<r;)try{if(i.aborted)throw new C;const o=e.factory(t);let a;if(a=o instanceof Promise?e.timeout?await k(o,e.timeout):await o:o,i.aborted)throw new C;const c=this.detectStaleness(s);if(c){if(n++,s.clear(),n<r)continue;return{ok:!1,error:new $(`Build stale after all retries: dependency "${String(c)}" changed during build.`,"system")}}return{ok:!0,value:a}}catch(e){if(i.aborted||e instanceof C)throw new C;if(e instanceof $)throw e;if(n++,n>=r)return{ok:!1,error:e}}return{ok:!1,error:new Error("Build exhausted retry budget unexpectedly.")}}commitResult(e,t,s,i,r){const{cleanupFunctions:n,disposeFunctions:o,capturedArtifactDeps:a,capturedStateSelectors:c}=r;s||(this.updateDependencyGraph(e,a,c),t.cleanupFunctions=n,t.disposeFunctions=o,t.artifactDependencies=new Set(a),t.stateGroups=c.map((({paths:e,options:t})=>({paths:e,options:t})))),i.ok?(t.instance=i.value,t.error=void 0):(t.instance=void 0,t.error=i.error),t.version++,this.cache.invalidatePackage(e)}detectStaleness(e){for(const[t,s]of e){const e=this.cache.get(t);if(e&&e.version!==s)return t}return null}async invalidate(e,t=!1,s=!1){const i=this.cache.get(e);if(!i)return;if("singleton"!==i.scope)return this.executeInvalidation(e,t,s);const r=i;return r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0),!t&&r.activeDebounceMs>0?new Promise(((i,n)=>{r.debounceTimer=setTimeout((()=>{r.debounceTimer=void 0,this.executeInvalidation(e,t,s).then(i).catch(n)}),r.activeDebounceMs)})):this.executeInvalidation(e,t,s)}async executeInvalidation(e,t,s=!1){const i=this.cache.get(e);i&&"singleton"===i.scope&&await i.invalidationSerializer.do((async()=>{i.version++,await this.cache.invalidateInstance(e),await this.cascadeInvalidation(this.graph.iterDependents(e));const r=this.registry.get(e),n=r&&(t||!r.lazy||this.observer.hasWatchers(e))&&!s;n&&await this.build(e).catch((t=>{t instanceof C||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),(n||s)&&this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(0===e.size)return;const t=[];for(const s of e)t.push(this.invalidate(s).catch((e=>{console.error(`[ArtifactManager] Cascade failed for "${String(s)}":`,e)})));await Promise.all(t)}updateDependencyGraph(e,t,s){const i=this.cache.get(e);if(!i||"singleton"!==i.scope)return;this.graph.registerNode(e),this.graph.setDependencies(e,t),i.stateDependencies=new Set;for(const{paths:e}of s)for(const t of e)i.stateDependencies.add(t);if(i.stateUnsubscribe&&(i.stateUnsubscribe(),i.stateUnsubscribe=void 0),0===s.length)return;const r=()=>this.invalidate(e),n=new Map;for(const{paths:e,options:t}of s){const s=void 0===t?"undefined":JSON.stringify(t);let i=n.get(s);i||(i={options:t,paths:new Set},n.set(s,i));for(const t of e)i.paths.add(t)}const o=[];for(const{options:e,paths:t}of n.values()){if(0===t.size)continue;const s=Array.from(t);void 0===e?o.push(this.store.watch(s,r)):o.push(this.store.watch(s,r,e))}0===o.length?i.stateUnsubscribe=void 0:1===o.length?i.stateUnsubscribe=o[0]:i.stateUnsubscribe=()=>{for(const e of o)e()}}createCachedArtifact(e){return"transient"===e.scope?{scope:"transient",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:"singleton",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce?e.debounce:0,controller:new AbortController,buildOnce:new p({retry:!0,throws:!0}),streamOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateGroups:[],artifactDependencies:new Set}}resolveStatic(e){if(!this.registry.has(e))throw new O(e);return this.build(e)}async resolveParameterized(e,t){if(!this.registry.has(e))throw new O(String(e));const s=this.registry.get(e);if(!s.paramKey)throw new $(`Artifact "${String(e)}" is not parameterized.`,"external");const i=s.paramKey(t),r=this.registry.getByString(i);if(r&&!r.paramKey&&!r.virtual)throw new $(`Parameterized artifact "${String(e)}" with params ${JSON.stringify(t)} resolves to key "${i}" which is already registered as a static artifact.`,"system");return this.registry.hasString(i)||this.registry.setVirtual(i,{key:i,factory:e=>s.factory({...e,params:t}),scope:s.scope,lazy:s.lazy,timeout:s.timeout,retries:s.retries,debounce:s.debounce,virtual:!0}),this.build(i,void 0,e)}computeParamKey(e,t){const s=this.registry.get(e);if(!s.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);return s.paramKey(t)}},N=class{constructor(e,t,s){this.registry=e,this.cache=t,this.container=s}listeners=new Map;watchers=new Map;watch(e,t=6e4){return this.watchForKey(e,this.registry.get(e),t)}watchParameterized(e,t,s=6e4){const i=this.registry.get(e);if(!i.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);const r=i.paramKey(t);return this.watchForKey(r,i,s,t)}watchForKey(e,t,s,i){const r="transient"===t.scope,n=r?v(e):e,o=this.watchers.get(n);if(o)return o.observer;const a=new y((async()=>{!r&&void 0===i||this.registry.hasString(e)||this.registry.setVirtual(e,{key:e,factory:r?t.factory:e=>t.factory({...e,params:i}),scope:r?"singleton":t.scope,lazy:t.lazy,timeout:t.timeout,retries:t.retries,debounce:t.debounce,paramKey:t.paramKey,virtual:!0})}),(async()=>{r||void 0!==i?(await this.registry.unregister(n).catch((()=>{})),this.cache.delete(n),this.watchers.delete(n)):this.cache.invalidatePackage(n),this.listeners.delete(n)}),{gracePeriod:r&&void 0===i?"sync":s});let c;const d={id:n,get count(){return a.subscribers},get:(t=!1)=>0!==a.subscribers||t?this.cache.package(n,((e,t)=>this.container.invalidate(n,e,t)),e):b,resolve:()=>c||(c=(async()=>{await a.acquire();try{return await this.container.resolve(n)}finally{a.release(),c=void 0}})(),c),subscribe:(e,t=!0)=>{const s=()=>e(d.get());return a.acquire().then((()=>{this.container.resolve(n).then((()=>{this.listeners.has(n)||this.listeners.set(n,new Set),t&&s(),this.listeners.get(n).add(s)}))})).catch((e=>{console.error(`[ArtifactObserver] Resolution failed for "${n}":`,e),this.listeners.get(n)?.add(s)})),()=>{this.listeners.get(n)?.delete(s),a.release()}}};return this.watchers.set(n,{resource:a,observer:d}),d}evictWatcher(e){[e,v(e)].forEach((e=>{const t=this.watchers.get(e);t&&(t.resource.forceCleanup(),this.watchers.delete(e))}))}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const s of t)try{s()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return this.watchers.has(e)||this.watchers.has(v(e))}getWatcherCount(e){const t=this.watchers.get(e)||this.watchers.get(v(e));return t?.resource.subscribers??0}clear(){this.watchers.clear(),this.listeners.clear()}},M=class{artifacts=new Map;register({key:e,factory:t,lazy:s,...i}){const{scope:r,...n}=i,o={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===s||s,...n};return this.artifacts.set(e,o),()=>this.unregister(e)}setVirtual(e,t){this.artifacts.set(e,t)}get(e){if(!this.has(e))throw new O(String(e));return this.artifacts.get(e)}getByString(e){return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}hasString(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()}},L=class e{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t),subset:(...t)=>e.subset(...t)},this.registry=new M,this.cache=new S,this.graph=new _,this.observer=new N(this.registry,this.cache,this),this.manager=new T(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const s=t,i=this.registry.get(s),r=this.cache.get(s);if(!i)return;let n="idle";r&&("singleton"===r.scope&&void 0!==r.debounceTimer?n="debouncing":"singleton"===r.scope&&r.buildOnce.running()?n="building":r.error?n="error":void 0!==r.instance&&(n="active")),e.push({id:s,scope:i.scope??"singleton",status:n,dependencies:this.graph.getDependencies(s).map((e=>String(e))),dependents:this.graph.getDependents(s).map((e=>String(e))),stateDependencies:"singleton"===r?.scope?Array.from(r.stateDependencies):[],buildCount:r?.buildCount??0})})),e}register(e){const{key:t}=e,s=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${s}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${s}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const i=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==i||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${s}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;await this.manager.dispose(s),await this.registry.unregister(s),this.observer.evictWatcher(s)}async resolve(e,t){return void 0===t?this.manager.resolveStatic(e):this.manager.resolveParameterized(e,t)}async require(e,t){const s=await this.resolve(e,t);if(s.error)throw s.error;return s.instance}watch(e,t,s){return void 0===t?this.observer.watch(e,s):this.observer.watchParameterized(e,t,s)}peek(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;return this.cache.get(s)?.instance}async invalidate(e,t){const s=t?.params,i=t?.replace??!1,r=void 0!==s?this.manager.computeParamKey(e,s):e;return this.manager.invalidate(r,i)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((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()}async export(){const e=[];for(const t of this.cache.keys()){const s=this.cache.get(t);if(!s||"singleton"!==s.scope)continue;if(void 0===s.instance)continue;const i=new Set;for(const e of s.stateGroups)for(const t of e.paths)i.add(t);const r=Array.from(i).sort(),n=this.store.subset(r),o=await I(JSON.stringify(n,Object.keys(n).sort()));let a;try{a=structuredClone(s.instance)}catch(e){throw new R(t)}e.push({key:t,instance:a,state:{groups:s.stateGroups.map((e=>({paths:e.paths,options:e.options}))),hash:o},dependencies:Array.from(s.artifactDependencies)})}const t={...{version:"1.0",timestamp:Date.now(),artifacts:e}},s=JSON.stringify(t),i=await I(s);return{...t,checksum:i}}async restore(e){const{checksum:t,...s}=e;if(await I(JSON.stringify(s))!==t)throw new D("Bundle checksum mismatch – data corrupted");if("1.0"!==e.version)throw new D(`Unsupported bundle version: ${e.version}`);const i=new Map;for(const t of e.artifacts)i.set(t.key,t);const r=new Set,n=new Map;for(const t of e.artifacts)for(const e of t.dependencies)n.has(e)||n.set(e,new Set),n.get(e).add(t.key);const o=async e=>{const t=new Set;for(const s of e.state.groups)for(const e of s.paths)t.add(e);const s=Array.from(t).sort(),i=this.store.subset(s);return I(JSON.stringify(i,Object.keys(i).sort()))};for(const t of e.artifacts){await o(t)!==t.state.hash&&r.add(t.key)}const a=Array.from(r);for(;a.length;){const e=a.shift(),t=n.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),a.push(e))}for(const t of e.artifacts){if(r.has(t.key))continue;this.cache.get(t.key)&&await this.cache.invalidateInstance(t.key,!1);const e={scope:"singleton",instance:t.instance,error:void 0,version:1,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set(t.state.groups.flatMap((e=>e.paths))),activeDebounceMs:0,buildOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateUnsubscribe:void 0,debounceTimer:void 0,controller:new AbortController,streamOnce:new p({retry:!0,throws:!0}),stream:void 0,stateGroups:t.state.groups,artifactDependencies:new Set(t.dependencies)};e.buildOnce.resolve(t.instance),this.cache.set(t.key,e);const s=[];for(const e of t.state.groups){const i=this.store.watch(e.paths,(()=>this.invalidate(t.key)),e.options);s.push(i)}e.stateUnsubscribe=()=>{for(const e of s)e()},this.graph.setDependencies(t.key,t.dependencies)}}static async from(t){const s=new e(t.store);if(t.bundle){if("object"!=typeof t.bundle||!t.bundle.version||!Array.isArray(t.bundle.artifacts))throw new D("Invalid bundle: missing version or artifacts array");await s.restore(t.bundle)}for(const e of t.templates)s.register(e);return s}},F={info:()=>{},error:()=>{},warn:()=>{}},z=class e{static instances=new Map;static default=new e;static get(t,s){return e.instances.has(t)||e.instances.set(t,new e(s)),e.instances.get(t)}static destroy(t){const s=e.instances.get(t);s&&(s.dispose(),e.instances.delete(t))}defaultPauseTimeout;onExpired;onExportFailed;logger;records=new Map;weakIndex=new Map;finalizer=new FinalizationRegistry((e=>this.weakIndex.delete(e)));constructor(e={}){this.defaultPauseTimeout=e.defaultPauseTimeout??3e5,this.onExpired=e.onExpired,this.onExportFailed=e.onExportFailed,this.logger=e.logger??F}register(e,t){if(this.records.has(e.id))return void this.logger.info(`Run "${e.id}" already registered, skipping.`);const s=e.__registryContainer;s||this.logger.warn(`Run "${e.id}" does not expose __registryContainer — deferred export will be skipped.`);const i={runId:e.id,pipelineId:e.__registryPipelineId??"unknown",startedAt:(new Date).toISOString(),status:"prepared",pausedAt:void 0,checkpoint:void 0,context:e,store:t,container:s,cleanupTimer:void 0,unsubscribers:[]};i.unsubscribers.push(e.on("pipeline:start",(e=>this.onRun(e))),e.on("pipeline:paused",(e=>this.onPaused(e))),e.on("pipeline:success",(e=>this.onSucceeded(e.runId))),e.on("pipeline:failure",(e=>this.onFailed(e.runId)))),this.records.set(e.id,i);const r=new WeakRef(e);this.weakIndex.set(e.id,r),this.finalizer.register(e,e.id,r),this.logger.info(`Registered run "${e.id}" [${i.pipelineId}]`)}getCheckpoint(e){const t=this.records.get(e);return t&&"paused"===t.status?t.checkpoint??null:null}getLiveContext(e){const t=this.records.get(e);return t&&"paused"===t.status&&null!==t.context?(this.cancelTimer(t),this.logger.info(`Fast-path resume for run "${e}" — live context returned, timer cancelled.`),t.status="running",t.pausedAt=void 0,t.checkpoint=void 0,t.context):null}list(){return Array.from(this.records.values()).map(K)}listByStatus(e){return Array.from(this.records.values()).filter((t=>t.status===e)).map(K)}has(e){return this.records.has(e)}get(e){const t=this.records.get(e);return t?K(t):void 0}prune(){let e=0;for(const[t,s]of this.records)"succeeded"!==s.status&&"failed"!==s.status||null!==s.context?"paused"===s.status&&null===s.context&&(this.records.delete(t),e++):(this.records.delete(t),e++);e>0&&this.logger.info(`Pruned ${e} terminal run records.`)}dispose(){for(const e of this.records.values())this.cancelTimer(e),this.unwire(e),e.context=null;this.logger.info("Registry disposed.")}onRun(e){const t=this.records.get(e.runId);t?t.status="running":this.logger.warn(`pipeline:paused received for untracked run "${e.runId}".`)}onPaused(e){const t=this.records.get(e.runId);if(!t)return void this.logger.warn(`pipeline:paused received for untracked run "${e.runId}".`);t.status="paused",t.pausedAt=(new Date).toISOString(),t.checkpoint=e.checkpoint;const s=e.pauseTimeout??this.defaultPauseTimeout;this.logger.info(`Run "${e.runId}" paused. Cleanup timer armed for ${s}ms.`),0===s?this.runExpirySequence(t):t.cleanupTimer=setTimeout((()=>{this.runExpirySequence(t)}),s)}onSucceeded(e){const t=this.records.get(e);t&&(t.status="succeeded",this.cancelTimer(t),this.unwire(t),t.context=null,this.logger.info(`Run "${e}" succeeded. Strong reference released.`))}onFailed(e){const t=this.records.get(e);t&&(t.status="failed",this.cancelTimer(t),this.unwire(t),t.context=null,this.logger.info(`Run "${e}" failed. Strong reference released.`))}async runExpirySequence(e){const{runId:t}=e;if(this.logger.info(`Pause timeout expired for run "${t}". Running deferred export.`),null===e.context||null===e.checkpoint)return;const s=e.checkpoint;try{const i=await e.container.export(),r={...s,containerBundle:i};await Q(e.store,r),e.checkpoint=r,this.logger.info(`Deferred export complete for run "${t}". Checkpoint updated with bundle.`),this.releaseContext(e),this.onExpired?.(t,r)}catch(i){this.logger.error(`Deferred export failed for run "${t}". Clearing checkpoint.`,i);try{await Z(e.store,s.pipelineId,t)}catch(e){this.logger.error(`Failed to clear checkpoint for run "${t}" after export failure.`,e)}this.releaseContext(e),this.onExportFailed?.(t,i)}}cancelTimer(e){void 0!==e.cleanupTimer&&(clearTimeout(e.cleanupTimer),e.cleanupTimer=void 0)}unwire(e){for(const t of e.unsubscribers)try{t()}catch{}e.unsubscribers.length=0}releaseContext(e){e.context=null,this.weakIndex.delete(e.runId),this.logger.info(`Strong reference released for run "${e.runId}". Context is GC-eligible.`)}};function K(e){return{runId:e.runId,pipelineId:e.pipelineId,status:e.status,startedAt:e.startedAt,pausedAt:e.pausedAt,checkpoint:e.checkpoint,context:e.context}}function B(e){return"object"==typeof e&&null!==e&&"pause"in e}var U="__pipeline_data__",j="__pipeline_id__";var V=class{constructor(e,t,s,i,r,n,o,a,c,d,h,u,l,p){this.pipeline=t,this.entry=s,this.store=i,this.container=r,this.keyPrefix=n,this.bus=o,this.parentPath=a,this.controller=c,this.once=d,this.logger=h,this.definitionId=u,this.index=l,this.factory=p,this.id=e,this.__registryContainer=r,this.__registryPipelineId=u}id;__registryContainer;__registryPipelineId;on(e,t){return this.bus.on(e,t)}abort(){this.controller.abort()}dangerouslyReset(){this.once.reset()}setEntry(e){this.entry=e}async run(){const e=await this.once.do((()=>this.execute()));return void 0!==e.error?c(new r({code:s.INTERNAL_ERROR.code,message:`Unexpected throw escaped run(): ${H(e.error)}`,operation:`pipeline:${this.pipeline.id}`,cause:e.error})):e.value}async execute(){this.bus.emit("pipeline:start",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id}),this.logger.info(`Pipeline start: ${this.pipeline.id} [${this.id}]`);const e=this.resolveEntryStage();if(!e.ok)return this.failPipeline(e.error);const{stageMap:t,orderedStages:i,stageOrderIndex:n}=this.index;let o=e.value,c=!0;for(;;){if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted before stage "${o.label}".`,operation:`stage:${o.id}`});return this.failPipeline(e)}const e=c?this.entry:void 0;c=!1;const d=await this.executeStage(o,e);if(!d.ok)return this.failPipeline(d.error);if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted after stage "${o.label}".`,operation:`stage:${o.id}`});return this.failPipeline(e)}const h=d.value,u="pause"===h.kind?void 0:h.nextInstruction,l=n.get(o.id)??-1,p=void 0!==i[l+1],g="pause"===h.kind?"pause":null===u?"terminate":"string"==typeof u?"jump":p?"advance":"natural-end";if(this.bus.emit("router:evaluated",{path:this.parentPath,stageId:o.id,stageLabel:o.label,runId:this.id,instruction:u,interpretation:g}),"pause"===h.kind){const{checkpoint:e,pauseTimeout:t}=h,s=this.store.get(!0);return this.logger.info(`Pipeline paused: ${this.pipeline.id} [${this.id}] at stage "${e.pausedAtStageId}"`+(void 0!==t?` (timeout: ${t}ms)`:"")),this.bus.emit("pipeline:paused",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,checkpoint:e,finalState:s,pauseTimeout:t}),a({status:"paused",runId:this.id,finalState:s,checkpoint:e})}if(null===u)break;if("string"==typeof u){const e=t.get(u);if(!e){const e=new r({code:s.INVALID_COMMAND.code,message:`Router on stage "${o.label}" returned unknown stageId: "${u}"`,operation:`stage:${o.id}`});return this.failPipeline(e)}o=e;continue}const f=i[l+1];if(!f)break;o=f}const d=this.store.get(!0);return this.logger.info(`Pipeline succeeded: ${this.pipeline.id} [${this.id}]`),this.bus.emit("pipeline:success",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,finalState:d}),a({status:"succeeded",runId:this.id,finalState:d})}resolveEntryStage(){const{stageMap:e,orderedStages:t}=this.index;if(this.entry?.stage){const t=e.get(this.entry.stage);return t?a(t):c(new r({code:s.INVALID_COMMAND.code,message:`Entry stage "${this.entry.stage}" not found.`,operation:`pipeline:${this.pipeline.id}`}))}const i=t[0];return i?a(i):c(new r({code:s.INVALID_COMMAND.code,message:"Pipeline has no stages.",operation:`pipeline:${this.pipeline.id}`}))}async executeStage(e,t){const s=e.pipelines&&e.pipelines.length>0?"pipelines":"steps",i=[...this.parentPath,{kind:"stage",id:e.id,label:e.label}];this.bus.emit("stage:start",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,mode:s});const r="pipelines"===s?await this.executePipelinesStage(e,i,t):await this.executeStepsStage(e,i,t);return r.ok?"pause"===r.value.kind?this.bus.emit("stage:paused",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,checkpoint:r.value.checkpoint}):this.bus.emit("stage:success",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,nextInstruction:r.value.nextInstruction}):this.bus.emit("stage:failure",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,error:r.error}),r}async executeStepsStage(e,t,i){const n=Object.values(e.steps??{});if(0===n.length){this.logger.info(`Stage "${e.label}" has no steps — skipping.`);const t=G(e.router,this.store.get(!0),{});if(B(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};return await Q(this.store,s),a({kind:"pause",checkpoint:s,pauseTimeout:t.timeout})}return a(J(t))}if(this.controller.signal.aborted)return c(new r({code:s.OPERATION_ABORTED.code,message:`Aborted before resolving steps in stage "${e.label}".`,operation:`stage:${e.id}`}));const o=void 0!==i?.step?n.filter((e=>e.id===i.step)):n;if(void 0!==i?.step&&0===o.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry step "${i.step}" not found in stage "${e.label}".`,operation:`stage:${e.id}`}));for(const e of o)this.bus.emit("step:start",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id});const d=await Promise.all(o.map((async t=>({step:t,result:await this.container.resolve(Y(this.keyPrefix,e.id,t.id))})))),h={};for(const{step:e,result:i}of d)i.ready?(this.bus.emit("step:success",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id}),h[e.id]=a(i.instance)):(this.bus.emit("step:failure",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id,error:i.error}),h[e.id]=c(new r({code:s.BACKEND_ERROR.code,message:H(i.error)})));const u=d.find((({result:e})=>!e.ready));if(u){const e=u.result.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Step "${u.step.label}" failed: ${H(e)}`,operation:`step:${u.step.id}`,cause:e}))}const l=d.map((({result:e})=>e.instance)).filter((e=>null!=e));let p;try{await this.store.transaction((async()=>{for(const e of l)await this.store.set(e);const t=G(e.router,this.store.get(!0),h);if(B(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await Q(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=J(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed during stage "${e.label}": ${H(t)}`,operation:`stage:${e.id}`,cause:t}))}return a(p)}async executePipelinesStage(e,t,i){const n=e.pipelines,o=void 0!==i?.pipeline?(()=>{const{index:e}=i.pipeline,t=n[e];return t?[{subPipeline:t,originalIndex:e}]:[]})():n.map(((e,t)=>({subPipeline:e,originalIndex:t})));if(void 0!==i?.pipeline&&0===o.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry sub‑pipeline index ${i.pipeline.index} out of bounds.`,operation:`stage:${e.id}`}));this.bus.emit("subpipeline:fork",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,subPipelineIds:o.map((({subPipeline:e})=>e.id))});const d=await Promise.all(o.map((async({subPipeline:s,originalIndex:r})=>{const n=void 0!==i?.pipeline?{stage:i.pipeline.stage,step:i.pipeline.step}:void 0,o=function(e,t,s){const i=`${t}:pipeline-${s}`;return e?`${e}:${i}`:i}(this.keyPrefix,e.id,r);return{subPipeline:s,originalIndex:r,ctx:await this.factory.buildRunContext(this.id,s,n,this.store,this.bus,t,this.container,o)}}))),h=()=>{d.forEach((({ctx:e})=>e.abort()))};this.controller.signal.addEventListener("abort",h,{once:!0});try{if(this.controller.signal.aborted)return h(),c(new r({code:s.OPERATION_ABORTED.code,message:this.controller.signal.reason,operation:`stage:${e.id}`}));const i=await Promise.all(d.map((({ctx:e})=>e.run()))),n={};for(let e=0;e<o.length;e++)n[o[e].subPipeline.id]=i[e];this.bus.emit("subpipeline:join",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,results:n});const u=i.findIndex((e=>!e.ok||"failed"===e.value.status));if(-1!==u){const t=o[u].subPipeline.id,n=i[u],a=n.ok?n.value.error:n.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Sub‑pipeline "${t}" failed: ${H(a)}`,operation:`stage:${e.id}`,cause:a}))}const l=i.findIndex((e=>e.ok&&"paused"===e.value.status));if(-1!==l){const t=i[l].value,{checkpoint:n}=t,d={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:e.id,pipeline:{index:o[l].originalIndex,stage:n.resumeAt.stage,step:n.resumeAt.step}},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};try{await this.store.transaction((async()=>{await Q(this.store,d)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Failed to write parent pause checkpoint for stage "${e.label}".`,operation:`stage:${e.id}`,cause:t}))}return a({kind:"pause",checkpoint:d,pauseTimeout:void 0})}let p;try{await this.store.transaction((async()=>{const t=G(e.pipelinesRouter,this.store.get(!0),n);if(B(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await Q(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=J(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed evaluating router for stage "${e.label}": ${H(t)}`,operation:`stage:${e.id}`,cause:t}))}return a(p)}finally{this.controller.signal.removeEventListener("abort",h)}}failPipeline(e){return this.bus.emit("pipeline:failure",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,error:e}),c(e)}};function q(e){const t=[...e.stages].sort(((e,t)=>e.order-t.order)),s=new Map,i=new Map;for(let e=0;e<t.length;e++){const r=t[e];s.set(r.id,r),i.set(r.id,e)}return{stageMap:s,orderedStages:t,stageOrderIndex:i}}function W(e,t,s){const i=[];for(const r of e.stages)if(r.steps)for(const e of Object.values(r.steps)){const n={runId:s.runId,pipelineId:s.pipelineId,stageId:r.id,stepId:e.id,signal:s.signal};i.push({key:Y(t,r.id,e.id),factory:t=>e.action(t,n),scope:e.scope,...void 0!==e.timeout&&{timeout:e.timeout},...void 0!==e.retries&&{retries:e.retries}})}return i}function Y(e,t,s){return e?`${e}:${t}:${s}`:`${t}:${s}`}function G(e,t,s){return e?e(t,s):void 0}function J(e){return{kind:"advance",nextInstruction:e}}function H(e){return e instanceof Error?e.message:String(e)}async function Q(e,t){const s=e,i=t.pipelineId,r=t.runId,n=s.get(!0)[U]??{},o={...n,[i]:{...n[i]??{},[r]:t}};await s.set({[U]:o})}function X(e,t,s){const i=e.get(!0)[U];if(t)return i?.[t]?.[s]??null;if(i)for(const e in i){const t=i[e][s];if(t)return t}return null}async function Z(e,t,s){const i=e,r=i.get(!0)[U]??{},n={...r[t]??{}};delete n[s];const o={...r,[t]:n};await i.set({[U]:o})}exports.PIPELINE_DATA_KEY=U,exports.PIPELINE_RUN_ID_KEY=j,exports.Pipeline=class{steps=new Map;globalBus=e.createEventBus();serializer=new g;executions=new Map;constructor(e){e&&e.forEach(((e,t)=>{(Array.isArray(e)?e:[e]).forEach((e=>this.steps.set(e.key,{...e,order:t})))}))}getSteps(){return this.steps}step(e){return this.steps.set(e.key,e),this}on(e,t){return this.globalBus.subscribe(e,t)}prepare(e,t,s,i){return new f(this,e,t,s?.signal,i)}async execute(e,t,s){const i=s?.disableDeduplication?`${e}:${Date.now()}:${Math.random()}`:this.getDedupeKey(e,t);let r=this.executions.get(i);r||(r=new p({retry:!0,throws:!1}),this.executions.set(i,r));const n=await r.do((async()=>{const i=await this.serializer.do((async()=>{const i=this.prepare(e,t,{signal:s?.signal},this.globalBus);return await i.run()}));if(i.error)throw i.error;return i.value})).finally((()=>{setTimeout((()=>this.executions.delete(i)),0)}));return n.error?c(n.error):n.value}getRegisteredSteps(){return Array.from(this.steps.keys())}validate(){const e=[];return 0===this.steps.size&&e.push("Pipeline has no registered steps"),e}destroy(){this.steps.clear(),this.globalBus.clear(),this.executions.clear()}groupByOrder(){const e=new Map;for(const t of this.steps.values()){const s=e.get(t.order)??[];s.push(t),e.set(t.order,s)}return e}getDedupeKey(e,t){try{return`${e}:${JSON.stringify(this.sortObjectKeys(t))}`}catch{return`${e}:${Date.now()}:${Math.random()}`}}sortObjectKeys(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map((e=>this.sortObjectKeys(e)));const t={};return Object.keys(e).sort().forEach((s=>{t[s]=this.sortObjectKeys(e[s])})),t}},exports.PipelineFactory=class{constructor(e,t){this.definition=e,this.logger=t.logger??F,this.storeFactory=t.storeFactory,this.initialStateFactory=t.initialStateFactory,this.registry=t.registry||new z({logger:this.logger}),this.index=q(e)}logger;storeFactory;initialStateFactory;registry;index;async prepare(e,s){const i=s??t.v7(),r=await this.storeFactory(i);await r.ready();const n=this.initialStateFactory?.()??{};await r.set(n),await r.set({[j]:i}),this.logger.info(`Prepared new run "${i}" for pipeline "${this.definition.id}"`);const o=await this.buildRunContext(i,this.definition,e,r,void 0,[]);return this.registry?.register(o,r),o}async resume(e){if(this.registry?.has(e)){const t=this.registry?.getCheckpoint(e),s=this.registry?.getLiveContext(e);if(t&&s)return s.setEntry(t.resumeAt),s.dangerouslyReset(),this.logger.info(`Fast‑path resume for run "${e}"`),a(s)}const t=await this.storeFactory(e),i=t.get()[j];if(i&&i!==e)return c(new r({code:s.INVALID_COMMAND.code,message:`Store contains runId "${i}", but requested "${e}".`,operation:"resume"}));const n=X(t,void 0,e);if(!n)return c(new r({code:s.NOT_FOUND.code,message:`No checkpoint found for runId "${e}".`,operation:"resume"}));if(n.pipelineId!==this.definition.id)return c(new r({code:s.INVALID_COMMAND.code,message:`Checkpoint runId "${e}" belongs to pipeline "${n.pipelineId}", not "${this.definition.id}" (mismatch-base).`,operation:"resume"}));this.logger.info(`Resuming pipeline "${this.definition.id}" [${e}] from store checkpoint at stage "${n.pausedAtStageId}"`);const o=await this.buildRunContext(e,this.definition,n.resumeAt,t,void 0,[],void 0,void 0,n.containerBundle);return this.registry?.register(o,t),a(o)}async buildRunContext(t,s,i,r,n,o,a,c,d){const h=void 0===a,u=c??"",l=new AbortController,g={runId:t,pipelineId:s.id,signal:l.signal};let f;d?f=await L.from({store:r,bundle:d,templates:W(s,u,g)}):(f=h?new L(r):a,function(e,t,s,i){for(const r of t.stages)if(r.steps)for(const t of Object.values(r.steps)){const n={runId:i.runId,pipelineId:i.pipelineId,stageId:r.id,stepId:t.id,signal:i.signal};e.register({key:Y(s,r.id,t.id),factory:e=>t.action(e,n),scope:t.scope,...void 0!==t.timeout&&{timeout:t.timeout},...void 0!==t.retries&&{retries:t.retries}})}}(f,s,u,g));const y=function(e,t){return{emit(s,i){e.emit({name:s,payload:i}),t?.emit(s,i)},on:(t,s)=>e.subscribe(t,s)}}(e.createEventBus(),n),m=new p({retry:!1,throws:!1}),w=h?this.index:q(s);return new V(t,s,i,r,f,u,y,o,l,m,this.logger,this.definition.id,w,this)}},exports.PipelineRegistry=z,exports.SequentialExecutionContext=f,exports.clearCheckpoint=Z,exports.isPauseInstruction=B,exports.readCheckpoint=X,exports.writeCheckpoint=Q;
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createEventBus as e}from"@asaidimu/utils-events";import{v7 as t}from"uuid";var s={VALIDATION_FAILED:{code:"VAL-001",name:"VALIDATION_FAILED",description:"Input validation failed due to one or more invalid fields",category:"validation",httpStatus:400,logLevel:"warn"},REQUIRED_FIELD_MISSING:{code:"VAL-002",name:"REQUIRED_FIELD_MISSING",description:"A required field was not provided in the request",category:"validation",httpStatus:400,logLevel:"warn"},INVALID_FORMAT:{code:"VAL-003",name:"INVALID_FORMAT",description:"Field value does not match expected format",category:"validation",httpStatus:400,logLevel:"warn"},NOT_FOUND:{code:"DB-001-NF",name:"NOT_FOUND",description:"The requested resource could not be found",category:"database",httpStatus:404,logLevel:"info",action:"Verify the resource identifier exists before accessing"},DUPLICATE_KEY:{code:"DB-002-DUP",name:"DUPLICATE_KEY",description:"A unique constraint violation occurred",category:"database",httpStatus:409,logLevel:"warn",action:"Check if the resource already exists before creation"},RESOURCE_LOCKED:{code:"DB-003-LOCK",name:"RESOURCE_LOCKED",description:"The resource is currently locked by another operation",category:"database",httpStatus:409,logLevel:"warn",action:"Retry the operation after a brief delay"},PERMISSION_DENIED:{code:"AUTH-001-DENIED",name:"PERMISSION_DENIED",description:"The authenticated user lacks permission for this operation",category:"auth",httpStatus:403,logLevel:"warn",action:"Check user roles and permissions"},UNAUTHENTICATED:{code:"AUTH-002-UNAUTH",name:"UNAUTHENTICATED",description:"Authentication is required for this operation",category:"auth",httpStatus:401,logLevel:"info",action:"Provide valid authentication credentials"},INVALID_COMMAND:{code:"BUS-001",name:"INVALID_COMMAND",description:"The command or operation is invalid for the current state",category:"business",httpStatus:400,logLevel:"warn"},OPERATION_ABORTED:{code:"BUS-002-ABORT",name:"OPERATION_ABORTED",description:"The operation was explicitly aborted",category:"business",httpStatus:409,logLevel:"info"},INTERNAL_ERROR:{code:"SYS-001",name:"INTERNAL_ERROR",description:"An unexpected internal error occurred",category:"system",httpStatus:500,logLevel:"error",action:"Check system logs for stack traces and diagnostic information"},BACKEND_ERROR:{code:"SYS-002",name:"BACKEND_ERROR",description:"An error occurred in a backend service",category:"system",httpStatus:502,logLevel:"error"},CONCURRENCY_ERROR:{code:"CON-001",name:"CONCURRENCY_ERROR",description:"A concurrency conflict occurred during the operation",category:"concurrency",httpStatus:409,logLevel:"warn",action:"Retry the operation with updated data"}},i=new Map;var r=class e extends Error{code;codeMetadata;severity;path;operation;issues;cause;constructor(t){const r={...function(e){const t=Object.values(s).find((t=>t.code===e));if(t)return t;return i.get(e)||{code:e,name:e.replace(/-/g,"_"),description:`Unknown error: ${e}`,category:"custom",httpStatus:500,logLevel:"error",action:"Check if this error code is properly registered or handle as unknown error"}}(t.code),...t.metadata,code:t.code};super(t.message??r.description),this.name="SystemError",this.code=t.code,this.codeMetadata=r,this.severity=t.severity??"error",this.path=t.path,this.operation=t.operation,this.issues=t.issues??[],this.cause=t.cause,Object.setPrototypeOf(this,e.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,e)}withPath(t){return new e({code:this.code,message:this.message,severity:this.severity,path:t,operation:this.operation,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withOperation(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:t,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withIssue(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,t],cause:this.cause,metadata:this.codeMetadata})}withIssues(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,...t],cause:this.cause,metadata:this.codeMetadata})}withCause(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:this.issues,cause:t,metadata:this.codeMetadata})}getHttpStatus(){return this.codeMetadata.httpStatus}toLogEntry(){return{name:this.name,code:this.code,category:this.codeMetadata.category,message:this.message,path:this.path,operation:this.operation,issues:this.issues,cause:this.cause instanceof Error?this.cause.message:this.cause,stack:this.stack,timestamp:(new Date).toISOString()}}toString(){let e=`[${this.code}] ${this.message} (${this.codeMetadata.category})`;return this.path&&(e+=` at '${this.path}'`),this.operation&&(e+=` during '${this.operation}'`),this.issues.length>0&&(e+="\nIssues:\n"+this.issues.map(((e,t)=>` ${t+1}. ${e.message} [${e.code}]`)).join("\n")),this.cause&&(e+=`\nCause: ${this.cause instanceof Error?this.cause.message:String(this.cause)}`),e}},n="SYS-001",a=(e,t)=>new r({code:n,message:t,cause:e}),o=e=>({ok:!0,value:e}),c=e=>({ok:!1,error:e}),h=class e extends r{constructor(t,s){super({code:"SYNC_ERROR",message:t,cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},d=class e extends h{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},u=class e extends h{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},l=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}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 s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,r)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),r(new d("Mutex lock timed out"))}),e)}))])}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?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},p=class{mutex=new l({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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{this._value=await e(),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")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}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(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,r)=>{i=setTimeout((()=>r(new d(s))),t)}))])}},g=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new l({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new u};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,i=null;try{if(this._done)throw new u;i=await e(),this._lastValue=i,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:i,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},f=class{constructor(t,s,i,r,n){this.pipeline=t,this.stepKey=s,this.params=i,r&&(r.aborted&&this.controller.abort(),r.addEventListener("abort",(()=>this.controller.abort()))),this.localBus=n??e()}id=Math.random().toString(36).substring(2,9);localBus;controller=new AbortController;once=new p({retry:!1,throws:!1});get signal(){return this.controller.signal}on(e,t){return this.localBus.subscribe(e,t)}abort(){this.controller.abort()}async run(){const{value:e,error:t}=await this.once.do((()=>this._run()));return t?c(t):e}async _run(){const e=this.pipeline.getSteps().get(this.stepKey);if(!e)return{ok:!1,error:new r({code:s.INVALID_COMMAND.code,message:`No step registered with key "${this.stepKey}"`,operation:this.stepKey})};if(this.signal.aborted)return this.failCancelled("Pipeline execution aborted before initialization",this.stepKey);const t=this.pipeline.groupByOrder(),i=Array.from(t.entries()).sort((([e],[t])=>e-t)),n=e.order;this.emit("start",{stepKey:this.stepKey,executionId:this.id});let a={[this.stepKey]:this.params},o=a,c=!0;for(const[e,t]of i){if(e<n)continue;if(this.signal.aborted)return this.failCancelled(`Pipeline runtime aborted at stage ${e}`,this.stepKey);const s=c?t.filter((e=>e.key===this.stepKey)):t;if(c=!1,0===s.length)continue;const i=await this.runStage(s,a);if(!i.ok)return i;o=i.value,a={...a,...o},this.emit("stage:success",{order:e,executionId:this.id,carry:o})}return this.emit("terminate",{carry:o,executionId:this.id}),{ok:!0,value:o}}async runStage(e,t){const s=await Promise.all(e.map((async e=>{try{if(this.signal.aborted)return{step:e,result:this.failCancelled("Aborted mid-flight execution sequence",e.key)};const s=await e.action(t,this.signal);return{step:e,result:s}}catch(t){return{step:e,result:{ok:!1,error:t instanceof r?t:a(t,t instanceof Error?t.message:"Unexpected exception raised during step run")}}}}))),i={};let n=null;for(const{step:e,result:t}of s)if(t.ok)this.emit("step:success",{stepKey:e.key,executionId:this.id,result:t.value}),i[e.key]=t.value;else{const s=t.error.withOperation(e.key);this.emit("step:failure",{stepKey:e.key,executionId:this.id,error:s}),n||(n={ok:!1,error:s},this.emit("failure",{stepKey:e.key,executionId:this.id,error:s}))}return n||{ok:!0,value:i}}emit(e,t){this.localBus.emit({name:e,payload:t})}failCancelled(e,t){return{ok:!1,error:new r({code:"CANCELLED",message:e,operation:t})}}},y=class{steps=new Map;globalBus=e();serializer=new g;executions=new Map;constructor(e){e&&e.forEach(((e,t)=>{(Array.isArray(e)?e:[e]).forEach((e=>this.steps.set(e.key,{...e,order:t})))}))}getSteps(){return this.steps}step(e){return this.steps.set(e.key,e),this}on(e,t){return this.globalBus.subscribe(e,t)}prepare(e,t,s,i){return new f(this,e,t,s?.signal,i)}async execute(e,t,s){const i=s?.disableDeduplication?`${e}:${Date.now()}:${Math.random()}`:this.getDedupeKey(e,t);let r=this.executions.get(i);r||(r=new p({retry:!0,throws:!1}),this.executions.set(i,r));const n=await r.do((async()=>{const i=await this.serializer.do((async()=>{const i=this.prepare(e,t,{signal:s?.signal},this.globalBus);return await i.run()}));if(i.error)throw i.error;return i.value})).finally((()=>{setTimeout((()=>this.executions.delete(i)),0)}));return n.error?c(n.error):n.value}getRegisteredSteps(){return Array.from(this.steps.keys())}validate(){const e=[];return 0===this.steps.size&&e.push("Pipeline has no registered steps"),e}destroy(){this.steps.clear(),this.globalBus.clear(),this.executions.clear()}groupByOrder(){const e=new Map;for(const t of this.steps.values()){const s=e.get(t.order)??[];s.push(t),e.set(t.order,s)}return e}getDedupeKey(e,t){try{return`${e}:${JSON.stringify(this.sortObjectKeys(t))}`}catch{return`${e}:${Date.now()}:${Math.random()}`}}sortObjectKeys(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map((e=>this.sortObjectKeys(e)));const t={};return Object.keys(e).sort().forEach((s=>{t[s]=this.sortObjectKeys(e[s])})),t}},m=class{constructor(e,t,s={}){this.factory=e,this.onCleanup=t,this.options=s}_count=0;init=new p({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask((()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())}))):void(this.cleanupTimer=setTimeout((()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()}),e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}};function w(e,t){if(!e.length)return;const s=e.slice(),i=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=s.length-1;e>=0;e--)try{await s[e]()}catch(t){console.error(`${i} Cleanup error at index ${e}:`,t)}}}async function v(e,t){const s=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${s} Cleanup error at index ${t}:`,e)}}function b(e){return`${e}__watched`}var S=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function k(e,t){let s;const i=new Promise(((e,i)=>{s=setTimeout((()=>i(new Error(`Timeout: ${t}ms`))),t)}));try{return Promise.race([e,i])}finally{clearTimeout(s)}}async function I(e){const t=(new TextEncoder).encode(e),s=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(s)).map((e=>e.toString(16).padStart(2,"0"))).join("")}var A=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,s){const i=this.get(e);if(!i)return S;if(i.package)return i.package;const r=e,n=w(i.cleanupFunctions,r),a="singleton"!==i.scope||void 0!==i.instance,o={instance:i.instance,error:i.error,ready:a,[s||e]:i.instance,cleanup:n,invalidate:t};return i.package=o,o}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const s=this.get(e);if(!s)return;const i=e;"singleton"===s.scope&&(s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),s.controller.abort(),await s.streamOnce.current(),s.streamSerializer.close(),s.stream=void 0,s.streamOnce=new p({retry:!0,throws:!0}),t||(s.streamSerializer=new g,s.controller=new AbortController)),await v(s.cleanupFunctions,i),await v(s.disposeFunctions,i),s.cleanupFunctions=[],s.disposeFunctions=[],"singleton"===s.scope&&(s.buildOnce=new p({retry:!0,throws:!0})),s.instance=void 0,s.error=void 0}},_=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const s of t)this.dependents.get(s)?.delete(e);const s=this.dependents.get(e);if(s)for(const t of s)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.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}iterDependents(e){return this.dependents.get(e)??O}setDependencies(e,t){this.registerNode(e);const s=this.dependencies.get(e),i=new Set(t);for(const t of s)i.has(t)||this.removeDependency(e,t);for(const t of i)s.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const s=[t],i=new Set([t]),r=new Map;for(;s.length>0;){const n=s.shift();if(n===e){const s=[];let i=e;for(;void 0!==i&&(s.push(i),i!==t);)i=r.get(i);return s.reverse(),s.unshift(e),s}const a=this.dependencies.get(n);if(a)for(const e of a)i.has(e)||(i.add(e),r.set(e,n),s.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const s of t)e.set(s,this.dependencies.get(s)?.size??0);const s=[];for(const[t,i]of e)0===i&&s.push(t);const i=[];for(;s.length>0;){const t=s.shift();i.push(t);const r=this.dependents.get(t);if(r)for(const t of r){const i=(e.get(t)||0)-1;e.set(t,i),0===i&&s.push(t)}}if(i.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return i}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,s){const i=new Set,r=new Set,n=[e];r.add(e),s&&i.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=a.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),i.add(e),n.push(e))}return i}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const s=Array.from(t).join(", ");return`${String(e)} → [${s||"∅"}]`})).join("\n")}},O=new Set,E=class{graph;constructor(){this.graph=new _}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){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}setDependencies(e,t){const s=Array.from(t).map((e=>e));this.graph.setDependencies(e,s)}wouldCreateCycle(e,t,s){if(s?.has(t)){const e=Array.from(s),i=e.indexOf(t),r=e.slice(i);return r.push(t),r}const i=this.graph.wouldCreateCycle(e,t);return i||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()}},$=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];var D=class e extends Error{category;constructor(t,s,i){super(t,{cause:i}),this.name="ArtifactError",this.category=s,Object.setPrototypeOf(this,e.prototype)}},x=class extends D{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},C=class extends D{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},R=class extends D{constructor(e){super(e,"system"),this.name="InvalidImportError"}},N=class extends D{constructor(e){super(`Artifact "${e}" instance is not JSON-serializable (POJO are required for persistence)`,"system"),this.name="InvalidExportOperationError"}},P=(new AbortController).signal,M=class{constructor(e,t,s,i,r){this.registry=e,this.cache=t,this.graph=s,this.store=i,this.observer=r}async build(e,t,s){const i=this.cache.get(e);if("singleton"===i?.scope&&i.buildOnce.done())return this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s);const r=this.registry.getByString(e);if(!r)throw new x(e);const n=t??[];if(n.includes(e))throw new D(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${[...n,e].join(" -> ")}`,"system");n.push(e);let a=i;a||(a=this.createCachedArtifact(r),this.cache.set(e,a));try{if("transient"===a.scope)return this.executeBuild(r,a,n);const i=a;try{await i.buildOnce.do((()=>this.executeBuild(r,i,n)))}catch(i){if(i instanceof C)return this.build(e,t,s);throw i}return i.stream&&i.streamOnce.do(i.stream),this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s)}finally{n.pop()}}async executeBuild(e,t,s){const i=e.key,r=String(i),n="transient"===t.scope;t.buildCount++,"singleton"===t.scope&&(t.activeDebounceMs=e.debounce??0);const a={cleanupFunctions:[],disposeFunctions:[],capturedArtifactDeps:new Set,capturedStateSelectors:[],dependencyVersions:new Map},o=this.buildContext(e,t,s,r,a),c=await this.runWithRetries(e,o,a.dependencyVersions);if(this.commitResult(i,t,n,c,a),n){const e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[i]:e,cleanup:w(a.cleanupFunctions,r),invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${r}"`)}}}buildContext(e,t,s,i,r){const n=e.key,a="transient"===t.scope,{cleanupFunctions:o,disposeFunctions:c,capturedArtifactDeps:h,dependencyVersions:d,capturedStateSelectors:u}=r,l=async(e,t)=>{const r=t?this.computeParamKey(e,t):e;if(r===n)throw new D(`Artifact "${i}" depends on itself.`,"system");const a=this.graph.wouldCreateCycle(n,r);if(a)throw new D(`Adding dependency "${String(r)}" to "${i}" would create a cycle: ${a.join(" -> ")}`,"system");h.add(r);const o=await(t?this.resolveParameterized(e,t):this.build(e,s)),c=this.cache.get(r);return c&&d.set(r,c.version),o},p="singleton"===t.scope?t.controller.signal:P,g=async(e,t)=>{const s=await l(e,t);if(s.error)throw s.error;return s.instance},f=(e,t)=>{const s=function(e,t="."){const s=new Set,i=new Map,r=(e="")=>{if(i.has(e))return i.get(e);const n=new Proxy((()=>{}),{get:(i,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic, arithmetic, or string operations inside a selector.");if($.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const a=e?`${e}${t}${n}`:n;return e&&s.delete(e),s.add(a),r(a)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions or methods.")}});return i.set(e,n),n};try{e(r())}catch(e){throw new Error(`Selector failed during path analysis. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(s)}(e);return u.push({paths:s,options:t}),e(this.store.get(!0))};return{state:()=>this.store.get(!0),previous:t.instance,signal:p,onCleanup:e=>o.push(e),onDispose:e=>c.push(e),use:e=>e({resolve:l,require:g,select:f}),stream:e=>{if(a)throw new D(`[ArtifactManager] Illegal stream on transient artifact "${i}"`,"system");const s=t,r=async(e,t=void 0)=>{await s.streamSerializer.do((async()=>{void 0!==s.stream&&(s.instance=e,s.error=t,s.version++,this.cache.invalidatePackage(n),await this.processStream(i))}))},o={value:()=>s.instance,get signal(){return s.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>r(e)};s.stream=async()=>{try{const t=await e(o);t&&s.cleanupFunctions.push(t)}catch(e){await r(void 0,e),await this.invalidate(n,!1,!0)}}}}}async runWithRetries(e,t,s){const i=t.signal,r=(e.retries??0)+1;let n=0;for(;n<r;)try{if(i.aborted)throw new C;const a=e.factory(t);let o;if(o=a instanceof Promise?e.timeout?await k(a,e.timeout):await a:a,i.aborted)throw new C;const c=this.detectStaleness(s);if(c){if(n++,s.clear(),n<r)continue;return{ok:!1,error:new D(`Build stale after all retries: dependency "${String(c)}" changed during build.`,"system")}}return{ok:!0,value:o}}catch(e){if(i.aborted||e instanceof C)throw new C;if(e instanceof D)throw e;if(n++,n>=r)return{ok:!1,error:e}}return{ok:!1,error:new Error("Build exhausted retry budget unexpectedly.")}}commitResult(e,t,s,i,r){const{cleanupFunctions:n,disposeFunctions:a,capturedArtifactDeps:o,capturedStateSelectors:c}=r;s||(this.updateDependencyGraph(e,o,c),t.cleanupFunctions=n,t.disposeFunctions=a,t.artifactDependencies=new Set(o),t.stateGroups=c.map((({paths:e,options:t})=>({paths:e,options:t})))),i.ok?(t.instance=i.value,t.error=void 0):(t.instance=void 0,t.error=i.error),t.version++,this.cache.invalidatePackage(e)}detectStaleness(e){for(const[t,s]of e){const e=this.cache.get(t);if(e&&e.version!==s)return t}return null}async invalidate(e,t=!1,s=!1){const i=this.cache.get(e);if(!i)return;if("singleton"!==i.scope)return this.executeInvalidation(e,t,s);const r=i;return r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0),!t&&r.activeDebounceMs>0?new Promise(((i,n)=>{r.debounceTimer=setTimeout((()=>{r.debounceTimer=void 0,this.executeInvalidation(e,t,s).then(i).catch(n)}),r.activeDebounceMs)})):this.executeInvalidation(e,t,s)}async executeInvalidation(e,t,s=!1){const i=this.cache.get(e);i&&"singleton"===i.scope&&await i.invalidationSerializer.do((async()=>{i.version++,await this.cache.invalidateInstance(e),await this.cascadeInvalidation(this.graph.iterDependents(e));const r=this.registry.get(e),n=r&&(t||!r.lazy||this.observer.hasWatchers(e))&&!s;n&&await this.build(e).catch((t=>{t instanceof C||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),(n||s)&&this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(0===e.size)return;const t=[];for(const s of e)t.push(this.invalidate(s).catch((e=>{console.error(`[ArtifactManager] Cascade failed for "${String(s)}":`,e)})));await Promise.all(t)}updateDependencyGraph(e,t,s){const i=this.cache.get(e);if(!i||"singleton"!==i.scope)return;this.graph.registerNode(e),this.graph.setDependencies(e,t),i.stateDependencies=new Set;for(const{paths:e}of s)for(const t of e)i.stateDependencies.add(t);if(i.stateUnsubscribe&&(i.stateUnsubscribe(),i.stateUnsubscribe=void 0),0===s.length)return;const r=()=>this.invalidate(e),n=new Map;for(const{paths:e,options:t}of s){const s=void 0===t?"undefined":JSON.stringify(t);let i=n.get(s);i||(i={options:t,paths:new Set},n.set(s,i));for(const t of e)i.paths.add(t)}const a=[];for(const{options:e,paths:t}of n.values()){if(0===t.size)continue;const s=Array.from(t);void 0===e?a.push(this.store.watch(s,r)):a.push(this.store.watch(s,r,e))}0===a.length?i.stateUnsubscribe=void 0:1===a.length?i.stateUnsubscribe=a[0]:i.stateUnsubscribe=()=>{for(const e of a)e()}}createCachedArtifact(e){return"transient"===e.scope?{scope:"transient",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:"singleton",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce?e.debounce:0,controller:new AbortController,buildOnce:new p({retry:!0,throws:!0}),streamOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateGroups:[],artifactDependencies:new Set}}resolveStatic(e){if(!this.registry.has(e))throw new x(e);return this.build(e)}async resolveParameterized(e,t){if(!this.registry.has(e))throw new x(String(e));const s=this.registry.get(e);if(!s.paramKey)throw new D(`Artifact "${String(e)}" is not parameterized.`,"external");const i=s.paramKey(t),r=this.registry.getByString(i);if(r&&!r.paramKey&&!r.virtual)throw new D(`Parameterized artifact "${String(e)}" with params ${JSON.stringify(t)} resolves to key "${i}" which is already registered as a static artifact.`,"system");return this.registry.hasString(i)||this.registry.setVirtual(i,{key:i,factory:e=>s.factory({...e,params:t}),scope:s.scope,lazy:s.lazy,timeout:s.timeout,retries:s.retries,debounce:s.debounce,virtual:!0}),this.build(i,void 0,e)}computeParamKey(e,t){const s=this.registry.get(e);if(!s.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);return s.paramKey(t)}},T=class{constructor(e,t,s){this.registry=e,this.cache=t,this.container=s}listeners=new Map;watchers=new Map;watch(e,t=6e4){return this.watchForKey(e,this.registry.get(e),t)}watchParameterized(e,t,s=6e4){const i=this.registry.get(e);if(!i.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);const r=i.paramKey(t);return this.watchForKey(r,i,s,t)}watchForKey(e,t,s,i){const r="transient"===t.scope,n=r?b(e):e,a=this.watchers.get(n);if(a)return a.observer;const o=new m((async()=>{!r&&void 0===i||this.registry.hasString(e)||this.registry.setVirtual(e,{key:e,factory:r?t.factory:e=>t.factory({...e,params:i}),scope:r?"singleton":t.scope,lazy:t.lazy,timeout:t.timeout,retries:t.retries,debounce:t.debounce,paramKey:t.paramKey,virtual:!0})}),(async()=>{r||void 0!==i?(await this.registry.unregister(n).catch((()=>{})),this.cache.delete(n),this.watchers.delete(n)):this.cache.invalidatePackage(n),this.listeners.delete(n)}),{gracePeriod:r&&void 0===i?"sync":s});let c;const h={id:n,get count(){return o.subscribers},get:(t=!1)=>0!==o.subscribers||t?this.cache.package(n,((e,t)=>this.container.invalidate(n,e,t)),e):S,resolve:()=>c||(c=(async()=>{await o.acquire();try{return await this.container.resolve(n)}finally{o.release(),c=void 0}})(),c),subscribe:(e,t=!0)=>{const s=()=>e(h.get());return o.acquire().then((()=>{this.container.resolve(n).then((()=>{this.listeners.has(n)||this.listeners.set(n,new Set),t&&s(),this.listeners.get(n).add(s)}))})).catch((e=>{console.error(`[ArtifactObserver] Resolution failed for "${n}":`,e),this.listeners.get(n)?.add(s)})),()=>{this.listeners.get(n)?.delete(s),o.release()}}};return this.watchers.set(n,{resource:o,observer:h}),h}evictWatcher(e){[e,b(e)].forEach((e=>{const t=this.watchers.get(e);t&&(t.resource.forceCleanup(),this.watchers.delete(e))}))}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const s of t)try{s()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return this.watchers.has(e)||this.watchers.has(b(e))}getWatcherCount(e){const t=this.watchers.get(e)||this.watchers.get(b(e));return t?.resource.subscribers??0}clear(){this.watchers.clear(),this.listeners.clear()}},L=class{artifacts=new Map;register({key:e,factory:t,lazy:s,...i}){const{scope:r,...n}=i,a={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===s||s,...n};return this.artifacts.set(e,a),()=>this.unregister(e)}setVirtual(e,t){this.artifacts.set(e,t)}get(e){if(!this.has(e))throw new x(String(e));return this.artifacts.get(e)}getByString(e){return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}hasString(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()}},F=class e{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t),subset:(...t)=>e.subset(...t)},this.registry=new L,this.cache=new A,this.graph=new E,this.observer=new T(this.registry,this.cache,this),this.manager=new M(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const s=t,i=this.registry.get(s),r=this.cache.get(s);if(!i)return;let n="idle";r&&("singleton"===r.scope&&void 0!==r.debounceTimer?n="debouncing":"singleton"===r.scope&&r.buildOnce.running()?n="building":r.error?n="error":void 0!==r.instance&&(n="active")),e.push({id:s,scope:i.scope??"singleton",status:n,dependencies:this.graph.getDependencies(s).map((e=>String(e))),dependents:this.graph.getDependents(s).map((e=>String(e))),stateDependencies:"singleton"===r?.scope?Array.from(r.stateDependencies):[],buildCount:r?.buildCount??0})})),e}register(e){const{key:t}=e,s=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${s}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${s}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const i=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==i||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${s}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;await this.manager.dispose(s),await this.registry.unregister(s),this.observer.evictWatcher(s)}async resolve(e,t){return void 0===t?this.manager.resolveStatic(e):this.manager.resolveParameterized(e,t)}async require(e,t){const s=await this.resolve(e,t);if(s.error)throw s.error;return s.instance}watch(e,t,s){return void 0===t?this.observer.watch(e,s):this.observer.watchParameterized(e,t,s)}peek(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;return this.cache.get(s)?.instance}async invalidate(e,t){const s=t?.params,i=t?.replace??!1,r=void 0!==s?this.manager.computeParamKey(e,s):e;return this.manager.invalidate(r,i)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((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()}async export(){const e=[];for(const t of this.cache.keys()){const s=this.cache.get(t);if(!s||"singleton"!==s.scope)continue;if(void 0===s.instance)continue;const i=new Set;for(const e of s.stateGroups)for(const t of e.paths)i.add(t);const r=Array.from(i).sort(),n=this.store.subset(r),a=await I(JSON.stringify(n,Object.keys(n).sort()));let o;try{o=structuredClone(s.instance)}catch(e){throw new N(t)}e.push({key:t,instance:o,state:{groups:s.stateGroups.map((e=>({paths:e.paths,options:e.options}))),hash:a},dependencies:Array.from(s.artifactDependencies)})}const t={...{version:"1.0",timestamp:Date.now(),artifacts:e}},s=JSON.stringify(t),i=await I(s);return{...t,checksum:i}}async restore(e){const{checksum:t,...s}=e;if(await I(JSON.stringify(s))!==t)throw new R("Bundle checksum mismatch – data corrupted");if("1.0"!==e.version)throw new R(`Unsupported bundle version: ${e.version}`);const i=new Map;for(const t of e.artifacts)i.set(t.key,t);const r=new Set,n=new Map;for(const t of e.artifacts)for(const e of t.dependencies)n.has(e)||n.set(e,new Set),n.get(e).add(t.key);const a=async e=>{const t=new Set;for(const s of e.state.groups)for(const e of s.paths)t.add(e);const s=Array.from(t).sort(),i=this.store.subset(s);return I(JSON.stringify(i,Object.keys(i).sort()))};for(const t of e.artifacts){await a(t)!==t.state.hash&&r.add(t.key)}const o=Array.from(r);for(;o.length;){const e=o.shift(),t=n.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),o.push(e))}for(const t of e.artifacts){if(r.has(t.key))continue;this.cache.get(t.key)&&await this.cache.invalidateInstance(t.key,!1);const e={scope:"singleton",instance:t.instance,error:void 0,version:1,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set(t.state.groups.flatMap((e=>e.paths))),activeDebounceMs:0,buildOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateUnsubscribe:void 0,debounceTimer:void 0,controller:new AbortController,streamOnce:new p({retry:!0,throws:!0}),stream:void 0,stateGroups:t.state.groups,artifactDependencies:new Set(t.dependencies)};e.buildOnce.resolve(t.instance),this.cache.set(t.key,e);const s=[];for(const e of t.state.groups){const i=this.store.watch(e.paths,(()=>this.invalidate(t.key)),e.options);s.push(i)}e.stateUnsubscribe=()=>{for(const e of s)e()},this.graph.setDependencies(t.key,t.dependencies)}}static async from(t){const s=new e(t.store);if(t.bundle){if("object"!=typeof t.bundle||!t.bundle.version||!Array.isArray(t.bundle.artifacts))throw new R("Invalid bundle: missing version or artifacts array");await s.restore(t.bundle)}for(const e of t.templates)s.register(e);return s}};function z(e){return"object"==typeof e&&null!==e&&"pause"in e}var K="__pipeline_data__";var B={info:()=>{},error:()=>{}},U=class{constructor(e,t){this.definition=e,this.logger=t.logger??B,this.storeFactory=t.storeFactory,this.initialStateFactory=t.initialStateFactory,this.registry=t.registry,this.index=V(e)}logger;storeFactory;initialStateFactory;registry;index;async prepare(e,s){const i=s??t(),r=await this.storeFactory(i);await r.ready();const n=this.initialStateFactory?.()??{};await r.set(n),this.logger.info(`Prepared new run "${i}" for pipeline "${this.definition.id}"`);const a=await this.buildRunContext(i,this.definition,e,r,void 0,[]);return this.registry?.register(a,r),a}async resume(e){const t=this.registry?.getLiveContext(e)??null;if(null!==t)return this.logger.info(`Resuming pipeline "${this.definition.id}" [${e}] from live registry context`),o(t);const i=await this.storeFactory(e),n=Q(i,void 0,e);if(!n)return c(new r({code:s.NOT_FOUND.code,message:`No checkpoint found for runId "${e}".`,operation:"resume"}));if(n.pipelineId!==this.definition.id)return c(new r({code:s.INVALID_COMMAND.code,message:`Checkpoint runId "${e}" belongs to pipeline "${n.pipelineId}", not "${this.definition.id}" (mismatch-base).`,operation:"resume"}));this.logger.info(`Resuming pipeline "${this.definition.id}" [${e}] from store checkpoint at stage "${n.pausedAtStageId}"`);const a=await this.buildRunContext(e,this.definition,n.resumeAt,i,void 0,[],void 0,void 0,n.containerBundle);return this.registry?.register(a,i),o(a)}async buildRunContext(t,s,i,r,n,a,o,c,h){const d=void 0===o,u=c??"",l=new AbortController,g={runId:t,pipelineId:s.id,signal:l.signal};let f;h?f=await F.from({store:r,bundle:h,templates:q(s,u,g)}):(f=d?new F(r):o,function(e,t,s,i){for(const r of t.stages)if(r.steps)for(const t of Object.values(r.steps)){const n={runId:i.runId,pipelineId:i.pipelineId,stageId:r.id,stepId:t.id,signal:i.signal};e.register({key:W(s,r.id,t.id),factory:e=>t.action(e,n),scope:t.scope,...void 0!==t.timeout&&{timeout:t.timeout},...void 0!==t.retries&&{retries:t.retries}})}}(f,s,u,g));const y=function(e,t){return{emit(s,i){e.emit({name:s,payload:i}),t?.emit(s,i)},on:(t,s)=>e.subscribe(t,s)}}(e(),n),m=new p({retry:!1,throws:!1}),w=d?this.index:V(s);return new j(t,s,i,r,f,u,y,a,l,m,this.logger,this.definition.id,w,this)}},j=class{constructor(e,t,s,i,r,n,a,o,c,h,d,u,l,p){this.pipeline=t,this.entry=s,this.store=i,this.container=r,this.keyPrefix=n,this.bus=a,this.parentPath=o,this.controller=c,this.once=h,this.logger=d,this.definitionId=u,this.index=l,this.factory=p,this.id=e,this.__registryContainer=r,this.__registryPipelineId=u}id;__registryContainer;__registryPipelineId;on(e,t){return this.bus.on(e,t)}abort(){this.controller.abort()}async run(){const e=await this.once.do((()=>this.execute()));return void 0!==e.error?c(new r({code:s.INTERNAL_ERROR.code,message:`Unexpected throw escaped run(): ${J(e.error)}`,operation:`pipeline:${this.pipeline.id}`,cause:e.error})):e.value}async execute(){this.bus.emit("pipeline:start",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id}),this.logger.info(`Pipeline start: ${this.pipeline.id} [${this.id}]`);const e=this.resolveEntryStage();if(!e.ok)return this.failPipeline(e.error);const{stageMap:t,orderedStages:i,stageOrderIndex:n}=this.index;let a=e.value,c=!0;for(;;){if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted before stage "${a.label}".`,operation:`stage:${a.id}`});return this.failPipeline(e)}const e=c?this.entry:void 0;c=!1;const h=await this.executeStage(a,e);if(!h.ok)return this.failPipeline(h.error);if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted after stage "${a.label}".`,operation:`stage:${a.id}`});return this.failPipeline(e)}const d=h.value,u="pause"===d.kind?void 0:d.nextInstruction,l=n.get(a.id)??-1,p=void 0!==i[l+1],g="pause"===d.kind?"pause":null===u?"terminate":"string"==typeof u?"jump":p?"advance":"natural-end";if(this.bus.emit("router:evaluated",{path:this.parentPath,stageId:a.id,stageLabel:a.label,runId:this.id,instruction:u,interpretation:g}),"pause"===d.kind){const{checkpoint:e,pauseTimeout:t}=d,s=this.store.get(!0);return this.logger.info(`Pipeline paused: ${this.pipeline.id} [${this.id}] at stage "${e.pausedAtStageId}"`+(void 0!==t?` (timeout: ${t}ms)`:"")),this.bus.emit("pipeline:paused",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,checkpoint:e,finalState:s,pauseTimeout:t}),o({status:"paused",runId:this.id,finalState:s,checkpoint:e})}if(null===u)break;if("string"==typeof u){const e=t.get(u);if(!e){const e=new r({code:s.INVALID_COMMAND.code,message:`Router on stage "${a.label}" returned unknown stageId: "${u}"`,operation:`stage:${a.id}`});return this.failPipeline(e)}a=e;continue}const f=i[l+1];if(!f)break;a=f}const h=this.store.get(!0);return this.logger.info(`Pipeline succeeded: ${this.pipeline.id} [${this.id}]`),this.bus.emit("pipeline:success",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,finalState:h}),o({status:"succeeded",runId:this.id,finalState:h})}resolveEntryStage(){const{stageMap:e,orderedStages:t}=this.index;if(this.entry?.stage){const t=e.get(this.entry.stage);return t?o(t):c(new r({code:s.INVALID_COMMAND.code,message:`Entry stage "${this.entry.stage}" not found.`,operation:`pipeline:${this.pipeline.id}`}))}const i=t[0];return i?o(i):c(new r({code:s.INVALID_COMMAND.code,message:"Pipeline has no stages.",operation:`pipeline:${this.pipeline.id}`}))}async executeStage(e,t){const s=e.pipelines&&e.pipelines.length>0?"pipelines":"steps",i=[...this.parentPath,{kind:"stage",id:e.id,label:e.label}];this.bus.emit("stage:start",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,mode:s});const r="pipelines"===s?await this.executePipelinesStage(e,i,t):await this.executeStepsStage(e,i,t);return r.ok?"pause"===r.value.kind?this.bus.emit("stage:paused",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,checkpoint:r.value.checkpoint}):this.bus.emit("stage:success",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,nextInstruction:r.value.nextInstruction}):this.bus.emit("stage:failure",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,error:r.error}),r}async executeStepsStage(e,t,i){const n=Object.values(e.steps??{});if(0===n.length){this.logger.info(`Stage "${e.label}" has no steps — skipping.`);const t=Y(e.router,this.store.get(!0),{});return o(G(t))}if(this.controller.signal.aborted)return c(new r({code:s.OPERATION_ABORTED.code,message:`Aborted before resolving steps in stage "${e.label}".`,operation:`stage:${e.id}`}));const a=void 0!==i?.step?n.filter((e=>e.id===i.step)):n;if(void 0!==i?.step&&0===a.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry step "${i.step}" not found in stage "${e.label}".`,operation:`stage:${e.id}`}));for(const e of a)this.bus.emit("step:start",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id});const h=await Promise.all(a.map((async t=>({step:t,result:await this.container.resolve(W(this.keyPrefix,e.id,t.id))})))),d={};for(const{step:e,result:i}of h)i.ready?(this.bus.emit("step:success",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id}),d[e.id]=o(i.instance)):(this.bus.emit("step:failure",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id,error:i.error}),d[e.id]=c(new r({code:s.BACKEND_ERROR.code,message:J(i.error)})));const u=h.find((({result:e})=>!e.ready));if(u){const e=u.result.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Step "${u.step.label}" failed: ${J(e)}`,operation:`step:${u.step.id}`,cause:e}))}const l=h.map((({result:e})=>e.instance)).filter((e=>null!=e));let p;try{await this.store.transaction((async()=>{for(const e of l)await this.store.set(e);const t=Y(e.router,this.store.get(!0),d);if(z(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await H(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=G(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed during stage "${e.label}": ${J(t)}`,operation:`stage:${e.id}`,cause:t}))}return o(p)}async executePipelinesStage(e,t,i){const n=e.pipelines,a=void 0!==i?.pipeline?(()=>{const{index:e}=i.pipeline,t=n[e];return t?[{subPipeline:t,originalIndex:e}]:[]})():n.map(((e,t)=>({subPipeline:e,originalIndex:t})));if(void 0!==i?.pipeline&&0===a.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry sub‑pipeline index ${i.pipeline.index} out of bounds.`,operation:`stage:${e.id}`}));this.bus.emit("subpipeline:fork",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,subPipelineIds:a.map((({subPipeline:e})=>e.id))});const h=await Promise.all(a.map((async({subPipeline:s,originalIndex:r})=>{const n=void 0!==i?.pipeline?{stage:i.pipeline.stage,step:i.pipeline.step}:void 0,a=function(e,t,s){const i=`${t}:pipeline-${s}`;return e?`${e}:${i}`:i}(this.keyPrefix,e.id,r);return{subPipeline:s,originalIndex:r,ctx:await this.factory.buildRunContext(this.id,s,n,this.store,this.bus,t,this.container,a)}}))),d=()=>{h.forEach((({ctx:e})=>e.abort()))};this.controller.signal.addEventListener("abort",d,{once:!0});try{if(this.controller.signal.aborted)return d(),c(new r({code:s.OPERATION_ABORTED.code,message:this.controller.signal.reason,operation:`stage:${e.id}`}));const i=await Promise.all(h.map((({ctx:e})=>e.run()))),n={};for(let e=0;e<a.length;e++)n[a[e].subPipeline.id]=i[e];this.bus.emit("subpipeline:join",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,results:n});const u=i.findIndex((e=>!e.ok||"failed"===e.value.status));if(-1!==u){const t=a[u].subPipeline.id,n=i[u],o=n.ok?n.value.error:n.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Sub‑pipeline "${t}" failed: ${J(o)}`,operation:`stage:${e.id}`,cause:o}))}const l=i.findIndex((e=>e.ok&&"paused"===e.value.status));if(-1!==l){const t=i[l].value,{checkpoint:n}=t,h={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:e.id,pipeline:{index:a[l].originalIndex,stage:n.resumeAt.stage,step:n.resumeAt.step}},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};try{await this.store.transaction((async()=>{await H(this.store,h)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Failed to write parent pause checkpoint for stage "${e.label}".`,operation:`stage:${e.id}`,cause:t}))}return o({kind:"pause",checkpoint:h,pauseTimeout:void 0})}let p;try{await this.store.transaction((async()=>{const t=Y(e.pipelinesRouter,this.store.get(!0),n);if(z(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await H(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=G(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed evaluating router for stage "${e.label}": ${J(t)}`,operation:`stage:${e.id}`,cause:t}))}return o(p)}finally{this.controller.signal.removeEventListener("abort",d)}}failPipeline(e){return this.bus.emit("pipeline:failure",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,error:e}),c(e)}};function V(e){const t=[...e.stages].sort(((e,t)=>e.order-t.order)),s=new Map,i=new Map;for(let e=0;e<t.length;e++){const r=t[e];s.set(r.id,r),i.set(r.id,e)}return{stageMap:s,orderedStages:t,stageOrderIndex:i}}function q(e,t,s){const i=[];for(const r of e.stages)if(r.steps)for(const e of Object.values(r.steps)){const n={runId:s.runId,pipelineId:s.pipelineId,stageId:r.id,stepId:e.id,signal:s.signal};i.push({key:W(t,r.id,e.id),factory:t=>e.action(t,n),scope:e.scope,...void 0!==e.timeout&&{timeout:e.timeout},...void 0!==e.retries&&{retries:e.retries}})}return i}function W(e,t,s){return e?`${e}:${t}:${s}`:`${t}:${s}`}function Y(e,t,s){return e?e(t,s):void 0}function G(e){return{kind:"advance",nextInstruction:e}}function J(e){return e instanceof Error?e.message:String(e)}async function H(e,t){const s=e,i=t.pipelineId,r=t.runId,n=s.get(!0)[K]??{},a={...n,[i]:{...n[i]??{},[r]:t}};await s.set({[K]:a})}function Q(e,t,s){const i=e.get(!0)[K];if(t)return i?.[t]?.[s]??null;if(i)for(const e in i){const t=i[e][s];if(t)return t}return null}async function X(e,t,s){const i=e,r=i.get(!0)[K]??{},n={...r[t]??{}};delete n[s];const a={...r,[t]:n};await i.set({[K]:a})}export{K as PIPELINE_DATA_KEY,y as Pipeline,U as PipelineFactory,f as SequentialExecutionContext,X as clearCheckpoint,z as isPauseInstruction,Q as readCheckpoint,H as writeCheckpoint};
|
|
1
|
+
import{createEventBus as e}from"@asaidimu/utils-events";import{v7 as t}from"uuid";var s={VALIDATION_FAILED:{code:"VAL-001",name:"VALIDATION_FAILED",description:"Input validation failed due to one or more invalid fields",category:"validation",httpStatus:400,logLevel:"warn"},REQUIRED_FIELD_MISSING:{code:"VAL-002",name:"REQUIRED_FIELD_MISSING",description:"A required field was not provided in the request",category:"validation",httpStatus:400,logLevel:"warn"},INVALID_FORMAT:{code:"VAL-003",name:"INVALID_FORMAT",description:"Field value does not match expected format",category:"validation",httpStatus:400,logLevel:"warn"},NOT_FOUND:{code:"DB-001-NF",name:"NOT_FOUND",description:"The requested resource could not be found",category:"database",httpStatus:404,logLevel:"info",action:"Verify the resource identifier exists before accessing"},DUPLICATE_KEY:{code:"DB-002-DUP",name:"DUPLICATE_KEY",description:"A unique constraint violation occurred",category:"database",httpStatus:409,logLevel:"warn",action:"Check if the resource already exists before creation"},RESOURCE_LOCKED:{code:"DB-003-LOCK",name:"RESOURCE_LOCKED",description:"The resource is currently locked by another operation",category:"database",httpStatus:409,logLevel:"warn",action:"Retry the operation after a brief delay"},PERMISSION_DENIED:{code:"AUTH-001-DENIED",name:"PERMISSION_DENIED",description:"The authenticated user lacks permission for this operation",category:"auth",httpStatus:403,logLevel:"warn",action:"Check user roles and permissions"},UNAUTHENTICATED:{code:"AUTH-002-UNAUTH",name:"UNAUTHENTICATED",description:"Authentication is required for this operation",category:"auth",httpStatus:401,logLevel:"info",action:"Provide valid authentication credentials"},INVALID_COMMAND:{code:"BUS-001",name:"INVALID_COMMAND",description:"The command or operation is invalid for the current state",category:"business",httpStatus:400,logLevel:"warn"},OPERATION_ABORTED:{code:"BUS-002-ABORT",name:"OPERATION_ABORTED",description:"The operation was explicitly aborted",category:"business",httpStatus:409,logLevel:"info"},INTERNAL_ERROR:{code:"SYS-001",name:"INTERNAL_ERROR",description:"An unexpected internal error occurred",category:"system",httpStatus:500,logLevel:"error",action:"Check system logs for stack traces and diagnostic information"},BACKEND_ERROR:{code:"SYS-002",name:"BACKEND_ERROR",description:"An error occurred in a backend service",category:"system",httpStatus:502,logLevel:"error"},CONCURRENCY_ERROR:{code:"CON-001",name:"CONCURRENCY_ERROR",description:"A concurrency conflict occurred during the operation",category:"concurrency",httpStatus:409,logLevel:"warn",action:"Retry the operation with updated data"}},i=new Map;var r=class e extends Error{code;codeMetadata;severity;path;operation;issues;cause;constructor(t){const r={...function(e){const t=Object.values(s).find((t=>t.code===e));if(t)return t;return i.get(e)||{code:e,name:e.replace(/-/g,"_"),description:`Unknown error: ${e}`,category:"custom",httpStatus:500,logLevel:"error",action:"Check if this error code is properly registered or handle as unknown error"}}(t.code),...t.metadata,code:t.code};super(t.message??r.description),this.name="SystemError",this.code=t.code,this.codeMetadata=r,this.severity=t.severity??"error",this.path=t.path,this.operation=t.operation,this.issues=t.issues??[],this.cause=t.cause,Object.setPrototypeOf(this,e.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,e)}withPath(t){return new e({code:this.code,message:this.message,severity:this.severity,path:t,operation:this.operation,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withOperation(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:t,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withIssue(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,t],cause:this.cause,metadata:this.codeMetadata})}withIssues(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,...t],cause:this.cause,metadata:this.codeMetadata})}withCause(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:this.issues,cause:t,metadata:this.codeMetadata})}getHttpStatus(){return this.codeMetadata.httpStatus}toLogEntry(){return{name:this.name,code:this.code,category:this.codeMetadata.category,message:this.message,path:this.path,operation:this.operation,issues:this.issues,cause:this.cause instanceof Error?this.cause.message:this.cause,stack:this.stack,timestamp:(new Date).toISOString()}}toString(){let e=`[${this.code}] ${this.message} (${this.codeMetadata.category})`;return this.path&&(e+=` at '${this.path}'`),this.operation&&(e+=` during '${this.operation}'`),this.issues.length>0&&(e+="\nIssues:\n"+this.issues.map(((e,t)=>` ${t+1}. ${e.message} [${e.code}]`)).join("\n")),this.cause&&(e+=`\nCause: ${this.cause instanceof Error?this.cause.message:String(this.cause)}`),e}},n="SYS-001",o=(e,t)=>new r({code:n,message:t,cause:e}),a=e=>({ok:!0,value:e}),c=e=>({ok:!1,error:e}),d=class e extends r{constructor(t,s){super({code:"SYNC_ERROR",message:t,cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},h=class e extends d{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},u=class e extends d{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},l=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}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 s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,r)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),r(new h("Mutex lock timed out"))}),e)}))])}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?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},p=class{mutex=new l({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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{this._value=await e(),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")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}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(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,r)=>{i=setTimeout((()=>r(new h(s))),t)}))])}},g=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new l({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new u};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,i=null;try{if(this._done)throw new u;i=await e(),this._lastValue=i,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:i,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},f=class{constructor(t,s,i,r,n){this.pipeline=t,this.stepKey=s,this.params=i,r&&(r.aborted&&this.controller.abort(),r.addEventListener("abort",(()=>this.controller.abort()))),this.localBus=n??e()}id=Math.random().toString(36).substring(2,9);localBus;controller=new AbortController;once=new p({retry:!1,throws:!1});get signal(){return this.controller.signal}on(e,t){return this.localBus.subscribe(e,t)}abort(){this.controller.abort()}async run(){const{value:e,error:t}=await this.once.do((()=>this._run()));return t?c(t):e}async _run(){const e=this.pipeline.getSteps().get(this.stepKey);if(!e)return{ok:!1,error:new r({code:s.INVALID_COMMAND.code,message:`No step registered with key "${this.stepKey}"`,operation:this.stepKey})};if(this.signal.aborted)return this.failCancelled("Pipeline execution aborted before initialization",this.stepKey);const t=this.pipeline.groupByOrder(),i=Array.from(t.entries()).sort((([e],[t])=>e-t)),n=e.order;this.emit("start",{stepKey:this.stepKey,executionId:this.id});let o={[this.stepKey]:this.params},a=o,c=!0;for(const[e,t]of i){if(e<n)continue;if(this.signal.aborted)return this.failCancelled(`Pipeline runtime aborted at stage ${e}`,this.stepKey);const s=c?t.filter((e=>e.key===this.stepKey)):t;if(c=!1,0===s.length)continue;const i=await this.runStage(s,o);if(!i.ok)return i;a=i.value,o={...o,...a},this.emit("stage:success",{order:e,executionId:this.id,carry:a})}return this.emit("terminate",{carry:a,executionId:this.id}),{ok:!0,value:a}}async runStage(e,t){const s=await Promise.all(e.map((async e=>{try{if(this.signal.aborted)return{step:e,result:this.failCancelled("Aborted mid-flight execution sequence",e.key)};const s=await e.action(t,this.signal);return{step:e,result:s}}catch(t){return{step:e,result:{ok:!1,error:t instanceof r?t:o(t,t instanceof Error?t.message:"Unexpected exception raised during step run")}}}}))),i={};let n=null;for(const{step:e,result:t}of s)if(t.ok)this.emit("step:success",{stepKey:e.key,executionId:this.id,result:t.value}),i[e.key]=t.value;else{const s=t.error.withOperation(e.key);this.emit("step:failure",{stepKey:e.key,executionId:this.id,error:s}),n||(n={ok:!1,error:s},this.emit("failure",{stepKey:e.key,executionId:this.id,error:s}))}return n||{ok:!0,value:i}}emit(e,t){this.localBus.emit({name:e,payload:t})}failCancelled(e,t){return{ok:!1,error:new r({code:"CANCELLED",message:e,operation:t})}}},y=class{steps=new Map;globalBus=e();serializer=new g;executions=new Map;constructor(e){e&&e.forEach(((e,t)=>{(Array.isArray(e)?e:[e]).forEach((e=>this.steps.set(e.key,{...e,order:t})))}))}getSteps(){return this.steps}step(e){return this.steps.set(e.key,e),this}on(e,t){return this.globalBus.subscribe(e,t)}prepare(e,t,s,i){return new f(this,e,t,s?.signal,i)}async execute(e,t,s){const i=s?.disableDeduplication?`${e}:${Date.now()}:${Math.random()}`:this.getDedupeKey(e,t);let r=this.executions.get(i);r||(r=new p({retry:!0,throws:!1}),this.executions.set(i,r));const n=await r.do((async()=>{const i=await this.serializer.do((async()=>{const i=this.prepare(e,t,{signal:s?.signal},this.globalBus);return await i.run()}));if(i.error)throw i.error;return i.value})).finally((()=>{setTimeout((()=>this.executions.delete(i)),0)}));return n.error?c(n.error):n.value}getRegisteredSteps(){return Array.from(this.steps.keys())}validate(){const e=[];return 0===this.steps.size&&e.push("Pipeline has no registered steps"),e}destroy(){this.steps.clear(),this.globalBus.clear(),this.executions.clear()}groupByOrder(){const e=new Map;for(const t of this.steps.values()){const s=e.get(t.order)??[];s.push(t),e.set(t.order,s)}return e}getDedupeKey(e,t){try{return`${e}:${JSON.stringify(this.sortObjectKeys(t))}`}catch{return`${e}:${Date.now()}:${Math.random()}`}}sortObjectKeys(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map((e=>this.sortObjectKeys(e)));const t={};return Object.keys(e).sort().forEach((s=>{t[s]=this.sortObjectKeys(e[s])})),t}},m=class{constructor(e,t,s={}){this.factory=e,this.onCleanup=t,this.options=s}_count=0;init=new p({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask((()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())}))):void(this.cleanupTimer=setTimeout((()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()}),e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}};function w(e,t){if(!e.length)return;const s=e.slice(),i=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=s.length-1;e>=0;e--)try{await s[e]()}catch(t){console.error(`${i} Cleanup error at index ${e}:`,t)}}}async function v(e,t){const s=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${s} Cleanup error at index ${t}:`,e)}}function b(e){return`${e}__watched`}var k=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function S(e,t){let s;const i=new Promise(((e,i)=>{s=setTimeout((()=>i(new Error(`Timeout: ${t}ms`))),t)}));try{return Promise.race([e,i])}finally{clearTimeout(s)}}async function I(e){const t=(new TextEncoder).encode(e),s=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(s)).map((e=>e.toString(16).padStart(2,"0"))).join("")}var A=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,s){const i=this.get(e);if(!i)return k;if(i.package)return i.package;const r=e,n=w(i.cleanupFunctions,r),o="singleton"!==i.scope||void 0!==i.instance,a={instance:i.instance,error:i.error,ready:o,[s||e]:i.instance,cleanup:n,invalidate:t};return i.package=a,a}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const s=this.get(e);if(!s)return;const i=e;"singleton"===s.scope&&(s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),s.controller.abort(),await s.streamOnce.current(),s.streamSerializer.close(),s.stream=void 0,s.streamOnce=new p({retry:!0,throws:!0}),t||(s.streamSerializer=new g,s.controller=new AbortController)),await v(s.cleanupFunctions,i),await v(s.disposeFunctions,i),s.cleanupFunctions=[],s.disposeFunctions=[],"singleton"===s.scope&&(s.buildOnce=new p({retry:!0,throws:!0})),s.instance=void 0,s.error=void 0}},x=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const s of t)this.dependents.get(s)?.delete(e);const s=this.dependents.get(e);if(s)for(const t of s)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.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}iterDependents(e){return this.dependents.get(e)??_}setDependencies(e,t){this.registerNode(e);const s=this.dependencies.get(e),i=new Set(t);for(const t of s)i.has(t)||this.removeDependency(e,t);for(const t of i)s.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const s=[t],i=new Set([t]),r=new Map;for(;s.length>0;){const n=s.shift();if(n===e){const s=[];let i=e;for(;void 0!==i&&(s.push(i),i!==t);)i=r.get(i);return s.reverse(),s.unshift(e),s}const o=this.dependencies.get(n);if(o)for(const e of o)i.has(e)||(i.add(e),r.set(e,n),s.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const s of t)e.set(s,this.dependencies.get(s)?.size??0);const s=[];for(const[t,i]of e)0===i&&s.push(t);const i=[];for(;s.length>0;){const t=s.shift();i.push(t);const r=this.dependents.get(t);if(r)for(const t of r){const i=(e.get(t)||0)-1;e.set(t,i),0===i&&s.push(t)}}if(i.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return i}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,s){const i=new Set,r=new Set,n=[e];r.add(e),s&&i.add(e);const o="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=o.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),i.add(e),n.push(e))}return i}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const s=Array.from(t).join(", ");return`${String(e)} → [${s||"∅"}]`})).join("\n")}},_=new Set,E=class{graph;constructor(){this.graph=new x}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){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}setDependencies(e,t){const s=Array.from(t).map((e=>e));this.graph.setDependencies(e,s)}wouldCreateCycle(e,t,s){if(s?.has(t)){const e=Array.from(s),i=e.indexOf(t),r=e.slice(i);return r.push(t),r}const i=this.graph.wouldCreateCycle(e,t);return i||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()}},$=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];var O=class e extends Error{category;constructor(t,s,i){super(t,{cause:i}),this.name="ArtifactError",this.category=s,Object.setPrototypeOf(this,e.prototype)}},C=class extends O{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},D=class extends O{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},R=class extends O{constructor(e){super(e,"system"),this.name="InvalidImportError"}},T=class extends O{constructor(e){super(`Artifact "${e}" instance is not JSON-serializable (POJO are required for persistence)`,"system"),this.name="InvalidExportOperationError"}},P=(new AbortController).signal,N=class{constructor(e,t,s,i,r){this.registry=e,this.cache=t,this.graph=s,this.store=i,this.observer=r}async build(e,t,s){const i=this.cache.get(e);if("singleton"===i?.scope&&i.buildOnce.done())return this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s);const r=this.registry.getByString(e);if(!r)throw new C(e);const n=t??[];if(n.includes(e))throw new O(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${[...n,e].join(" -> ")}`,"system");n.push(e);let o=i;o||(o=this.createCachedArtifact(r),this.cache.set(e,o));try{if("transient"===o.scope)return this.executeBuild(r,o,n);const i=o;try{await i.buildOnce.do((()=>this.executeBuild(r,i,n)))}catch(i){if(i instanceof D)return this.build(e,t,s);throw i}return i.stream&&i.streamOnce.do(i.stream),this.cache.package(e,((t,s)=>this.invalidate(e,t,s)),s)}finally{n.pop()}}async executeBuild(e,t,s){const i=e.key,r=String(i),n="transient"===t.scope;t.buildCount++,"singleton"===t.scope&&(t.activeDebounceMs=e.debounce??0);const o={cleanupFunctions:[],disposeFunctions:[],capturedArtifactDeps:new Set,capturedStateSelectors:[],dependencyVersions:new Map},a=this.buildContext(e,t,s,r,o),c=await this.runWithRetries(e,a,o.dependencyVersions);if(this.commitResult(i,t,n,c,o),n){const e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[i]:e,cleanup:w(o.cleanupFunctions,r),invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${r}"`)}}}buildContext(e,t,s,i,r){const n=e.key,o="transient"===t.scope,{cleanupFunctions:a,disposeFunctions:c,capturedArtifactDeps:d,dependencyVersions:h,capturedStateSelectors:u}=r,l=async(e,t)=>{const r=t?this.computeParamKey(e,t):e;if(r===n)throw new O(`Artifact "${i}" depends on itself.`,"system");const o=this.graph.wouldCreateCycle(n,r);if(o)throw new O(`Adding dependency "${String(r)}" to "${i}" would create a cycle: ${o.join(" -> ")}`,"system");d.add(r);const a=await(t?this.resolveParameterized(e,t):this.build(e,s)),c=this.cache.get(r);return c&&h.set(r,c.version),a},p="singleton"===t.scope?t.controller.signal:P,g=async(e,t)=>{const s=await l(e,t);if(s.error)throw s.error;return s.instance},f=(e,t)=>{const s=function(e,t="."){const s=new Set,i=new Map,r=(e="")=>{if(i.has(e))return i.get(e);const n=new Proxy((()=>{}),{get:(i,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic, arithmetic, or string operations inside a selector.");if($.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const o=e?`${e}${t}${n}`:n;return e&&s.delete(e),s.add(o),r(o)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions or methods.")}});return i.set(e,n),n};try{e(r())}catch(e){throw new Error(`Selector failed during path analysis. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(s)}(e);return u.push({paths:s,options:t}),e(this.store.get(!0))};return{state:()=>this.store.get(!0),previous:t.instance,signal:p,onCleanup:e=>a.push(e),onDispose:e=>c.push(e),use:e=>e({resolve:l,require:g,select:f}),stream:e=>{if(o)throw new O(`[ArtifactManager] Illegal stream on transient artifact "${i}"`,"system");const s=t,r=async(e,t=void 0)=>{await s.streamSerializer.do((async()=>{void 0!==s.stream&&(s.instance=e,s.error=t,s.version++,this.cache.invalidatePackage(n),await this.processStream(i))}))},a={value:()=>s.instance,get signal(){return s.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>r(e)};s.stream=async()=>{try{const t=await e(a);t&&s.cleanupFunctions.push(t)}catch(e){await r(void 0,e),await this.invalidate(n,!1,!0)}}}}}async runWithRetries(e,t,s){const i=t.signal,r=(e.retries??0)+1;let n=0;for(;n<r;)try{if(i.aborted)throw new D;const o=e.factory(t);let a;if(a=o instanceof Promise?e.timeout?await S(o,e.timeout):await o:o,i.aborted)throw new D;const c=this.detectStaleness(s);if(c){if(n++,s.clear(),n<r)continue;return{ok:!1,error:new O(`Build stale after all retries: dependency "${String(c)}" changed during build.`,"system")}}return{ok:!0,value:a}}catch(e){if(i.aborted||e instanceof D)throw new D;if(e instanceof O)throw e;if(n++,n>=r)return{ok:!1,error:e}}return{ok:!1,error:new Error("Build exhausted retry budget unexpectedly.")}}commitResult(e,t,s,i,r){const{cleanupFunctions:n,disposeFunctions:o,capturedArtifactDeps:a,capturedStateSelectors:c}=r;s||(this.updateDependencyGraph(e,a,c),t.cleanupFunctions=n,t.disposeFunctions=o,t.artifactDependencies=new Set(a),t.stateGroups=c.map((({paths:e,options:t})=>({paths:e,options:t})))),i.ok?(t.instance=i.value,t.error=void 0):(t.instance=void 0,t.error=i.error),t.version++,this.cache.invalidatePackage(e)}detectStaleness(e){for(const[t,s]of e){const e=this.cache.get(t);if(e&&e.version!==s)return t}return null}async invalidate(e,t=!1,s=!1){const i=this.cache.get(e);if(!i)return;if("singleton"!==i.scope)return this.executeInvalidation(e,t,s);const r=i;return r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0),!t&&r.activeDebounceMs>0?new Promise(((i,n)=>{r.debounceTimer=setTimeout((()=>{r.debounceTimer=void 0,this.executeInvalidation(e,t,s).then(i).catch(n)}),r.activeDebounceMs)})):this.executeInvalidation(e,t,s)}async executeInvalidation(e,t,s=!1){const i=this.cache.get(e);i&&"singleton"===i.scope&&await i.invalidationSerializer.do((async()=>{i.version++,await this.cache.invalidateInstance(e),await this.cascadeInvalidation(this.graph.iterDependents(e));const r=this.registry.get(e),n=r&&(t||!r.lazy||this.observer.hasWatchers(e))&&!s;n&&await this.build(e).catch((t=>{t instanceof D||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),(n||s)&&this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(0===e.size)return;const t=[];for(const s of e)t.push(this.invalidate(s).catch((e=>{console.error(`[ArtifactManager] Cascade failed for "${String(s)}":`,e)})));await Promise.all(t)}updateDependencyGraph(e,t,s){const i=this.cache.get(e);if(!i||"singleton"!==i.scope)return;this.graph.registerNode(e),this.graph.setDependencies(e,t),i.stateDependencies=new Set;for(const{paths:e}of s)for(const t of e)i.stateDependencies.add(t);if(i.stateUnsubscribe&&(i.stateUnsubscribe(),i.stateUnsubscribe=void 0),0===s.length)return;const r=()=>this.invalidate(e),n=new Map;for(const{paths:e,options:t}of s){const s=void 0===t?"undefined":JSON.stringify(t);let i=n.get(s);i||(i={options:t,paths:new Set},n.set(s,i));for(const t of e)i.paths.add(t)}const o=[];for(const{options:e,paths:t}of n.values()){if(0===t.size)continue;const s=Array.from(t);void 0===e?o.push(this.store.watch(s,r)):o.push(this.store.watch(s,r,e))}0===o.length?i.stateUnsubscribe=void 0:1===o.length?i.stateUnsubscribe=o[0]:i.stateUnsubscribe=()=>{for(const e of o)e()}}createCachedArtifact(e){return"transient"===e.scope?{scope:"transient",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:"singleton",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce?e.debounce:0,controller:new AbortController,buildOnce:new p({retry:!0,throws:!0}),streamOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateGroups:[],artifactDependencies:new Set}}resolveStatic(e){if(!this.registry.has(e))throw new C(e);return this.build(e)}async resolveParameterized(e,t){if(!this.registry.has(e))throw new C(String(e));const s=this.registry.get(e);if(!s.paramKey)throw new O(`Artifact "${String(e)}" is not parameterized.`,"external");const i=s.paramKey(t),r=this.registry.getByString(i);if(r&&!r.paramKey&&!r.virtual)throw new O(`Parameterized artifact "${String(e)}" with params ${JSON.stringify(t)} resolves to key "${i}" which is already registered as a static artifact.`,"system");return this.registry.hasString(i)||this.registry.setVirtual(i,{key:i,factory:e=>s.factory({...e,params:t}),scope:s.scope,lazy:s.lazy,timeout:s.timeout,retries:s.retries,debounce:s.debounce,virtual:!0}),this.build(i,void 0,e)}computeParamKey(e,t){const s=this.registry.get(e);if(!s.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);return s.paramKey(t)}},M=class{constructor(e,t,s){this.registry=e,this.cache=t,this.container=s}listeners=new Map;watchers=new Map;watch(e,t=6e4){return this.watchForKey(e,this.registry.get(e),t)}watchParameterized(e,t,s=6e4){const i=this.registry.get(e);if(!i.paramKey)throw new Error(`Artifact "${String(e)}" is not parameterized.`);const r=i.paramKey(t);return this.watchForKey(r,i,s,t)}watchForKey(e,t,s,i){const r="transient"===t.scope,n=r?b(e):e,o=this.watchers.get(n);if(o)return o.observer;const a=new m((async()=>{!r&&void 0===i||this.registry.hasString(e)||this.registry.setVirtual(e,{key:e,factory:r?t.factory:e=>t.factory({...e,params:i}),scope:r?"singleton":t.scope,lazy:t.lazy,timeout:t.timeout,retries:t.retries,debounce:t.debounce,paramKey:t.paramKey,virtual:!0})}),(async()=>{r||void 0!==i?(await this.registry.unregister(n).catch((()=>{})),this.cache.delete(n),this.watchers.delete(n)):this.cache.invalidatePackage(n),this.listeners.delete(n)}),{gracePeriod:r&&void 0===i?"sync":s});let c;const d={id:n,get count(){return a.subscribers},get:(t=!1)=>0!==a.subscribers||t?this.cache.package(n,((e,t)=>this.container.invalidate(n,e,t)),e):k,resolve:()=>c||(c=(async()=>{await a.acquire();try{return await this.container.resolve(n)}finally{a.release(),c=void 0}})(),c),subscribe:(e,t=!0)=>{const s=()=>e(d.get());return a.acquire().then((()=>{this.container.resolve(n).then((()=>{this.listeners.has(n)||this.listeners.set(n,new Set),t&&s(),this.listeners.get(n).add(s)}))})).catch((e=>{console.error(`[ArtifactObserver] Resolution failed for "${n}":`,e),this.listeners.get(n)?.add(s)})),()=>{this.listeners.get(n)?.delete(s),a.release()}}};return this.watchers.set(n,{resource:a,observer:d}),d}evictWatcher(e){[e,b(e)].forEach((e=>{const t=this.watchers.get(e);t&&(t.resource.forceCleanup(),this.watchers.delete(e))}))}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const s of t)try{s()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return this.watchers.has(e)||this.watchers.has(b(e))}getWatcherCount(e){const t=this.watchers.get(e)||this.watchers.get(b(e));return t?.resource.subscribers??0}clear(){this.watchers.clear(),this.listeners.clear()}},L=class{artifacts=new Map;register({key:e,factory:t,lazy:s,...i}){const{scope:r,...n}=i,o={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===s||s,...n};return this.artifacts.set(e,o),()=>this.unregister(e)}setVirtual(e,t){this.artifacts.set(e,t)}get(e){if(!this.has(e))throw new C(String(e));return this.artifacts.get(e)}getByString(e){return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}hasString(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()}},F=class e{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t),subset:(...t)=>e.subset(...t)},this.registry=new L,this.cache=new A,this.graph=new E,this.observer=new M(this.registry,this.cache,this),this.manager=new N(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const s=t,i=this.registry.get(s),r=this.cache.get(s);if(!i)return;let n="idle";r&&("singleton"===r.scope&&void 0!==r.debounceTimer?n="debouncing":"singleton"===r.scope&&r.buildOnce.running()?n="building":r.error?n="error":void 0!==r.instance&&(n="active")),e.push({id:s,scope:i.scope??"singleton",status:n,dependencies:this.graph.getDependencies(s).map((e=>String(e))),dependents:this.graph.getDependents(s).map((e=>String(e))),stateDependencies:"singleton"===r?.scope?Array.from(r.stateDependencies):[],buildCount:r?.buildCount??0})})),e}register(e){const{key:t}=e,s=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${s}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${s}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const i=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==i||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${s}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;await this.manager.dispose(s),await this.registry.unregister(s),this.observer.evictWatcher(s)}async resolve(e,t){return void 0===t?this.manager.resolveStatic(e):this.manager.resolveParameterized(e,t)}async require(e,t){const s=await this.resolve(e,t);if(s.error)throw s.error;return s.instance}watch(e,t,s){return void 0===t?this.observer.watch(e,s):this.observer.watchParameterized(e,t,s)}peek(e,t){const s=void 0!==t?this.manager.computeParamKey(e,t):e;return this.cache.get(s)?.instance}async invalidate(e,t){const s=t?.params,i=t?.replace??!1,r=void 0!==s?this.manager.computeParamKey(e,s):e;return this.manager.invalidate(r,i)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((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()}async export(){const e=[];for(const t of this.cache.keys()){const s=this.cache.get(t);if(!s||"singleton"!==s.scope)continue;if(void 0===s.instance)continue;const i=new Set;for(const e of s.stateGroups)for(const t of e.paths)i.add(t);const r=Array.from(i).sort(),n=this.store.subset(r),o=await I(JSON.stringify(n,Object.keys(n).sort()));let a;try{a=structuredClone(s.instance)}catch(e){throw new T(t)}e.push({key:t,instance:a,state:{groups:s.stateGroups.map((e=>({paths:e.paths,options:e.options}))),hash:o},dependencies:Array.from(s.artifactDependencies)})}const t={...{version:"1.0",timestamp:Date.now(),artifacts:e}},s=JSON.stringify(t),i=await I(s);return{...t,checksum:i}}async restore(e){const{checksum:t,...s}=e;if(await I(JSON.stringify(s))!==t)throw new R("Bundle checksum mismatch – data corrupted");if("1.0"!==e.version)throw new R(`Unsupported bundle version: ${e.version}`);const i=new Map;for(const t of e.artifacts)i.set(t.key,t);const r=new Set,n=new Map;for(const t of e.artifacts)for(const e of t.dependencies)n.has(e)||n.set(e,new Set),n.get(e).add(t.key);const o=async e=>{const t=new Set;for(const s of e.state.groups)for(const e of s.paths)t.add(e);const s=Array.from(t).sort(),i=this.store.subset(s);return I(JSON.stringify(i,Object.keys(i).sort()))};for(const t of e.artifacts){await o(t)!==t.state.hash&&r.add(t.key)}const a=Array.from(r);for(;a.length;){const e=a.shift(),t=n.get(e);if(t)for(const e of t)r.has(e)||(r.add(e),a.push(e))}for(const t of e.artifacts){if(r.has(t.key))continue;this.cache.get(t.key)&&await this.cache.invalidateInstance(t.key,!1);const e={scope:"singleton",instance:t.instance,error:void 0,version:1,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set(t.state.groups.flatMap((e=>e.paths))),activeDebounceMs:0,buildOnce:new p({retry:!0,throws:!0}),streamSerializer:new g({yieldMode:"microtask"}),invalidationSerializer:new g({yieldMode:"macrotask"}),stateUnsubscribe:void 0,debounceTimer:void 0,controller:new AbortController,streamOnce:new p({retry:!0,throws:!0}),stream:void 0,stateGroups:t.state.groups,artifactDependencies:new Set(t.dependencies)};e.buildOnce.resolve(t.instance),this.cache.set(t.key,e);const s=[];for(const e of t.state.groups){const i=this.store.watch(e.paths,(()=>this.invalidate(t.key)),e.options);s.push(i)}e.stateUnsubscribe=()=>{for(const e of s)e()},this.graph.setDependencies(t.key,t.dependencies)}}static async from(t){const s=new e(t.store);if(t.bundle){if("object"!=typeof t.bundle||!t.bundle.version||!Array.isArray(t.bundle.artifacts))throw new R("Invalid bundle: missing version or artifacts array");await s.restore(t.bundle)}for(const e of t.templates)s.register(e);return s}},z={info:()=>{},error:()=>{},warn:()=>{}},K=class e{static instances=new Map;static default=new e;static get(t,s){return e.instances.has(t)||e.instances.set(t,new e(s)),e.instances.get(t)}static destroy(t){const s=e.instances.get(t);s&&(s.dispose(),e.instances.delete(t))}defaultPauseTimeout;onExpired;onExportFailed;logger;records=new Map;weakIndex=new Map;finalizer=new FinalizationRegistry((e=>this.weakIndex.delete(e)));constructor(e={}){this.defaultPauseTimeout=e.defaultPauseTimeout??3e5,this.onExpired=e.onExpired,this.onExportFailed=e.onExportFailed,this.logger=e.logger??z}register(e,t){if(this.records.has(e.id))return void this.logger.info(`Run "${e.id}" already registered, skipping.`);const s=e.__registryContainer;s||this.logger.warn(`Run "${e.id}" does not expose __registryContainer — deferred export will be skipped.`);const i={runId:e.id,pipelineId:e.__registryPipelineId??"unknown",startedAt:(new Date).toISOString(),status:"prepared",pausedAt:void 0,checkpoint:void 0,context:e,store:t,container:s,cleanupTimer:void 0,unsubscribers:[]};i.unsubscribers.push(e.on("pipeline:start",(e=>this.onRun(e))),e.on("pipeline:paused",(e=>this.onPaused(e))),e.on("pipeline:success",(e=>this.onSucceeded(e.runId))),e.on("pipeline:failure",(e=>this.onFailed(e.runId)))),this.records.set(e.id,i);const r=new WeakRef(e);this.weakIndex.set(e.id,r),this.finalizer.register(e,e.id,r),this.logger.info(`Registered run "${e.id}" [${i.pipelineId}]`)}getCheckpoint(e){const t=this.records.get(e);return t&&"paused"===t.status?t.checkpoint??null:null}getLiveContext(e){const t=this.records.get(e);return t&&"paused"===t.status&&null!==t.context?(this.cancelTimer(t),this.logger.info(`Fast-path resume for run "${e}" — live context returned, timer cancelled.`),t.status="running",t.pausedAt=void 0,t.checkpoint=void 0,t.context):null}list(){return Array.from(this.records.values()).map(B)}listByStatus(e){return Array.from(this.records.values()).filter((t=>t.status===e)).map(B)}has(e){return this.records.has(e)}get(e){const t=this.records.get(e);return t?B(t):void 0}prune(){let e=0;for(const[t,s]of this.records)"succeeded"!==s.status&&"failed"!==s.status||null!==s.context?"paused"===s.status&&null===s.context&&(this.records.delete(t),e++):(this.records.delete(t),e++);e>0&&this.logger.info(`Pruned ${e} terminal run records.`)}dispose(){for(const e of this.records.values())this.cancelTimer(e),this.unwire(e),e.context=null;this.logger.info("Registry disposed.")}onRun(e){const t=this.records.get(e.runId);t?t.status="running":this.logger.warn(`pipeline:paused received for untracked run "${e.runId}".`)}onPaused(e){const t=this.records.get(e.runId);if(!t)return void this.logger.warn(`pipeline:paused received for untracked run "${e.runId}".`);t.status="paused",t.pausedAt=(new Date).toISOString(),t.checkpoint=e.checkpoint;const s=e.pauseTimeout??this.defaultPauseTimeout;this.logger.info(`Run "${e.runId}" paused. Cleanup timer armed for ${s}ms.`),0===s?this.runExpirySequence(t):t.cleanupTimer=setTimeout((()=>{this.runExpirySequence(t)}),s)}onSucceeded(e){const t=this.records.get(e);t&&(t.status="succeeded",this.cancelTimer(t),this.unwire(t),t.context=null,this.logger.info(`Run "${e}" succeeded. Strong reference released.`))}onFailed(e){const t=this.records.get(e);t&&(t.status="failed",this.cancelTimer(t),this.unwire(t),t.context=null,this.logger.info(`Run "${e}" failed. Strong reference released.`))}async runExpirySequence(e){const{runId:t}=e;if(this.logger.info(`Pause timeout expired for run "${t}". Running deferred export.`),null===e.context||null===e.checkpoint)return;const s=e.checkpoint;try{const i=await e.container.export(),r={...s,containerBundle:i};await Z(e.store,r),e.checkpoint=r,this.logger.info(`Deferred export complete for run "${t}". Checkpoint updated with bundle.`),this.releaseContext(e),this.onExpired?.(t,r)}catch(i){this.logger.error(`Deferred export failed for run "${t}". Clearing checkpoint.`,i);try{await te(e.store,s.pipelineId,t)}catch(e){this.logger.error(`Failed to clear checkpoint for run "${t}" after export failure.`,e)}this.releaseContext(e),this.onExportFailed?.(t,i)}}cancelTimer(e){void 0!==e.cleanupTimer&&(clearTimeout(e.cleanupTimer),e.cleanupTimer=void 0)}unwire(e){for(const t of e.unsubscribers)try{t()}catch{}e.unsubscribers.length=0}releaseContext(e){e.context=null,this.weakIndex.delete(e.runId),this.logger.info(`Strong reference released for run "${e.runId}". Context is GC-eligible.`)}};function B(e){return{runId:e.runId,pipelineId:e.pipelineId,status:e.status,startedAt:e.startedAt,pausedAt:e.pausedAt,checkpoint:e.checkpoint,context:e.context}}function U(e){return"object"==typeof e&&null!==e&&"pause"in e}var j="__pipeline_data__",V="__pipeline_id__";var q=class{constructor(e,t){this.definition=e,this.logger=t.logger??z,this.storeFactory=t.storeFactory,this.initialStateFactory=t.initialStateFactory,this.registry=t.registry||new K({logger:this.logger}),this.index=Y(e)}logger;storeFactory;initialStateFactory;registry;index;async prepare(e,s){const i=s??t(),r=await this.storeFactory(i);await r.ready();const n=this.initialStateFactory?.()??{};await r.set(n),await r.set({[V]:i}),this.logger.info(`Prepared new run "${i}" for pipeline "${this.definition.id}"`);const o=await this.buildRunContext(i,this.definition,e,r,void 0,[]);return this.registry?.register(o,r),o}async resume(e){if(this.registry?.has(e)){const t=this.registry?.getCheckpoint(e),s=this.registry?.getLiveContext(e);if(t&&s)return s.setEntry(t.resumeAt),s.dangerouslyReset(),this.logger.info(`Fast‑path resume for run "${e}"`),a(s)}const t=await this.storeFactory(e),i=t.get()[V];if(i&&i!==e)return c(new r({code:s.INVALID_COMMAND.code,message:`Store contains runId "${i}", but requested "${e}".`,operation:"resume"}));const n=ee(t,void 0,e);if(!n)return c(new r({code:s.NOT_FOUND.code,message:`No checkpoint found for runId "${e}".`,operation:"resume"}));if(n.pipelineId!==this.definition.id)return c(new r({code:s.INVALID_COMMAND.code,message:`Checkpoint runId "${e}" belongs to pipeline "${n.pipelineId}", not "${this.definition.id}" (mismatch-base).`,operation:"resume"}));this.logger.info(`Resuming pipeline "${this.definition.id}" [${e}] from store checkpoint at stage "${n.pausedAtStageId}"`);const o=await this.buildRunContext(e,this.definition,n.resumeAt,t,void 0,[],void 0,void 0,n.containerBundle);return this.registry?.register(o,t),a(o)}async buildRunContext(t,s,i,r,n,o,a,c,d){const h=void 0===a,u=c??"",l=new AbortController,g={runId:t,pipelineId:s.id,signal:l.signal};let f;d?f=await F.from({store:r,bundle:d,templates:G(s,u,g)}):(f=h?new F(r):a,function(e,t,s,i){for(const r of t.stages)if(r.steps)for(const t of Object.values(r.steps)){const n={runId:i.runId,pipelineId:i.pipelineId,stageId:r.id,stepId:t.id,signal:i.signal};e.register({key:J(s,r.id,t.id),factory:e=>t.action(e,n),scope:t.scope,...void 0!==t.timeout&&{timeout:t.timeout},...void 0!==t.retries&&{retries:t.retries}})}}(f,s,u,g));const y=function(e,t){return{emit(s,i){e.emit({name:s,payload:i}),t?.emit(s,i)},on:(t,s)=>e.subscribe(t,s)}}(e(),n),m=new p({retry:!1,throws:!1}),w=h?this.index:Y(s);return new W(t,s,i,r,f,u,y,o,l,m,this.logger,this.definition.id,w,this)}},W=class{constructor(e,t,s,i,r,n,o,a,c,d,h,u,l,p){this.pipeline=t,this.entry=s,this.store=i,this.container=r,this.keyPrefix=n,this.bus=o,this.parentPath=a,this.controller=c,this.once=d,this.logger=h,this.definitionId=u,this.index=l,this.factory=p,this.id=e,this.__registryContainer=r,this.__registryPipelineId=u}id;__registryContainer;__registryPipelineId;on(e,t){return this.bus.on(e,t)}abort(){this.controller.abort()}dangerouslyReset(){this.once.reset()}setEntry(e){this.entry=e}async run(){const e=await this.once.do((()=>this.execute()));return void 0!==e.error?c(new r({code:s.INTERNAL_ERROR.code,message:`Unexpected throw escaped run(): ${X(e.error)}`,operation:`pipeline:${this.pipeline.id}`,cause:e.error})):e.value}async execute(){this.bus.emit("pipeline:start",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id}),this.logger.info(`Pipeline start: ${this.pipeline.id} [${this.id}]`);const e=this.resolveEntryStage();if(!e.ok)return this.failPipeline(e.error);const{stageMap:t,orderedStages:i,stageOrderIndex:n}=this.index;let o=e.value,c=!0;for(;;){if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted before stage "${o.label}".`,operation:`stage:${o.id}`});return this.failPipeline(e)}const e=c?this.entry:void 0;c=!1;const d=await this.executeStage(o,e);if(!d.ok)return this.failPipeline(d.error);if(this.controller.signal.aborted){const e=new r({code:s.OPERATION_ABORTED.code,message:`Run aborted after stage "${o.label}".`,operation:`stage:${o.id}`});return this.failPipeline(e)}const h=d.value,u="pause"===h.kind?void 0:h.nextInstruction,l=n.get(o.id)??-1,p=void 0!==i[l+1],g="pause"===h.kind?"pause":null===u?"terminate":"string"==typeof u?"jump":p?"advance":"natural-end";if(this.bus.emit("router:evaluated",{path:this.parentPath,stageId:o.id,stageLabel:o.label,runId:this.id,instruction:u,interpretation:g}),"pause"===h.kind){const{checkpoint:e,pauseTimeout:t}=h,s=this.store.get(!0);return this.logger.info(`Pipeline paused: ${this.pipeline.id} [${this.id}] at stage "${e.pausedAtStageId}"`+(void 0!==t?` (timeout: ${t}ms)`:"")),this.bus.emit("pipeline:paused",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,checkpoint:e,finalState:s,pauseTimeout:t}),a({status:"paused",runId:this.id,finalState:s,checkpoint:e})}if(null===u)break;if("string"==typeof u){const e=t.get(u);if(!e){const e=new r({code:s.INVALID_COMMAND.code,message:`Router on stage "${o.label}" returned unknown stageId: "${u}"`,operation:`stage:${o.id}`});return this.failPipeline(e)}o=e;continue}const f=i[l+1];if(!f)break;o=f}const d=this.store.get(!0);return this.logger.info(`Pipeline succeeded: ${this.pipeline.id} [${this.id}]`),this.bus.emit("pipeline:success",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,finalState:d}),a({status:"succeeded",runId:this.id,finalState:d})}resolveEntryStage(){const{stageMap:e,orderedStages:t}=this.index;if(this.entry?.stage){const t=e.get(this.entry.stage);return t?a(t):c(new r({code:s.INVALID_COMMAND.code,message:`Entry stage "${this.entry.stage}" not found.`,operation:`pipeline:${this.pipeline.id}`}))}const i=t[0];return i?a(i):c(new r({code:s.INVALID_COMMAND.code,message:"Pipeline has no stages.",operation:`pipeline:${this.pipeline.id}`}))}async executeStage(e,t){const s=e.pipelines&&e.pipelines.length>0?"pipelines":"steps",i=[...this.parentPath,{kind:"stage",id:e.id,label:e.label}];this.bus.emit("stage:start",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,mode:s});const r="pipelines"===s?await this.executePipelinesStage(e,i,t):await this.executeStepsStage(e,i,t);return r.ok?"pause"===r.value.kind?this.bus.emit("stage:paused",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,checkpoint:r.value.checkpoint}):this.bus.emit("stage:success",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,nextInstruction:r.value.nextInstruction}):this.bus.emit("stage:failure",{path:this.parentPath,stageId:e.id,stageLabel:e.label,runId:this.id,error:r.error}),r}async executeStepsStage(e,t,i){const n=Object.values(e.steps??{});if(0===n.length){this.logger.info(`Stage "${e.label}" has no steps — skipping.`);const t=H(e.router,this.store.get(!0),{});if(U(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};return await Z(this.store,s),a({kind:"pause",checkpoint:s,pauseTimeout:t.timeout})}return a(Q(t))}if(this.controller.signal.aborted)return c(new r({code:s.OPERATION_ABORTED.code,message:`Aborted before resolving steps in stage "${e.label}".`,operation:`stage:${e.id}`}));const o=void 0!==i?.step?n.filter((e=>e.id===i.step)):n;if(void 0!==i?.step&&0===o.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry step "${i.step}" not found in stage "${e.label}".`,operation:`stage:${e.id}`}));for(const e of o)this.bus.emit("step:start",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id});const d=await Promise.all(o.map((async t=>({step:t,result:await this.container.resolve(J(this.keyPrefix,e.id,t.id))})))),h={};for(const{step:e,result:i}of d)i.ready?(this.bus.emit("step:success",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id}),h[e.id]=a(i.instance)):(this.bus.emit("step:failure",{path:t,stepId:e.id,stepLabel:e.label,runId:this.id,error:i.error}),h[e.id]=c(new r({code:s.BACKEND_ERROR.code,message:X(i.error)})));const u=d.find((({result:e})=>!e.ready));if(u){const e=u.result.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Step "${u.step.label}" failed: ${X(e)}`,operation:`step:${u.step.id}`,cause:e}))}const l=d.map((({result:e})=>e.instance)).filter((e=>null!=e));let p;try{await this.store.transaction((async()=>{for(const e of l)await this.store.set(e);const t=H(e.router,this.store.get(!0),h);if(U(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await Z(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=Q(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed during stage "${e.label}": ${X(t)}`,operation:`stage:${e.id}`,cause:t}))}return a(p)}async executePipelinesStage(e,t,i){const n=e.pipelines,o=void 0!==i?.pipeline?(()=>{const{index:e}=i.pipeline,t=n[e];return t?[{subPipeline:t,originalIndex:e}]:[]})():n.map(((e,t)=>({subPipeline:e,originalIndex:t})));if(void 0!==i?.pipeline&&0===o.length)return c(new r({code:s.INVALID_COMMAND.code,message:`Entry sub‑pipeline index ${i.pipeline.index} out of bounds.`,operation:`stage:${e.id}`}));this.bus.emit("subpipeline:fork",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,subPipelineIds:o.map((({subPipeline:e})=>e.id))});const d=await Promise.all(o.map((async({subPipeline:s,originalIndex:r})=>{const n=void 0!==i?.pipeline?{stage:i.pipeline.stage,step:i.pipeline.step}:void 0,o=function(e,t,s){const i=`${t}:pipeline-${s}`;return e?`${e}:${i}`:i}(this.keyPrefix,e.id,r);return{subPipeline:s,originalIndex:r,ctx:await this.factory.buildRunContext(this.id,s,n,this.store,this.bus,t,this.container,o)}}))),h=()=>{d.forEach((({ctx:e})=>e.abort()))};this.controller.signal.addEventListener("abort",h,{once:!0});try{if(this.controller.signal.aborted)return h(),c(new r({code:s.OPERATION_ABORTED.code,message:this.controller.signal.reason,operation:`stage:${e.id}`}));const i=await Promise.all(d.map((({ctx:e})=>e.run()))),n={};for(let e=0;e<o.length;e++)n[o[e].subPipeline.id]=i[e];this.bus.emit("subpipeline:join",{path:t,stageId:e.id,stageLabel:e.label,runId:this.id,results:n});const u=i.findIndex((e=>!e.ok||"failed"===e.value.status));if(-1!==u){const t=o[u].subPipeline.id,n=i[u],a=n.ok?n.value.error:n.error;return c(new r({code:s.BACKEND_ERROR.code,message:`Sub‑pipeline "${t}" failed: ${X(a)}`,operation:`stage:${e.id}`,cause:a}))}const l=i.findIndex((e=>e.ok&&"paused"===e.value.status));if(-1!==l){const t=i[l].value,{checkpoint:n}=t,d={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:e.id,pipeline:{index:o[l].originalIndex,stage:n.resumeAt.stage,step:n.resumeAt.step}},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};try{await this.store.transaction((async()=>{await Z(this.store,d)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Failed to write parent pause checkpoint for stage "${e.label}".`,operation:`stage:${e.id}`,cause:t}))}return a({kind:"pause",checkpoint:d,pauseTimeout:void 0})}let p;try{await this.store.transaction((async()=>{const t=H(e.pipelinesRouter,this.store.get(!0),n);if(U(t)){const s={runId:this.id,pipelineId:this.definitionId,resumeAt:{stage:t.pause},pausedAtStageId:e.id,pausedAtStageLabel:e.label,pausedOn:(new Date).toISOString()};await Z(this.store,s),p={kind:"pause",checkpoint:s,pauseTimeout:t.timeout}}else p=Q(t)}),{flush:!0})}catch(t){return c(new r({code:s.CONCURRENCY_ERROR.code,message:`Transaction failed evaluating router for stage "${e.label}": ${X(t)}`,operation:`stage:${e.id}`,cause:t}))}return a(p)}finally{this.controller.signal.removeEventListener("abort",h)}}failPipeline(e){return this.bus.emit("pipeline:failure",{path:this.parentPath,pipelineId:this.pipeline.id,pipelineLabel:this.pipeline.label,runId:this.id,error:e}),c(e)}};function Y(e){const t=[...e.stages].sort(((e,t)=>e.order-t.order)),s=new Map,i=new Map;for(let e=0;e<t.length;e++){const r=t[e];s.set(r.id,r),i.set(r.id,e)}return{stageMap:s,orderedStages:t,stageOrderIndex:i}}function G(e,t,s){const i=[];for(const r of e.stages)if(r.steps)for(const e of Object.values(r.steps)){const n={runId:s.runId,pipelineId:s.pipelineId,stageId:r.id,stepId:e.id,signal:s.signal};i.push({key:J(t,r.id,e.id),factory:t=>e.action(t,n),scope:e.scope,...void 0!==e.timeout&&{timeout:e.timeout},...void 0!==e.retries&&{retries:e.retries}})}return i}function J(e,t,s){return e?`${e}:${t}:${s}`:`${t}:${s}`}function H(e,t,s){return e?e(t,s):void 0}function Q(e){return{kind:"advance",nextInstruction:e}}function X(e){return e instanceof Error?e.message:String(e)}async function Z(e,t){const s=e,i=t.pipelineId,r=t.runId,n=s.get(!0)[j]??{},o={...n,[i]:{...n[i]??{},[r]:t}};await s.set({[j]:o})}function ee(e,t,s){const i=e.get(!0)[j];if(t)return i?.[t]?.[s]??null;if(i)for(const e in i){const t=i[e][s];if(t)return t}return null}async function te(e,t,s){const i=e,r=i.get(!0)[j]??{},n={...r[t]??{}};delete n[s];const o={...r,[t]:n};await i.set({[j]:o})}export{j as PIPELINE_DATA_KEY,V as PIPELINE_RUN_ID_KEY,y as Pipeline,q as PipelineFactory,K as PipelineRegistry,f as SequentialExecutionContext,te as clearCheckpoint,U as isPauseInstruction,ee as readCheckpoint,Z as writeCheckpoint};
|