injeca 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,2 +1,199 @@
1
- import { A as resolve, C as ProvidedBy, D as invoke, E as createContainer, F as createDefaultLogger, I as createLoggLogger, L as createNoopLogger, M as stop, N as Logger, O as lifecycle, P as LoggerOptions, R as Lifecycle, S as ProvideOptionWithKeys, T as ResolveDependencyDeclaration, _ as InvokeOptionWithKeys, b as ProvideOptionObject, c as injeca, d as DependencyMap, f as InferProvided, g as InvokeOptionObjectWithKeys, h as InvokeOptionObject, j as start, k as provide, l as BuildContext, m as InvokeOptionFunc, p as InvokeOption, u as Container, v as ProvideOption, w as ProvidedKey, x as ProvideOptionObjectWithKeys, y as ProvideOptionFunc } from "./global-BLY6_SI_.mjs";
2
- export { BuildContext, Container, DependencyMap, InferProvided, InvokeOption, InvokeOptionFunc, InvokeOptionObject, InvokeOptionObjectWithKeys, InvokeOptionWithKeys, Lifecycle, Logger, LoggerOptions, ProvideOption, ProvideOptionFunc, ProvideOptionObject, ProvideOptionObjectWithKeys, ProvideOptionWithKeys, ProvidedBy, ProvidedKey, ResolveDependencyDeclaration, createContainer, createDefaultLogger, createLoggLogger, createNoopLogger, injeca, invoke, lifecycle, provide, resolve, start, stop };
1
+ import { $ as DecisionSource, A as PeekValue, At as OwnerRecord, B as LifecycleContext, Bt as systemClock, C as GraphDependency, Ct as ProviderInfo, D as ImpactResult, Dt as DependencyChange, E as ImpactChange, Et as ServiceMetadata, F as HookContext, Ft as ServiceState, G as TimeoutContext, Gt as createNoopLogger, H as ContainerOptions, Ht as LoggerOptions, I as HookContextFor, It as ServiceStatus, J as DecideFor, K as TimeoutHandler, L as HookDependencies, Lt as SetStatusOptions, M as DependencyHookContext, Mt as ServiceBlocker, N as Disposer, Nt as ServiceExplanation, O as PeekDependency, Ot as DependencySnapshot, P as EffectSetup, Pt as ServicePhase, Q as DecisionOptions, R as HookHandler, Rt as StatusCause, S as Graph, St as ProvidedKey, T as GraphService, Tt as ResolveDependencyDeclaration, U as HookTimeouts, Ut as createDefaultLogger, V as Container, Vt as Logger, W as PolicyOptions, Wt as createLoggLogger, X as DecisionFor, Y as Decision, Z as DecisionKind, _ as Registration, _t as KeyOptions, a as TransactionReplace, at as HookResult, b as ReplaceOptions, bt as OptionalValue, c as InvokeOptionFunc, ct as RequeueOptions, d as InvokeOptionWithKeys, dt as ConditionalDependency, et as DependencyHook, f as ProvideOption, ft as DependencyDeclaration, g as ProvideOptionWithKeys, gt as InferProvided, h as ProvideOptionObjectWithKeys, ht as FallbackDependency, i as TransactionProvide, it as HookDecisionKind, j as BuildContext, jt as OwnerValue, k as PeekResult, kt as DependencyState, l as InvokeOptionObject, lt as ServiceHook, m as ProvideOptionObject, mt as DependencyMap, n as Transaction, nt as FailDecision, o as InvocationHandle, ot as RebuildDecision, p as ProvideOptionFunc, pt as DependencyDeclarations, q as Decide, r as TransactionCommitOptions, rt as HandledDecision, s as InvokeOption, st as RequeueDecision, t as DeclareOptions, tt as ExponentialBackoff, u as InvokeOptionObjectWithKeys, ut as StopDecision, v as RegistrationOptions, vt as KeyReference, w as GraphResolution, wt as ResolutionCondition, x as WithdrawOptions, xt as ProvidedBy, y as ReplaceFunction, yt as OptionalDependency, z as InvocationContext, zt as Clock } from "./index-DTYp044J.mjs";
2
+ import { A as dispose, C as defineKey, D as invoke, E as where, M as EventKey, N as ListenerEntry, O as DisposeOptions, P as ListenerMetadata, S as stop, T as optional, _ as provide, a as resolve$1, b as StopOptions, c as stop$1, d as graph, f as transaction, g as resolve, h as ResolveOptions, j as effect, k as createContainer, l as listeners, m as withTimeout, n as invoke$1, o as setLogger, p as timeout, r as provide$1, s as start$1, t as getContainer, u as peek, v as listen, w as firstAvailable, x as start, y as StartOptions } from "./global-DPfe26g5.mjs";
3
+ interface ObserveRecordBase {
4
+ /** The key name of the service, or the name of the invocation. */
5
+ readonly key: string;
6
+ /** The owner record of the container of the service. */
7
+ readonly owner: OwnerRecord;
8
+ readonly instanceId: string | undefined;
9
+ readonly reason?: string;
10
+ }
11
+ /** A service moved to another phase. A replayed record has no `from`. */
12
+ interface PhaseObserveRecord extends ObserveRecordBase {
13
+ readonly type: 'phase';
14
+ readonly from: ServicePhase | undefined;
15
+ readonly to: ServicePhase;
16
+ /** The decision that caused the move, when a decision caused it. */
17
+ readonly decision?: DecisionKind;
18
+ }
19
+ /** The effective status of a running instance changed. A replayed record, or the first status of an instance, has no `from`. */
20
+ interface StatusObserveRecord extends ObserveRecordBase {
21
+ readonly type: 'status';
22
+ readonly from: ServiceStatus | undefined;
23
+ readonly to: ServiceStatus;
24
+ readonly cause?: StatusCause;
25
+ }
26
+ /** A hook returned a decision. `ignored` is `true` when injeca did not apply it. */
27
+ interface DecisionObserveRecord extends ObserveRecordBase {
28
+ readonly type: 'decision';
29
+ readonly hook: ServiceHook;
30
+ readonly decision: DecisionKind;
31
+ readonly attempt: number;
32
+ readonly ignored: boolean;
33
+ }
34
+ /** A call that had no effect, for example `setStatus` after the instance was disposed. */
35
+ interface IgnoredObserveRecord extends ObserveRecordBase {
36
+ readonly type: 'ignored';
37
+ readonly call: 'setStatus';
38
+ }
39
+ /** A `start` or `stop` hook did not settle before its configured timeout. The `onTimeout` decision follows as a `decision` record. */
40
+ interface TimeoutObserveRecord extends ObserveRecordBase {
41
+ readonly type: 'timeout';
42
+ readonly hook: 'start' | 'stop';
43
+ readonly timeoutMs: number;
44
+ readonly attempt: number;
45
+ }
46
+ /** A second `provide` of the same key before `start()` replaced the current registration. No hook runs for it. */
47
+ interface RegistrationReplacedObserveRecord extends ObserveRecordBase {
48
+ readonly type: 'registration-replaced';
49
+ readonly reason: string;
50
+ }
51
+ /** A `watch` or `observe` callback threw. The error did not stop a transition or the other callbacks. */
52
+ interface ErrorObserveRecord extends ObserveRecordBase {
53
+ readonly type: 'error';
54
+ readonly error: unknown;
55
+ }
56
+ /**
57
+ * The `signal` of `stop()`, `dispose()`, or `withdraw()` aborted before this service stopped. The call stopped waiting. The cleanups of the service keep running.
58
+ * `phase` is the phase at the abort. `abortReason` is the reason of the signal.
59
+ */
60
+ interface WaitAbortedObserveRecord extends ObserveRecordBase {
61
+ readonly type: 'wait-aborted';
62
+ readonly call: 'stop' | 'dispose' | 'withdraw';
63
+ readonly phase: ServicePhase;
64
+ readonly reason: string;
65
+ readonly abortReason: unknown;
66
+ }
67
+ /**
68
+ * A cleanup called `stop()` or `dispose()` of its own container, or of an ancestor, or `withdraw()` of a registration that waits for that cleanup.
69
+ * The wait includes that cleanup, so injeca resolved the call at once. The action continues.
70
+ * `key` is the service of the cleanup, or `''` for a container effect.
71
+ */
72
+ interface ReentrantCallObserveRecord extends ObserveRecordBase {
73
+ readonly type: 'reentrant-call';
74
+ readonly call: 'stop' | 'dispose' | 'withdraw';
75
+ readonly reason: string;
76
+ }
77
+ /** One record of the observe stream. */
78
+ type ObserveRecord = PhaseObserveRecord | StatusObserveRecord | DecisionObserveRecord | IgnoredObserveRecord | TimeoutObserveRecord | RegistrationReplacedObserveRecord | ErrorObserveRecord | WaitAbortedObserveRecord | ReentrantCallObserveRecord;
79
+ type InjecaErrorCode = 'build-after-dispose' | 'duplicate-service' | 'hook-outside-build' | 'hook-timeout' | 'invalid-argument' | 'invalid-decision' | 'service-failed' | 'replace-while-stopping' | 'stale-registration' | 'start-timeout' | 'transaction-incomplete' | 'wait-timeout';
80
+ interface InjecaErrorOptions {
81
+ cause?: unknown;
82
+ }
83
+ /**
84
+ * The base class of all injeca errors. Use `code` to identify an error. The message text is not stable.
85
+ */
86
+ export declare class InjecaError extends Error {
87
+ readonly code: InjecaErrorCode;
88
+ constructor(code: InjecaErrorCode, message: string, options?: InjecaErrorOptions);
89
+ }
90
+ /** A started container already has a current registration for the key. */
91
+ export declare class DuplicateServiceError extends InjecaError {
92
+ readonly code: 'duplicate-service';
93
+ constructor(message: string, options?: InjecaErrorOptions);
94
+ }
95
+ /** A registration is no longer the current registration of its service. */
96
+ export declare class StaleRegistrationError extends InjecaError {
97
+ readonly code: 'stale-registration';
98
+ constructor(message: string, options?: InjecaErrorOptions);
99
+ }
100
+ /** A hook returned a decision from another run, or a kind that the hook does not accept. */
101
+ export declare class InvalidDecisionError extends InjecaError {
102
+ readonly code: 'invalid-decision';
103
+ constructor(message: string, options?: InjecaErrorOptions);
104
+ }
105
+ /** A caller used a container or an instance after its disposal started. */
106
+ export declare class BuildAfterDisposeError extends InjecaError {
107
+ readonly code: 'build-after-dispose';
108
+ constructor(message: string, options?: InjecaErrorOptions);
109
+ }
110
+ /** `on` was called after `build` settled. */
111
+ export declare class HookOutsideBuildError extends InjecaError {
112
+ readonly code: 'hook-outside-build';
113
+ constructor(message: string, options?: InjecaErrorOptions);
114
+ }
115
+ /** A transaction commit found a declared service without `provide`. */
116
+ export declare class TransactionIncompleteError extends InjecaError {
117
+ readonly code: 'transaction-incomplete';
118
+ constructor(message: string, options?: InjecaErrorOptions);
119
+ }
120
+ /** A `start` or `stop` hook did not settle before its configured timeout. */
121
+ export declare class HookTimeoutError extends InjecaError {
122
+ readonly code: 'hook-timeout';
123
+ readonly hook: 'start' | 'stop';
124
+ readonly timeoutMs: number;
125
+ constructor(message: string, hook: 'start' | 'stop', timeoutMs: number, options?: InjecaErrorOptions);
126
+ }
127
+ /** `replace` was called on a service in `stopping`. */
128
+ export declare class ReplaceWhileStoppingError extends InjecaError {
129
+ readonly code: 'replace-while-stopping';
130
+ constructor(message: string, options?: InjecaErrorOptions);
131
+ }
132
+ /** `start()` did not reach `running` for every service before its configured timeout. */
133
+ export declare class StartTimeoutError extends InjecaError {
134
+ readonly code: 'start-timeout';
135
+ /** One entry for each service or invocation that is not `running`. */
136
+ readonly explanations: readonly ServiceExplanation[];
137
+ constructor(message: string, explanations: readonly ServiceExplanation[], options?: InjecaErrorOptions);
138
+ }
139
+ /** `waitFor()` found the service in `failed`, or waiting for a required provider in `failed`. `cause` is the failure. */
140
+ export declare class ServiceFailedError extends InjecaError {
141
+ readonly code: 'service-failed';
142
+ /** The key name that the caller waited for. */
143
+ readonly key: string;
144
+ constructor(message: string, key: string, options?: InjecaErrorOptions);
145
+ }
146
+ /** `waitFor()` or `resolve()` did not match before its configured timeout. */
147
+ export declare class WaitTimeoutError extends InjecaError {
148
+ readonly code: 'wait-timeout';
149
+ constructor(message: string, options?: InjecaErrorOptions);
150
+ }
151
+ /** A caller passed a value with the wrong shape, or reading a caller-owned property failed. */
152
+ export declare class InvalidArgumentError extends InjecaError {
153
+ readonly code: 'invalid-argument';
154
+ constructor(message: string, options?: InjecaErrorOptions);
155
+ }
156
+ /**
157
+ * Subscribes to all transitions of the services in `container` and in its child containers.
158
+ *
159
+ * It replays the current state of each service at once, then sends each change in order.
160
+ * A callback error goes to the other observers as an `error` record. No call follows the disposal of the container.
161
+ * Returns a disposer.
162
+ */
163
+ export declare function observe(container: Container, callback: (record: ObserveRecord) => void): () => void;
164
+ /** A key name, a key from `defineKey`, or the result of `provide`. */
165
+ type WatchKey = KeyReference;
166
+ /**
167
+ * Sends the current phase and effective status of `key` at once, then each change, in order.
168
+ *
169
+ * The key resolves from `container` and its ancestors. After a withdrawal, the callback sees the old service until it is `withdrawn`, or until a new provider appears.
170
+ * A callback error goes to the observe stream. The container owns the subscription: no call follows its disposal. Returns a disposer.
171
+ */
172
+ export declare function watch(container: Container, key: WatchKey, callback: (state: ServiceState) => void): () => void;
173
+ interface WaitForOptions {
174
+ /** Waits for this effective status. Without it, `waitFor` waits until the key is available: `ready` or `degraded`. */
175
+ status?: ServiceStatus;
176
+ /**
177
+ * Ends the wait when the signal aborts. A timeout reason (`name === 'TimeoutError'`) rejects with `wait-timeout`, with the reason as `cause`.
178
+ * Another reason rejects as it is. Use `timeout(container, ms)` for a timeout on the container clock. There is no default.
179
+ */
180
+ signal?: AbortSignal;
181
+ }
182
+ /**
183
+ * Resolves with the state of `key` when it is available, or when it has `options.status`.
184
+ *
185
+ * It rejects with `service-failed` when the service is in `failed`, or when it waits for a required provider in `failed`, as `resolve` does.
186
+ * It rejects when `options.signal` aborts, at once for an aborted signal, and when the container is disposed. It has no built-in timeout.
187
+ */
188
+ export declare function waitFor(container: Container, key: WatchKey, options?: WaitForOptions): Promise<ServiceState>;
189
+ export declare const injeca: {
190
+ provide: typeof provide$1;
191
+ invoke: typeof invoke$1;
192
+ resolve: typeof resolve$1;
193
+ start: typeof start$1;
194
+ stop: typeof stop$1;
195
+ setLogger: typeof setLogger;
196
+ getContainer: typeof getContainer;
197
+ };
198
+ export { type BuildContext, type Clock, type ConditionalDependency, type Container, type ContainerOptions, type Decide, type DecideFor, type Decision, type DecisionFor, type DecisionKind, type DecisionObserveRecord, type DecisionOptions, type DecisionSource, type DeclareOptions, type DependencyChange, type DependencyDeclaration, type DependencyDeclarations, type DependencyHook, type DependencyHookContext, type DependencyMap, type DependencySnapshot, type DependencyState, type DisposeOptions, type Disposer, type EffectSetup, type ErrorObserveRecord, type EventKey, type ExponentialBackoff, type FailDecision, type FallbackDependency, type Graph, type GraphDependency, type GraphResolution, type GraphService, type HandledDecision, type HookContext, type HookContextFor, type HookDecisionKind, type HookDependencies, type HookHandler, type HookResult, type HookTimeouts, type IgnoredObserveRecord, type ImpactChange, type ImpactResult, type InferProvided, type InjecaErrorCode, type InjecaErrorOptions, type InvocationContext, type InvocationHandle, type InvokeOption, type InvokeOptionFunc, type InvokeOptionObject, type InvokeOptionObjectWithKeys, type InvokeOptionWithKeys, type KeyOptions, type KeyReference, type LifecycleContext, type ListenerEntry, type ListenerMetadata, type Logger, type LoggerOptions, type ObserveRecord, type ObserveRecordBase, type OptionalDependency, type OptionalValue, type OwnerRecord, type OwnerValue, type PeekDependency, type PeekResult, type PeekValue, type PhaseObserveRecord, type PolicyOptions, type ProvideOption, type ProvideOptionFunc, type ProvideOptionObject, type ProvideOptionObjectWithKeys, type ProvideOptionWithKeys, type ProvidedBy, type ProvidedKey, type ProviderInfo, type RebuildDecision, type ReentrantCallObserveRecord, type Registration, type RegistrationOptions, type RegistrationReplacedObserveRecord, type ReplaceFunction, type ReplaceOptions, type RequeueDecision, type RequeueOptions, type ResolutionCondition, type ResolveDependencyDeclaration, type ResolveOptions, type ServiceBlocker, type ServiceExplanation, type ServiceHook, type ServiceMetadata, type ServicePhase, type ServiceState, type ServiceStatus, type SetStatusOptions, type StartOptions, type StatusCause, type StatusObserveRecord, type StopDecision, type StopOptions, type TimeoutContext, type TimeoutHandler, type TimeoutObserveRecord, type Transaction, type TransactionCommitOptions, type TransactionProvide, type TransactionReplace, type WaitAbortedObserveRecord, type WaitForOptions, type WatchKey, type WithdrawOptions, createContainer, createDefaultLogger, createLoggLogger, createNoopLogger, defineKey, dispose, effect, firstAvailable, graph, invoke, listen, listeners, optional, peek, provide, resolve, start, stop, systemClock, timeout, transaction, where, withTimeout };
199
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,3 +1,243 @@
1
- import { a as provide, c as stop, d as createNoopLogger, i as lifecycle, l as createDefaultLogger, n as createContainer, o as resolve, r as invoke, s as start, t as injeca, u as createLoggLogger } from "./src-UXkTj4Np.mjs";
1
+ import { B as withoutUndefined, C as optional, Ct as InvalidDecisionError, D as releaseConsumerDemand, Dt as StartTimeoutError, Et as StaleRegistrationError, G as nodeOf, M as statusFields, Ot as TransactionIncompleteError, S as normalizeName, St as InvalidArgumentError, T as demandConsumerService, Tt as ServiceFailedError, U as assertActive, Z as blockingFailure, _t as BuildAfterDisposeError, b as firstAvailable, bt as HookTimeoutError, gt as withOwner, ht as untracked, kt as WaitTimeoutError, mt as batch, st as selectProvider, tt as findProvider, vt as DuplicateServiceError, w as where, wt as ReplaceWhileStoppingError, xt as InjecaError, y as defineKey, yt as HookOutsideBuildError, z as reportCallbackError } from "./decision-BXZu3N1O.mjs";
2
+ import { A as createNoopLogger, C as effect, D as systemClock, E as waitAbortError, O as createDefaultLogger, S as dispose, T as readSignal, _ as listen, a as resolve$1, b as invoke, c as stop$1, d as graph, f as transaction, g as provide, h as resolve, k as createLoggLogger, l as listeners, m as withTimeout, n as invoke$1, o as setLogger, p as timeout, r as provide$1, s as start$1, t as getContainer, u as peek, v as start, w as onAbort, x as createContainer, y as stop } from "./global-B5N-d-TO.mjs";
3
+ import { effect as effect$1 } from "alien-signals";
4
+ // src/queries/observe.ts
5
+ function replayOf(service) {
6
+ const owner = service.container.owner;
7
+ const instanceId = service.signals.instance()?.id;
8
+ const records = [{
9
+ type: "phase",
10
+ key: service.name,
11
+ owner,
12
+ instanceId,
13
+ from: void 0,
14
+ to: service.signals.phase()
15
+ }];
16
+ const status = service.signals.effective();
17
+ if (status) records.push({
18
+ type: "status",
19
+ key: service.name,
20
+ owner,
21
+ instanceId,
22
+ from: void 0,
23
+ to: status.status,
24
+ ...statusFields(status)
25
+ });
26
+ return records;
27
+ }
28
+ function subtree(container) {
29
+ return [container, ...[...container.children].flatMap(subtree)];
30
+ }
31
+ /**
32
+ * Subscribes to all transitions of the services in `container` and in its child containers.
33
+ *
34
+ * It replays the current state of each service at once, then sends each change in order.
35
+ * A callback error goes to the other observers as an `error` record. No call follows the disposal of the container.
36
+ * Returns a disposer.
37
+ */
38
+ function observe(container, callback) {
39
+ const node = nodeOf(container);
40
+ assertActive(node, "observe");
41
+ if (typeof callback !== "function") throw new InvalidArgumentError("The observe callback is not a function.");
42
+ const { deliveries, observers } = node.runtime;
43
+ const observer = {
44
+ container: node,
45
+ callback,
46
+ active: true
47
+ };
48
+ const replay = untracked(() => subtree(node).flatMap((current) => [...current.services]).filter((service) => service.kind !== "resolver" && service.signals.present()).flatMap(replayOf));
49
+ observers.add(observer);
50
+ const stop = () => {
51
+ observer.active = false;
52
+ observers.delete(observer);
53
+ node.disposedListeners.delete(stop);
54
+ };
55
+ node.disposedListeners.add(stop);
56
+ deliveries.deliver(replay.map((entry) => ({
57
+ run: () => {
58
+ if (observer.active) callback(Object.freeze(entry));
59
+ },
60
+ onError: (error) => reportCallbackError(node, entry.key, error, "An observe callback threw.", observer)
61
+ })));
62
+ return stop;
63
+ }
64
+ // src/queries/watch.ts
65
+ const statuses = /* @__PURE__ */ new Set([
66
+ "ready",
67
+ "degraded",
68
+ "unavailable"
69
+ ]);
70
+ function readKey(key, action) {
71
+ let name;
72
+ try {
73
+ name = normalizeName(key);
74
+ } catch (error) {
75
+ throw new InvalidArgumentError(`Cannot read the key of ${action}.`, { cause: error });
76
+ }
77
+ if (typeof name !== "string" || name.length === 0) throw new InvalidArgumentError(`The key of ${action} must be a name or a key.`);
78
+ return name;
79
+ }
80
+ function stateOf(service) {
81
+ if (!service) return Object.freeze({
82
+ phase: void 0,
83
+ status: void 0,
84
+ instanceId: void 0
85
+ });
86
+ const status = service.signals.effective();
87
+ return Object.freeze({
88
+ phase: service.signals.phase(),
89
+ status: status?.status,
90
+ instanceId: service.signals.instance()?.id,
91
+ ...withoutUndefined({
92
+ reason: status?.reason,
93
+ cause: status?.cause
94
+ })
95
+ });
96
+ }
97
+ function sameState(a, b) {
98
+ return a.phase === b.phase && a.status === b.status && a.instanceId === b.instanceId && a.reason === b.reason && a.cause === b.cause;
99
+ }
100
+ /**
101
+ * Sends the current phase and effective status of `key` at once, then each change, in order.
102
+ *
103
+ * The key resolves from `container` and its ancestors. After a withdrawal, the callback sees the old service until it is `withdrawn`, or until a new provider appears.
104
+ * A callback error goes to the observe stream. The container owns the subscription: no call follows its disposal. Returns a disposer.
105
+ */
106
+ function watch(container, key, callback) {
107
+ const node = nodeOf(container);
108
+ assertActive(node, "watch");
109
+ const name = readKey(key, "watch");
110
+ if (typeof callback !== "function") throw new InvalidArgumentError("The watch callback is not a function.");
111
+ return untracked(() => subscribe(node, name, callback));
112
+ }
113
+ /**
114
+ * The effect of one `watch` call. It tracks the provider of `name` and its state. The delivery queue calls the callback untracked.
115
+ *
116
+ * For a `perConsumer` registration, the subscription demands the consumer service of `node`, as `resolve` does. So the state is the real availability for `node`.
117
+ * The demand ends with the subscription.
118
+ */
119
+ function subscribe(node, name, callback) {
120
+ const { deliveries } = node.runtime;
121
+ const subscription = {};
122
+ let active = true;
123
+ let last;
124
+ let delivered;
125
+ let demand;
126
+ let demandQueued = false;
127
+ const syncDemand = () => {
128
+ if (!active) return;
129
+ const registration = selectProvider(node, name)?.registration;
130
+ const next = registration?.perConsumer ? demandConsumerService(registration, node, subscription) : void 0;
131
+ if (demand && demand !== next) releaseConsumerDemand(demand, subscription);
132
+ demand = next;
133
+ };
134
+ batch(syncDemand);
135
+ const stopEffect = withOwner(node.reactiveOwner, () => effect$1(() => {
136
+ const current = findProvider(node, name);
137
+ const moved = demand !== void 0 && current?.template !== void 0 && current !== demand;
138
+ if ((current?.perConsumer || moved) && !demandQueued) {
139
+ demandQueued = true;
140
+ queueMicrotask(() => untracked(() => {
141
+ demandQueued = false;
142
+ batch(syncDemand);
143
+ }));
144
+ }
145
+ if (current) last = current;
146
+ const state = stateOf(current ?? last);
147
+ if (delivered && sameState(delivered, state)) return;
148
+ delivered = state;
149
+ deliveries.deliver([{
150
+ run: () => {
151
+ if (active && node.state !== "disposed") callback(state);
152
+ },
153
+ onError: (error) => reportCallbackError(node, name, error, "A watch callback threw.")
154
+ }]);
155
+ }));
156
+ const stop = () => {
157
+ if (!active) return;
158
+ active = false;
159
+ stopEffect();
160
+ if (demand) untracked(() => batch(() => releaseConsumerDemand(demand, subscription)));
161
+ node.disposedListeners.delete(stop);
162
+ };
163
+ node.disposedListeners.add(stop);
164
+ return stop;
165
+ }
166
+ function readWaitOptions(options) {
167
+ let status;
168
+ try {
169
+ status = options?.status;
170
+ } catch (error) {
171
+ throw new InvalidArgumentError("Cannot read the waitFor options.", { cause: error });
172
+ }
173
+ if (status !== void 0 && (typeof status !== "string" || !statuses.has(status))) throw new InvalidArgumentError(`The status option of waitFor must be 'ready', 'degraded', or 'unavailable'. Got ${String(status)}.`);
174
+ return {
175
+ status,
176
+ signal: readSignal(options, "waitFor")
177
+ };
178
+ }
179
+ /** The failure that ends a wait for `name`: its service is in `failed`, or it waits for a required provider in `failed`. */
180
+ function failureOf(node, name) {
181
+ const provider = findProvider(node, name);
182
+ if (!provider) return void 0;
183
+ const phase = provider.signals.phase();
184
+ if (phase === "failed") return provider.failure ?? { error: void 0 };
185
+ return phase === "pending" ? blockingFailure(provider) : void 0;
186
+ }
187
+ /**
188
+ * Resolves with the state of `key` when it is available, or when it has `options.status`.
189
+ *
190
+ * It rejects with `service-failed` when the service is in `failed`, or when it waits for a required provider in `failed`, as `resolve` does.
191
+ * It rejects when `options.signal` aborts, at once for an aborted signal, and when the container is disposed. It has no built-in timeout.
192
+ */
193
+ function waitFor(container, key, options) {
194
+ const node = nodeOf(container);
195
+ assertActive(node, "waitFor");
196
+ const name = readKey(key, "waitFor");
197
+ const { status, signal } = readWaitOptions(options);
198
+ const abortError = (reason) => waitAbortError(reason, `waitFor('${name}') timed out.`);
199
+ if (signal?.aborted) return Promise.reject(abortError(signal.reason));
200
+ const matches = (state) => state.phase === "running" && (status === void 0 ? state.status !== void 0 && state.status !== "unavailable" : state.status === status);
201
+ return new Promise((resolve, reject) => untracked(() => {
202
+ let done = false;
203
+ let stopWatch;
204
+ let disarm = () => {};
205
+ let stopListening = () => {};
206
+ const onDisposed = () => finish(() => reject(new BuildAfterDisposeError(`The container was disposed before waitFor('${name}') matched.`)));
207
+ function finish(outcome) {
208
+ if (done) return;
209
+ done = true;
210
+ stopWatch?.();
211
+ stopListening();
212
+ disarm();
213
+ node.disposedListeners.delete(onDisposed);
214
+ outcome();
215
+ }
216
+ node.disposedListeners.add(onDisposed);
217
+ disarm = onAbort(signal, (reason) => finish(() => reject(abortError(reason))));
218
+ const checkFailure = () => {
219
+ const failure = failureOf(node, name);
220
+ if (failure) finish(() => reject(new ServiceFailedError(`waitFor('${name}') found a failed service.`, name, { cause: failure.error })));
221
+ };
222
+ stopListening = node.runtime.reconciler.onDrained(checkFailure);
223
+ stopWatch = subscribe(node, name, (state) => {
224
+ if (matches(state)) finish(() => resolve(state));
225
+ else if (state.phase === "failed") checkFailure();
226
+ });
227
+ node.runtime.reconciler.requestDrain();
228
+ if (done) stopWatch();
229
+ }));
230
+ }
231
+ // src/index.ts
232
+ const injeca = {
233
+ provide: provide$1,
234
+ invoke: invoke$1,
235
+ resolve: resolve$1,
236
+ start: start$1,
237
+ stop: stop$1,
238
+ setLogger,
239
+ getContainer
240
+ };
241
+ export { BuildAfterDisposeError, DuplicateServiceError, HookOutsideBuildError, HookTimeoutError, InjecaError, InvalidArgumentError, InvalidDecisionError, ReplaceWhileStoppingError, ServiceFailedError, StaleRegistrationError, StartTimeoutError, TransactionIncompleteError, WaitTimeoutError, createContainer, createDefaultLogger, createLoggLogger, createNoopLogger, defineKey, dispose, effect, firstAvailable, graph, injeca, invoke, listen, listeners, observe, optional, peek, provide, resolve, start, stop, systemClock, timeout, transaction, waitFor, watch, where, withTimeout };
2
242
 
3
- export { createContainer, createDefaultLogger, createLoggLogger, createNoopLogger, injeca, invoke, lifecycle, provide, resolve, start, stop };
243
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["effect","globalProvide","globalInvoke","globalResolve","globalStart","globalStop","globalSetLogger","globalGetContainer"],"sources":["../src/queries/observe.ts","../src/queries/watch.ts","../src/index.ts"],"sourcesContent":["import type { ContainerNode, Observer, ServiceNode } from '../graph/graph'\nimport type { Container, ObserveRecord } from '../types'\n\nimport { InvalidArgumentError } from '../diagnostics/errors'\nimport { assertActive, nodeOf } from '../graph/nodes'\nimport { reportCallbackError } from '../graph/observers'\nimport { statusFields } from '../graph/status'\nimport { untracked } from '../helpers/signals'\n\nfunction replayOf(service: ServiceNode): ObserveRecord[] {\n const owner = service.container.owner\n const instanceId = service.signals.instance()?.id\n const records: ObserveRecord[] = [{ type: 'phase', key: service.name, owner, instanceId, from: undefined, to: service.signals.phase() }]\n const status = service.signals.effective()\n if (status)\n records.push({ type: 'status', key: service.name, owner, instanceId, from: undefined, to: status.status, ...statusFields(status) })\n\n return records\n}\n\nfunction subtree(container: ContainerNode): ContainerNode[] {\n return [container, ...[...container.children].flatMap(subtree)]\n}\n\n/**\n * Subscribes to all transitions of the services in `container` and in its child containers.\n *\n * It replays the current state of each service at once, then sends each change in order.\n * A callback error goes to the other observers as an `error` record. No call follows the disposal of the container.\n * Returns a disposer.\n */\nexport function observe(container: Container, callback: (record: ObserveRecord) => void): () => void {\n const node = nodeOf(container)\n assertActive(node, 'observe')\n if (typeof callback !== 'function')\n throw new InvalidArgumentError('The observe callback is not a function.')\n\n const { deliveries, observers } = node.runtime\n const observer: Observer = { container: node, callback, active: true }\n const replay = untracked(() => subtree(node)\n .flatMap(current => [...current.services])\n .filter(service => service.kind !== 'resolver' && service.signals.present())\n .flatMap(replayOf))\n\n observers.add(observer)\n const stop = (): void => {\n observer.active = false\n observers.delete(observer)\n node.disposedListeners.delete(stop)\n }\n node.disposedListeners.add(stop)\n\n deliveries.deliver(replay.map(entry => ({\n run: () => {\n if (observer.active)\n callback(Object.freeze(entry))\n },\n onError: (error: unknown) => reportCallbackError(node, entry.key, error, 'An observe callback threw.', observer),\n })))\n\n return stop\n}\n","import type { ContainerNode, ServiceNode } from '../graph/graph'\nimport type { Container, KeyReference, ServiceState, ServiceStatus } from '../types'\n\nimport { effect } from 'alien-signals'\n\nimport { BuildAfterDisposeError, InvalidArgumentError, ServiceFailedError } from '../diagnostics/errors'\nimport { assertActive, demandConsumerService, nodeOf, releaseConsumerDemand } from '../graph/nodes'\nimport { reportCallbackError } from '../graph/observers'\nimport { blockingFailure, findProvider, selectProvider } from '../graph/resolvers/resolvers'\nimport { onAbort, readSignal, waitAbortError } from '../helpers/abort'\nimport { batch, untracked, withOwner } from '../helpers/signals'\nimport { withoutUndefined } from '../helpers/without-undefined'\nimport { normalizeName } from '../primitives/keys'\n\n/** A key name, a key from `defineKey`, or the result of `provide`. */\nexport type WatchKey = KeyReference\n\nconst statuses: ReadonlySet<string> = new Set<ServiceStatus>(['ready', 'degraded', 'unavailable'])\n\nfunction readKey(key: unknown, action: string): string {\n let name: unknown\n try {\n name = normalizeName(key as string)\n }\n catch (error) {\n throw new InvalidArgumentError(`Cannot read the key of ${action}.`, { cause: error })\n }\n if (typeof name !== 'string' || name.length === 0)\n throw new InvalidArgumentError(`The key of ${action} must be a name or a key.`)\n\n return name\n}\n\nfunction stateOf(service: ServiceNode | undefined): ServiceState {\n if (!service)\n return Object.freeze({ phase: undefined, status: undefined, instanceId: undefined })\n\n const status = service.signals.effective()\n return Object.freeze({\n phase: service.signals.phase(),\n status: status?.status,\n instanceId: service.signals.instance()?.id,\n ...withoutUndefined({ reason: status?.reason, cause: status?.cause }),\n })\n}\n\nfunction sameState(a: ServiceState, b: ServiceState): boolean {\n return a.phase === b.phase && a.status === b.status && a.instanceId === b.instanceId && a.reason === b.reason && a.cause === b.cause\n}\n\n/**\n * Sends the current phase and effective status of `key` at once, then each change, in order.\n *\n * The key resolves from `container` and its ancestors. After a withdrawal, the callback sees the old service until it is `withdrawn`, or until a new provider appears.\n * A callback error goes to the observe stream. The container owns the subscription: no call follows its disposal. Returns a disposer.\n */\nexport function watch(container: Container, key: WatchKey, callback: (state: ServiceState) => void): () => void {\n const node = nodeOf(container)\n assertActive(node, 'watch')\n const name = readKey(key, 'watch')\n if (typeof callback !== 'function')\n throw new InvalidArgumentError('The watch callback is not a function.')\n\n return untracked(() => subscribe(node, name, callback))\n}\n\n/**\n * The effect of one `watch` call. It tracks the provider of `name` and its state. The delivery queue calls the callback untracked.\n *\n * For a `perConsumer` registration, the subscription demands the consumer service of `node`, as `resolve` does. So the state is the real availability for `node`.\n * The demand ends with the subscription.\n */\nfunction subscribe(node: ContainerNode, name: string, callback: (state: ServiceState) => void): () => void {\n const { deliveries } = node.runtime\n const subscription = {}\n let active = true\n let last: ServiceNode | undefined\n let delivered: ServiceState | undefined\n let demand: ServiceNode | undefined\n let demandQueued = false\n\n const syncDemand = (): void => {\n if (!active)\n return\n\n const registration = selectProvider(node, name)?.registration\n const next = registration?.perConsumer ? demandConsumerService(registration, node, subscription) : undefined\n if (demand && demand !== next)\n releaseConsumerDemand(demand, subscription)\n demand = next\n }\n batch(syncDemand)\n\n const stopEffect = withOwner(node.reactiveOwner, () => effect(() => {\n const current = findProvider(node, name)\n // A `perConsumer` registration has no service for this container yet, for example after a replacement. Demand it after this run, outside the effect.\n // A new consumer service, for example after a rebuild, takes over the demand too.\n const moved = demand !== undefined && current?.template !== undefined && current !== demand\n if ((current?.perConsumer || moved) && !demandQueued) {\n demandQueued = true\n queueMicrotask(() => untracked(() => {\n demandQueued = false\n batch(syncDemand)\n }))\n }\n if (current)\n last = current\n const state = stateOf(current ?? last)\n if (delivered && sameState(delivered, state))\n return\n\n delivered = state\n deliveries.deliver([{\n run: () => {\n if (active && node.state !== 'disposed')\n callback(state)\n },\n onError: error => reportCallbackError(node, name, error, 'A watch callback threw.'),\n }])\n }))\n\n const stop = (): void => {\n if (!active)\n return\n\n active = false\n stopEffect()\n if (demand)\n untracked(() => batch(() => releaseConsumerDemand(demand!, subscription)))\n node.disposedListeners.delete(stop)\n }\n node.disposedListeners.add(stop)\n\n return stop\n}\n\nexport interface WaitForOptions {\n /** Waits for this effective status. Without it, `waitFor` waits until the key is available: `ready` or `degraded`. */\n status?: ServiceStatus\n /**\n * Ends the wait when the signal aborts. A timeout reason (`name === 'TimeoutError'`) rejects with `wait-timeout`, with the reason as `cause`.\n * Another reason rejects as it is. Use `timeout(container, ms)` for a timeout on the container clock. There is no default.\n */\n signal?: AbortSignal\n}\n\nfunction readWaitOptions(options: WaitForOptions | undefined): { readonly status: ServiceStatus | undefined, readonly signal: AbortSignal | undefined } {\n let status: unknown\n try {\n status = options?.status\n }\n catch (error) {\n throw new InvalidArgumentError('Cannot read the waitFor options.', { cause: error })\n }\n if (status !== undefined && (typeof status !== 'string' || !statuses.has(status)))\n throw new InvalidArgumentError(`The status option of waitFor must be 'ready', 'degraded', or 'unavailable'. Got ${String(status)}.`)\n\n return { status: status as ServiceStatus | undefined, signal: readSignal(options, 'waitFor') }\n}\n\n/** The failure that ends a wait for `name`: its service is in `failed`, or it waits for a required provider in `failed`. */\nfunction failureOf(node: ContainerNode, name: string): { readonly error: unknown } | undefined {\n const provider = findProvider(node, name)\n if (!provider)\n return undefined\n\n const phase = provider.signals.phase()\n if (phase === 'failed')\n return provider.failure ?? { error: undefined }\n return phase === 'pending' ? blockingFailure(provider) : undefined\n}\n\n/**\n * Resolves with the state of `key` when it is available, or when it has `options.status`.\n *\n * It rejects with `service-failed` when the service is in `failed`, or when it waits for a required provider in `failed`, as `resolve` does.\n * It rejects when `options.signal` aborts, at once for an aborted signal, and when the container is disposed. It has no built-in timeout.\n */\nexport function waitFor(container: Container, key: WatchKey, options?: WaitForOptions): Promise<ServiceState> {\n const node = nodeOf(container)\n assertActive(node, 'waitFor')\n const name = readKey(key, 'waitFor')\n const { status, signal } = readWaitOptions(options)\n const abortError = (reason: unknown): unknown => waitAbortError(reason, `waitFor('${name}') timed out.`)\n if (signal?.aborted)\n return Promise.reject(abortError(signal.reason))\n\n const matches = (state: ServiceState): boolean => state.phase === 'running'\n && (status === undefined ? state.status !== undefined && state.status !== 'unavailable' : state.status === status)\n\n return new Promise((resolve, reject) => untracked(() => {\n let done = false\n let stopWatch: (() => void) | undefined\n let disarm = () => {}\n let stopListening = () => {}\n\n const onDisposed = (): void => finish(() => reject(new BuildAfterDisposeError(`The container was disposed before waitFor('${name}') matched.`)))\n\n function finish(outcome: () => void): void {\n if (done)\n return\n\n done = true\n stopWatch?.()\n stopListening()\n disarm()\n node.disposedListeners.delete(onDisposed)\n outcome()\n }\n\n node.disposedListeners.add(onDisposed)\n disarm = onAbort(signal, reason => finish(() => reject(abortError(reason))))\n\n const checkFailure = (): void => {\n const failure = failureOf(node, name)\n if (failure)\n finish(() => reject(new ServiceFailedError(`waitFor('${name}') found a failed service.`, name, { cause: failure.error })))\n }\n\n // A failure of a dependency does not change the state of `key`. The check runs after each drain, as for `resolve`.\n stopListening = node.runtime.reconciler.onDrained(checkFailure)\n stopWatch = subscribe(node, name, (state) => {\n if (matches(state))\n finish(() => resolve(state))\n else if (state.phase === 'failed')\n checkFailure()\n })\n node.runtime.reconciler.requestDrain()\n // The first state can match at once, before `stopWatch` was assigned.\n if (done)\n stopWatch()\n }))\n}\n","import {\n getContainer as globalGetContainer,\n invoke as globalInvoke,\n provide as globalProvide,\n resolve as globalResolve,\n setLogger as globalSetLogger,\n start as globalStart,\n stop as globalStop,\n} from './global'\n\nexport type { InjecaErrorCode, InjecaErrorOptions } from './diagnostics/errors'\nexport {\n BuildAfterDisposeError,\n DuplicateServiceError,\n HookOutsideBuildError,\n HookTimeoutError,\n InjecaError,\n InvalidArgumentError,\n InvalidDecisionError,\n ReplaceWhileStoppingError,\n ServiceFailedError,\n StaleRegistrationError,\n StartTimeoutError,\n TransactionIncompleteError,\n WaitTimeoutError,\n} from './diagnostics/errors'\n\nexport type { Logger, LoggerOptions } from './diagnostics/logger'\n\nexport {\n createDefaultLogger,\n createLoggLogger,\n createNoopLogger,\n} from './diagnostics/logger'\nexport type { Clock } from './helpers/clock'\n\nexport { systemClock } from './helpers/clock'\nexport type {\n Decide,\n DecideFor,\n Decision,\n DecisionFor,\n DecisionKind,\n DecisionOptions,\n DecisionSource,\n DependencyHook,\n ExponentialBackoff,\n FailDecision,\n HandledDecision,\n HookDecisionKind,\n HookResult,\n RebuildDecision,\n RequeueDecision,\n RequeueOptions,\n ServiceHook,\n StopDecision,\n} from './primitives/decision'\n\nexport { observe } from './queries/observe'\n\nexport { waitFor, watch } from './queries/watch'\nexport type { WaitForOptions, WatchKey } from './queries/watch'\n\nexport {\n createContainer,\n defineKey,\n dispose,\n effect,\n firstAvailable,\n graph,\n invoke,\n listen,\n listeners,\n optional,\n peek,\n provide,\n resolve,\n start,\n stop,\n timeout,\n transaction,\n where,\n withTimeout,\n} from './scoped'\n\nexport type { DisposeOptions, ResolveOptions, StartOptions, StopOptions } from './scoped'\nexport type {\n BuildContext,\n ConditionalDependency,\n Container,\n ContainerOptions,\n DeclareOptions,\n DecisionObserveRecord,\n DependencyChange,\n DependencyDeclaration,\n DependencyDeclarations,\n DependencyHookContext,\n DependencyMap,\n DependencySnapshot,\n DependencyState,\n Disposer,\n EffectSetup,\n ErrorObserveRecord,\n EventKey,\n FallbackDependency,\n Graph,\n GraphDependency,\n GraphResolution,\n GraphService,\n HookTimeouts,\n HookContext,\n HookContextFor,\n HookDependencies,\n HookHandler,\n IgnoredObserveRecord,\n ImpactChange,\n ImpactResult,\n InferProvided,\n InvocationContext,\n InvocationHandle,\n InvokeOption,\n InvokeOptionFunc,\n InvokeOptionObject,\n InvokeOptionObjectWithKeys,\n InvokeOptionWithKeys,\n KeyOptions,\n KeyReference,\n LifecycleContext,\n ListenerEntry,\n ListenerMetadata,\n ObserveRecord,\n ObserveRecordBase,\n OptionalDependency,\n OptionalValue,\n OwnerRecord,\n OwnerValue,\n PeekDependency,\n PeekResult,\n PeekValue,\n PhaseObserveRecord,\n PolicyOptions,\n ProviderInfo,\n ProvidedBy,\n ProvidedKey,\n ProvideOption,\n ProvideOptionFunc,\n ProvideOptionObject,\n ProvideOptionObjectWithKeys,\n ProvideOptionWithKeys,\n Registration,\n RegistrationOptions,\n ReentrantCallObserveRecord,\n RegistrationReplacedObserveRecord,\n ReplaceFunction,\n ReplaceOptions,\n ResolutionCondition,\n ResolveDependencyDeclaration,\n ServiceBlocker,\n ServiceExplanation,\n ServiceMetadata,\n ServicePhase,\n ServiceState,\n ServiceStatus,\n SetStatusOptions,\n StatusCause,\n StatusObserveRecord,\n TimeoutContext,\n TimeoutHandler,\n TimeoutObserveRecord,\n Transaction,\n TransactionCommitOptions,\n TransactionProvide,\n TransactionReplace,\n WaitAbortedObserveRecord,\n WithdrawOptions,\n} from './types'\n\nexport const injeca = {\n provide: globalProvide,\n invoke: globalInvoke,\n resolve: globalResolve,\n start: globalStart,\n stop: globalStop,\n setLogger: globalSetLogger,\n getContainer: globalGetContainer,\n}\n"],"mappings":";;;;AASA,SAAS,SAAS,SAAuC;CACvD,MAAM,QAAQ,QAAQ,UAAU;CAChC,MAAM,aAAa,QAAQ,QAAQ,SAAS,CAAC,EAAE;CAC/C,MAAM,UAA2B,CAAC;EAAE,MAAM;EAAS,KAAK,QAAQ;EAAM;EAAO;EAAY,MAAM,KAAA;EAAW,IAAI,QAAQ,QAAQ,MAAM;CAAE,CAAC;CACvI,MAAM,SAAS,QAAQ,QAAQ,UAAU;CACzC,IAAI,QACF,QAAQ,KAAK;EAAE,MAAM;EAAU,KAAK,QAAQ;EAAM;EAAO;EAAY,MAAM,KAAA;EAAW,IAAI,OAAO;EAAQ,GAAG,aAAa,MAAM;CAAE,CAAC;CAEpI,OAAO;AACT;AAEA,SAAS,QAAQ,WAA2C;CAC1D,OAAO,CAAC,WAAW,GAAG,CAAC,GAAG,UAAU,QAAQ,CAAC,CAAC,QAAQ,OAAO,CAAC;AAChE;;;;;;;;AASA,SAAgB,QAAQ,WAAsB,UAAuD;CACnG,MAAM,OAAO,OAAO,SAAS;CAC7B,aAAa,MAAM,SAAS;CAC5B,IAAI,OAAO,aAAa,YACtB,MAAM,IAAI,qBAAqB,yCAAyC;CAE1E,MAAM,EAAE,YAAY,cAAc,KAAK;CACvC,MAAM,WAAqB;EAAE,WAAW;EAAM;EAAU,QAAQ;CAAK;CACrE,MAAM,SAAS,gBAAgB,QAAQ,IAAI,CAAC,CACzC,SAAQ,YAAW,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CACzC,QAAO,YAAW,QAAQ,SAAS,cAAc,QAAQ,QAAQ,QAAQ,CAAC,CAAC,CAC3E,QAAQ,QAAQ,CAAC;CAEpB,UAAU,IAAI,QAAQ;CACtB,MAAM,aAAmB;EACvB,SAAS,SAAS;EAClB,UAAU,OAAO,QAAQ;EACzB,KAAK,kBAAkB,OAAO,IAAI;CACpC;CACA,KAAK,kBAAkB,IAAI,IAAI;CAE/B,WAAW,QAAQ,OAAO,KAAI,WAAU;EACtC,WAAW;GACT,IAAI,SAAS,QACX,SAAS,OAAO,OAAO,KAAK,CAAC;EACjC;EACA,UAAU,UAAmB,oBAAoB,MAAM,MAAM,KAAK,OAAO,8BAA8B,QAAQ;CACjH,EAAE,CAAC;CAEH,OAAO;AACT;;AC5CA,MAAM,2BAAgC,IAAI,IAAmB;CAAC;CAAS;CAAY;AAAa,CAAC;AAEjG,SAAS,QAAQ,KAAc,QAAwB;CACrD,IAAI;CACJ,IAAI;EACF,OAAO,cAAc,GAAa;CACpC,SACO,OAAO;EACZ,MAAM,IAAI,qBAAqB,0BAA0B,OAAO,IAAI,EAAE,OAAO,MAAM,CAAC;CACtF;CACA,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,qBAAqB,cAAc,OAAO,0BAA0B;CAEhF,OAAO;AACT;AAEA,SAAS,QAAQ,SAAgD;CAC/D,IAAI,CAAC,SACH,OAAO,OAAO,OAAO;EAAE,OAAO,KAAA;EAAW,QAAQ,KAAA;EAAW,YAAY,KAAA;CAAU,CAAC;CAErF,MAAM,SAAS,QAAQ,QAAQ,UAAU;CACzC,OAAO,OAAO,OAAO;EACnB,OAAO,QAAQ,QAAQ,MAAM;EAC7B,QAAQ,QAAQ;EAChB,YAAY,QAAQ,QAAQ,SAAS,CAAC,EAAE;EACxC,GAAG,iBAAiB;GAAE,QAAQ,QAAQ;GAAQ,OAAO,QAAQ;EAAM,CAAC;CACtE,CAAC;AACH;AAEA,SAAS,UAAU,GAAiB,GAA0B;CAC5D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE;AACjI;;;;;;;AAQA,SAAgB,MAAM,WAAsB,KAAe,UAAqD;CAC9G,MAAM,OAAO,OAAO,SAAS;CAC7B,aAAa,MAAM,OAAO;CAC1B,MAAM,OAAO,QAAQ,KAAK,OAAO;CACjC,IAAI,OAAO,aAAa,YACtB,MAAM,IAAI,qBAAqB,uCAAuC;CAExE,OAAO,gBAAgB,UAAU,MAAM,MAAM,QAAQ,CAAC;AACxD;;;;;;;AAQA,SAAS,UAAU,MAAqB,MAAc,UAAqD;CACzG,MAAM,EAAE,eAAe,KAAK;CAC5B,MAAM,eAAe,CAAC;CACtB,IAAI,SAAS;CACb,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,eAAe;CAEnB,MAAM,mBAAyB;EAC7B,IAAI,CAAC,QACH;EAEF,MAAM,eAAe,eAAe,MAAM,IAAI,CAAC,EAAE;EACjD,MAAM,OAAO,cAAc,cAAc,sBAAsB,cAAc,MAAM,YAAY,IAAI,KAAA;EACnG,IAAI,UAAU,WAAW,MACvB,sBAAsB,QAAQ,YAAY;EAC5C,SAAS;CACX;CACA,MAAM,UAAU;CAEhB,MAAM,aAAa,UAAU,KAAK,qBAAqBA,eAAa;EAClE,MAAM,UAAU,aAAa,MAAM,IAAI;EAGvC,MAAM,QAAQ,WAAW,KAAA,KAAa,SAAS,aAAa,KAAA,KAAa,YAAY;EACrF,KAAK,SAAS,eAAe,UAAU,CAAC,cAAc;GACpD,eAAe;GACf,qBAAqB,gBAAgB;IACnC,eAAe;IACf,MAAM,UAAU;GAClB,CAAC,CAAC;EACJ;EACA,IAAI,SACF,OAAO;EACT,MAAM,QAAQ,QAAQ,WAAW,IAAI;EACrC,IAAI,aAAa,UAAU,WAAW,KAAK,GACzC;EAEF,YAAY;EACZ,WAAW,QAAQ,CAAC;GAClB,WAAW;IACT,IAAI,UAAU,KAAK,UAAU,YAC3B,SAAS,KAAK;GAClB;GACA,UAAS,UAAS,oBAAoB,MAAM,MAAM,OAAO,yBAAyB;EACpF,CAAC,CAAC;CACJ,CAAC,CAAC;CAEF,MAAM,aAAmB;EACvB,IAAI,CAAC,QACH;EAEF,SAAS;EACT,WAAW;EACX,IAAI,QACF,gBAAgB,YAAY,sBAAsB,QAAS,YAAY,CAAC,CAAC;EAC3E,KAAK,kBAAkB,OAAO,IAAI;CACpC;CACA,KAAK,kBAAkB,IAAI,IAAI;CAE/B,OAAO;AACT;AAYA,SAAS,gBAAgB,SAA+H;CACtJ,IAAI;CACJ,IAAI;EACF,SAAS,SAAS;CACpB,SACO,OAAO;EACZ,MAAM,IAAI,qBAAqB,oCAAoC,EAAE,OAAO,MAAM,CAAC;CACrF;CACA,IAAI,WAAW,KAAA,MAAc,OAAO,WAAW,YAAY,CAAC,SAAS,IAAI,MAAM,IAC7E,MAAM,IAAI,qBAAqB,mFAAmF,OAAO,MAAM,EAAE,EAAE;CAErI,OAAO;EAAU;EAAqC,QAAQ,WAAW,SAAS,SAAS;CAAE;AAC/F;;AAGA,SAAS,UAAU,MAAqB,MAAuD;CAC7F,MAAM,WAAW,aAAa,MAAM,IAAI;CACxC,IAAI,CAAC,UACH,OAAO,KAAA;CAET,MAAM,QAAQ,SAAS,QAAQ,MAAM;CACrC,IAAI,UAAU,UACZ,OAAO,SAAS,WAAW,EAAE,OAAO,KAAA,EAAU;CAChD,OAAO,UAAU,YAAY,gBAAgB,QAAQ,IAAI,KAAA;AAC3D;;;;;;;AAQA,SAAgB,QAAQ,WAAsB,KAAe,SAAiD;CAC5G,MAAM,OAAO,OAAO,SAAS;CAC7B,aAAa,MAAM,SAAS;CAC5B,MAAM,OAAO,QAAQ,KAAK,SAAS;CACnC,MAAM,EAAE,QAAQ,WAAW,gBAAgB,OAAO;CAClD,MAAM,cAAc,WAA6B,eAAe,QAAQ,YAAY,KAAK,cAAc;CACvG,IAAI,QAAQ,SACV,OAAO,QAAQ,OAAO,WAAW,OAAO,MAAM,CAAC;CAEjD,MAAM,WAAW,UAAiC,MAAM,UAAU,cAC5D,WAAW,KAAA,IAAY,MAAM,WAAW,KAAA,KAAa,MAAM,WAAW,gBAAgB,MAAM,WAAW;CAE7G,OAAO,IAAI,SAAS,SAAS,WAAW,gBAAgB;EACtD,IAAI,OAAO;EACX,IAAI;EACJ,IAAI,eAAe,CAAC;EACpB,IAAI,sBAAsB,CAAC;EAE3B,MAAM,mBAAyB,aAAa,OAAO,IAAI,uBAAuB,8CAA8C,KAAK,YAAY,CAAC,CAAC;EAE/I,SAAS,OAAO,SAA2B;GACzC,IAAI,MACF;GAEF,OAAO;GACP,YAAY;GACZ,cAAc;GACd,OAAO;GACP,KAAK,kBAAkB,OAAO,UAAU;GACxC,QAAQ;EACV;EAEA,KAAK,kBAAkB,IAAI,UAAU;EACrC,SAAS,QAAQ,SAAQ,WAAU,aAAa,OAAO,WAAW,MAAM,CAAC,CAAC,CAAC;EAE3E,MAAM,qBAA2B;GAC/B,MAAM,UAAU,UAAU,MAAM,IAAI;GACpC,IAAI,SACF,aAAa,OAAO,IAAI,mBAAmB,YAAY,KAAK,6BAA6B,MAAM,EAAE,OAAO,QAAQ,MAAM,CAAC,CAAC,CAAC;EAC7H;EAGA,gBAAgB,KAAK,QAAQ,WAAW,UAAU,YAAY;EAC9D,YAAY,UAAU,MAAM,OAAO,UAAU;GAC3C,IAAI,QAAQ,KAAK,GACf,aAAa,QAAQ,KAAK,CAAC;QACxB,IAAI,MAAM,UAAU,UACvB,aAAa;EACjB,CAAC;EACD,KAAK,QAAQ,WAAW,aAAa;EAErC,IAAI,MACF,UAAU;CACd,CAAC,CAAC;AACJ;;ACvDA,MAAa,SAAS;CACpB,SAASC;CACT,QAAQC;CACR,SAASC;CACT,OAAOC;CACP,MAAMC;CACKC;CACGC;AAChB"}
@@ -0,0 +1,61 @@
1
+ import { Dt as DependencyChange, I as HookContextFor, L as HookDependencies, V as Container, Y as Decision, lt as ServiceHook, zt as Clock } from "./index-DTYp044J.mjs";
2
+ /**
3
+ * Resolves when the work queue of `container` has drained and stays drained.
4
+ *
5
+ * A build or a hook that settles on a microtask can queue more work after a drain.
6
+ * So it waits one macrotask after each drain, and starts again when another drain happens.
7
+ * The macrotask is a real `setTimeout(0)`, so it does not resolve while the fake timers of a test runner hold `setTimeout`.
8
+ * A `manualClock` does not change `setTimeout`, so the two work together.
9
+ *
10
+ * It does not wait for work that a timer starts later, for example a requeue delay or a policy timeout. Move the clock first, then await `drained` again.
11
+ */
12
+ export declare function drained(container: Container): Promise<void>;
13
+ /** A clock that moves only when a test calls `advance`. Pass `clock` to `createContainer`. */
14
+ interface ManualClock {
15
+ /** The clock for `createContainer({ clock })`. Its time starts at 0. */
16
+ readonly clock: Clock;
17
+ /**
18
+ * Moves the time forward by `ms`, and runs each timer that is due, in the order of its time.
19
+ * A timer that a callback sets during the call runs at a later call, also when it is due now.
20
+ */
21
+ readonly advance: (ms: number) => void;
22
+ /** The number of timers that wait. A timer that was cancelled or that ran does not count. */
23
+ readonly pending: () => number;
24
+ }
25
+ /**
26
+ * Creates a manual clock for tests. It drives `timeout()`, `withTimeout()`, requeue delays, and the `start` and `stop` policy timeouts without real time.
27
+ *
28
+ * `advance` runs the timer callbacks synchronously. Await `drained(container)` after it, so that the work that the callbacks start settles.
29
+ */
30
+ export declare function manualClock(): ManualClock;
31
+ export interface HookContextOptions<D = undefined> {
32
+ /** The service name that the decisions carry. It defaults to `'test'`. */
33
+ service?: string;
34
+ /** The instance id that the decisions carry. It defaults to `'test-instance'`. */
35
+ instanceId?: string;
36
+ /** It defaults to `1`. */
37
+ attempt?: number;
38
+ previous?: Decision;
39
+ /** It defaults to a signal that does not abort. */
40
+ signal?: AbortSignal;
41
+ /** The snapshot of a dependency hook. It defaults to an empty record. */
42
+ dependsOn?: HookDependencies<D>;
43
+ /** The changes of a dependency hook. It defaults to an empty list. */
44
+ changes?: readonly DependencyChange[];
45
+ /** The clock for `issuedAt`. It defaults to `Date.now`. */
46
+ now?: () => number;
47
+ }
48
+ /**
49
+ * Creates a hook context for a unit test of a hook handler, or of a helper that gets `decide`.
50
+ *
51
+ * Its decisions are bound to this context, as in a real run. Use `checkDecision` to check a result as injeca does.
52
+ */
53
+ export declare function createHookContext<H extends ServiceHook, D = undefined>(hook: H, options?: HookContextOptions<D>): HookContextFor<H, D>;
54
+ /**
55
+ * Checks the value that a handler returned for `context`, as injeca does. `undefined` gives `undefined`: the default of the hook.
56
+ *
57
+ * @throws {InvalidDecisionError} for a decision from another context, or a kind that the hook does not accept. A value that is not a decision gives `undefined`.
58
+ */
59
+ export declare function checkDecision(context: object, value: unknown): Decision | undefined;
60
+ export type { ManualClock };
61
+ //# sourceMappingURL=testing.d.mts.map