injeca 0.2.0 → 0.3.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/README.md +359 -32
- package/dist/decision-odiPb2Au.mjs +194 -0
- package/dist/decision-odiPb2Au.mjs.map +1 -0
- package/dist/global-B9Bk2EG2.d.mts +153 -0
- package/dist/global-C0Nk0pU8.mjs +3790 -0
- package/dist/global-C0Nk0pU8.mjs.map +1 -0
- package/dist/global.d.mts +2 -2
- package/dist/global.mjs +1 -3
- package/dist/index-DXguNx2M.d.mts +643 -0
- package/dist/index.d.mts +174 -2
- package/dist/index.mjs +210 -2
- package/dist/index.mjs.map +1 -0
- package/dist/testing.d.mts +31 -0
- package/dist/testing.mjs +45 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +12 -25
- package/dist/builtin-BPDNf8Z-.mjs +0 -25
- package/dist/builtin-BPDNf8Z-.mjs.map +0 -1
- package/dist/global-BLY6_SI_.d.mts +0 -130
- package/dist/src-UXkTj4Np.mjs +0 -294
- package/dist/src-UXkTj4Np.mjs.map +0 -1
package/dist/global.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { invoke, provide, resetContainer, resolve, setLogger, start, stop };
|
|
1
|
+
import { a as resolve, c as stop, i as resetContainer, n as invoke, o as setLogger, r as provide, s as start, t as getContainer } from "./global-B9Bk2EG2.mjs";
|
|
2
|
+
export { getContainer, invoke, provide, resetContainer, resolve, setLogger, start, stop };
|
package/dist/global.mjs
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export { invoke, provide, resetContainer, resolve, setLogger, start, stop };
|
|
1
|
+
export { t as getContainer, n as invoke, r as provide, i as resetContainer, a as resolve, o as setLogger, s as start, c as stop } from "./global-C0Nk0pU8.mjs";
|
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
import { Logg } from "@guiiai/logg";
|
|
2
|
+
interface Logger {
|
|
3
|
+
provide: (name: string, dependencies: string[]) => void;
|
|
4
|
+
invoke: (dependencies: string[]) => void;
|
|
5
|
+
beforeRun: (name: string) => void;
|
|
6
|
+
run: (name: string, duration: number) => void;
|
|
7
|
+
hookOnStart: (name: string) => void;
|
|
8
|
+
hookOnStartComplete: (name: string, duration: number) => void;
|
|
9
|
+
hookOnStop: (name: string) => void;
|
|
10
|
+
hookOnStopComplete: (name: string, duration: number) => void;
|
|
11
|
+
running: () => void;
|
|
12
|
+
}
|
|
13
|
+
interface LoggerOptions {
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
logger?: Logger;
|
|
16
|
+
}
|
|
17
|
+
declare function createDefaultLogger(): Logger;
|
|
18
|
+
declare function createLoggLogger(logg: Logg): Logger;
|
|
19
|
+
declare function createNoopLogger(): Logger;
|
|
20
|
+
/**
|
|
21
|
+
* The time source of a container. Pass a custom clock to control time in tests.
|
|
22
|
+
*
|
|
23
|
+
* The reconciler uses it for requeue delays and hook timeouts. The work queue does not use it. It drains on microtasks.
|
|
24
|
+
*/
|
|
25
|
+
interface Clock {
|
|
26
|
+
now: () => number;
|
|
27
|
+
/** Calls `callback` after `ms` milliseconds. Returns a function that cancels the call. */
|
|
28
|
+
setTimeout: (callback: () => void, ms: number) => () => void;
|
|
29
|
+
}
|
|
30
|
+
declare const systemClock: Clock;
|
|
31
|
+
type OwnerValue = string | number | boolean | null | readonly OwnerValue[] | {
|
|
32
|
+
readonly [key: string]: OwnerValue;
|
|
33
|
+
};
|
|
34
|
+
/** A serializable record that names the owner of a container. injeca does not interpret its fields. */
|
|
35
|
+
interface OwnerRecord {
|
|
36
|
+
readonly [key: string]: OwnerValue;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The phase of a service.
|
|
40
|
+
*
|
|
41
|
+
* - `declared`: a transaction reserved the service. Consumers cannot resolve it.
|
|
42
|
+
* - `pending`: the service waits until its required dependencies are available, or for `start()`. It runs no code.
|
|
43
|
+
* - `conflict`: an exclusive key has more than one declaration in one resolution area. It runs no code.
|
|
44
|
+
* - `building`: `build` runs. The instance is not visible.
|
|
45
|
+
* - `starting`: the instance is published. The `start` hooks run.
|
|
46
|
+
* - `retrying`: a `start` hook returned `requeue`. The service keeps its instance and its dependencies, and waits for the next attempt. It is not available.
|
|
47
|
+
* - `running`: the instance serves calls. Only this phase has a status.
|
|
48
|
+
* - `stopping`: the service waits until its holders release it. Then the `stop` hooks and the effect disposers run.
|
|
49
|
+
* - `failed`: a build failed, a hook returned `fail`, retries ended, or a timeout failed. `start()` or `replace()` moves the service out of it.
|
|
50
|
+
* - `withdrawn`: the registration is withdrawn and the instance is disposed.
|
|
51
|
+
*/
|
|
52
|
+
type ServicePhase = 'declared' | 'pending' | 'conflict' | 'building' | 'starting' | 'retrying' | 'running' | 'stopping' | 'failed' | 'withdrawn';
|
|
53
|
+
/**
|
|
54
|
+
* The status of a running instance.
|
|
55
|
+
*
|
|
56
|
+
* - `ready`: the service works at full quality.
|
|
57
|
+
* - `degraded`: every call completes, at lower quality.
|
|
58
|
+
* - `unavailable`: the instance exists, but calls fail now.
|
|
59
|
+
*/
|
|
60
|
+
type ServiceStatus = 'ready' | 'degraded' | 'unavailable';
|
|
61
|
+
/** One link of a cause chain. A remote plugin uses it to report a cause inside the plugin. */
|
|
62
|
+
interface StatusCause {
|
|
63
|
+
readonly key: string;
|
|
64
|
+
readonly owner: OwnerRecord;
|
|
65
|
+
readonly status: ServiceStatus;
|
|
66
|
+
readonly reason?: string;
|
|
67
|
+
readonly cause?: StatusCause;
|
|
68
|
+
}
|
|
69
|
+
/** The second argument of `setStatus` in its object form. */
|
|
70
|
+
interface SetStatusOptions {
|
|
71
|
+
readonly reason?: string;
|
|
72
|
+
readonly cause?: StatusCause;
|
|
73
|
+
}
|
|
74
|
+
/** The identity and the effective status of one resolved dependency. */
|
|
75
|
+
interface DependencyState {
|
|
76
|
+
/** The key name of the provider. For `firstAvailable`, it is the selected key. */
|
|
77
|
+
readonly provider: string;
|
|
78
|
+
readonly instanceId: string;
|
|
79
|
+
readonly status: ServiceStatus;
|
|
80
|
+
}
|
|
81
|
+
/** One dependency in the snapshot of a dependency hook. */
|
|
82
|
+
interface DependencySnapshot<T> extends DependencyState {
|
|
83
|
+
readonly value: T;
|
|
84
|
+
}
|
|
85
|
+
/** The difference of one dependency between the last handled snapshot and the current snapshot. `undefined` means no provider. */
|
|
86
|
+
interface DependencyChange {
|
|
87
|
+
/** The local name in `dependsOn`. */
|
|
88
|
+
readonly key: string;
|
|
89
|
+
readonly from: DependencyState | undefined;
|
|
90
|
+
readonly to: DependencyState | undefined;
|
|
91
|
+
}
|
|
92
|
+
/** The state that `watch` sends. `phase` is `undefined` when no provider exists for the key. */
|
|
93
|
+
interface ServiceState {
|
|
94
|
+
readonly phase: ServicePhase | undefined;
|
|
95
|
+
/** The effective status. It is `undefined` outside `running`. */
|
|
96
|
+
readonly status: ServiceStatus | undefined;
|
|
97
|
+
readonly instanceId: string | undefined;
|
|
98
|
+
readonly reason?: string;
|
|
99
|
+
readonly cause?: StatusCause;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* One reason why a service is not `running`, or why it is not available.
|
|
103
|
+
*
|
|
104
|
+
* - `missing-provider`: no container in the resolution chain has a provider for a required key.
|
|
105
|
+
* - `failed-dependency`: the provider of a required key is in `failed`.
|
|
106
|
+
* - `pending-dependency`: the provider of a required key exists, but it does not run yet.
|
|
107
|
+
* - `unavailable-dependency`: the provider of a required key runs, but its effective status is `unavailable`. `cause` starts the cause chain.
|
|
108
|
+
* - `rejected-provider`: a resolution condition rejected the provider of a required key. `owner` and `metadata` name the provider.
|
|
109
|
+
* - `conflicting-dependency`: the provider of a required key is an exclusive key with more than one declaration.
|
|
110
|
+
* - `conflict`: the service itself is an exclusive key with more than one declaration. `owners` lists the owner of each declaration.
|
|
111
|
+
* - `failed`: the service itself is in `failed`.
|
|
112
|
+
* - `retrying`: a `start` hook of the service returned `requeue`. `attempt` is the attempt that requeued, and `reason` is its reason.
|
|
113
|
+
* - `not-started`: the container of the service is not started, and nothing demands the service.
|
|
114
|
+
*/
|
|
115
|
+
type ServiceBlocker = {
|
|
116
|
+
readonly kind: 'missing-provider';
|
|
117
|
+
readonly dependency: string;
|
|
118
|
+
readonly key: string;
|
|
119
|
+
} | {
|
|
120
|
+
readonly kind: 'failed-dependency';
|
|
121
|
+
readonly dependency: string;
|
|
122
|
+
readonly key: string;
|
|
123
|
+
readonly error: unknown;
|
|
124
|
+
} | {
|
|
125
|
+
readonly kind: 'pending-dependency';
|
|
126
|
+
readonly dependency: string;
|
|
127
|
+
readonly key: string;
|
|
128
|
+
readonly phase: ServicePhase;
|
|
129
|
+
} | {
|
|
130
|
+
readonly kind: 'unavailable-dependency';
|
|
131
|
+
readonly dependency: string;
|
|
132
|
+
readonly key: string;
|
|
133
|
+
readonly cause: StatusCause;
|
|
134
|
+
} | {
|
|
135
|
+
readonly kind: 'rejected-provider';
|
|
136
|
+
readonly dependency: string;
|
|
137
|
+
readonly key: string;
|
|
138
|
+
readonly owner: OwnerRecord;
|
|
139
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
140
|
+
} | {
|
|
141
|
+
readonly kind: 'conflicting-dependency';
|
|
142
|
+
readonly dependency: string;
|
|
143
|
+
readonly key: string;
|
|
144
|
+
readonly owners: readonly OwnerRecord[];
|
|
145
|
+
} | {
|
|
146
|
+
readonly kind: 'conflict';
|
|
147
|
+
readonly key: string;
|
|
148
|
+
readonly owners: readonly OwnerRecord[];
|
|
149
|
+
} | {
|
|
150
|
+
readonly kind: 'failed';
|
|
151
|
+
readonly error: unknown;
|
|
152
|
+
} | {
|
|
153
|
+
readonly kind: 'retrying';
|
|
154
|
+
readonly attempt: number;
|
|
155
|
+
readonly reason?: string;
|
|
156
|
+
} | {
|
|
157
|
+
readonly kind: 'not-started';
|
|
158
|
+
};
|
|
159
|
+
/** Why a service or an invocation is not `running`, or why it is not available. `graph(container).explain()` returns it. */
|
|
160
|
+
interface ServiceExplanation {
|
|
161
|
+
readonly name: string;
|
|
162
|
+
readonly kind: 'service' | 'invocation';
|
|
163
|
+
readonly owner: OwnerRecord;
|
|
164
|
+
readonly phase: ServicePhase;
|
|
165
|
+
/** The effective status of a running service. */
|
|
166
|
+
readonly status?: ServiceStatus;
|
|
167
|
+
readonly reason?: string;
|
|
168
|
+
/** The cause chain of the effective status. */
|
|
169
|
+
readonly cause?: StatusCause;
|
|
170
|
+
readonly blockers: readonly ServiceBlocker[];
|
|
171
|
+
}
|
|
172
|
+
declare const providedType: unique symbol;
|
|
173
|
+
declare const optionalType: unique symbol;
|
|
174
|
+
declare const fallbackType: unique symbol;
|
|
175
|
+
declare const conditionalType: unique symbol;
|
|
176
|
+
declare const optionalBrand: unique symbol;
|
|
177
|
+
declare const fallbackBrand: unique symbol;
|
|
178
|
+
declare const conditionBrand: unique symbol;
|
|
179
|
+
type DependencyMap = Record<string, any>;
|
|
180
|
+
/**
|
|
181
|
+
* A typed identity for a service. `provide` and `defineKey` return one.
|
|
182
|
+
*/
|
|
183
|
+
interface ProvidedKey<Key, T, _D extends DependencyMap | undefined> {
|
|
184
|
+
key: Key;
|
|
185
|
+
/** `true` for a key from `defineKey(name, { exclusive: true })`. Only one provider can exist in its resolution area. */
|
|
186
|
+
readonly exclusive?: boolean;
|
|
187
|
+
/** Carries the value type. It has no value at run time. */
|
|
188
|
+
readonly [providedType]?: T;
|
|
189
|
+
}
|
|
190
|
+
/** A key name, a key from `defineKey`, or the result of `provide`. */
|
|
191
|
+
type KeyReference = string | ProvidedKey<string, unknown, DependencyMap | undefined>;
|
|
192
|
+
interface KeyOptions {
|
|
193
|
+
/** Makes an exclusive key. Two or more providers in one resolution area all go to `conflict`. */
|
|
194
|
+
readonly exclusive?: boolean;
|
|
195
|
+
}
|
|
196
|
+
/** A frozen record on a registration. Resolution conditions and graph queries read it. */
|
|
197
|
+
type ServiceMetadata = Readonly<Record<string, unknown>>;
|
|
198
|
+
/** The read-only information about a provider that a resolution condition gets. */
|
|
199
|
+
interface ProviderInfo {
|
|
200
|
+
/** The key name of the provider. */
|
|
201
|
+
readonly key: string;
|
|
202
|
+
/** The owner record of the container of the provider. */
|
|
203
|
+
readonly owner: OwnerRecord;
|
|
204
|
+
readonly metadata: ServiceMetadata;
|
|
205
|
+
}
|
|
206
|
+
/** A resolution condition from `where`. It must be pure and synchronous. A thrown error counts as `false`. */
|
|
207
|
+
type ResolutionCondition = (provider: ProviderInfo) => boolean;
|
|
208
|
+
type ProvidedBy<T> = string & {
|
|
209
|
+
__providedType?: T;
|
|
210
|
+
};
|
|
211
|
+
/** A dependency marker from `optional(key)`. A missing provider gives `undefined` and does not keep the dependent `pending`. */
|
|
212
|
+
interface OptionalDependency<T> {
|
|
213
|
+
readonly [optionalBrand]: true;
|
|
214
|
+
/** The names of the keys, in order. More than one name comes from `optional(firstAvailable(...))`. */
|
|
215
|
+
readonly dependencies: readonly string[];
|
|
216
|
+
/** The resolution condition from `where`, when the marker has one. */
|
|
217
|
+
readonly condition?: ResolutionCondition;
|
|
218
|
+
/** Carries the value type. It has no value at run time. */
|
|
219
|
+
readonly [optionalType]?: T;
|
|
220
|
+
}
|
|
221
|
+
/** A required dependency marker from `where(key, condition)`. A provider that the condition rejects does not resolve. */
|
|
222
|
+
interface ConditionalDependency<T> {
|
|
223
|
+
readonly [conditionBrand]: true;
|
|
224
|
+
/** The name of the key. */
|
|
225
|
+
readonly dependencies: readonly string[];
|
|
226
|
+
readonly condition: ResolutionCondition;
|
|
227
|
+
/** Carries the value type. It has no value at run time. */
|
|
228
|
+
readonly [conditionalType]?: T;
|
|
229
|
+
}
|
|
230
|
+
/** A fallback dependency marker from `firstAvailable(...keys)`. It resolves to the first available provider in the list. */
|
|
231
|
+
interface FallbackDependency<T> {
|
|
232
|
+
readonly [fallbackBrand]: true;
|
|
233
|
+
/** The names of the keys, in order of preference. */
|
|
234
|
+
readonly dependencies: readonly string[];
|
|
235
|
+
/** Carries the value type. It has no value at run time. */
|
|
236
|
+
readonly [fallbackType]?: T;
|
|
237
|
+
}
|
|
238
|
+
/** One value of a `dependsOn` declaration: a name, a key, an optional marker, a fallback marker, or a condition marker. */
|
|
239
|
+
type DependencyDeclaration = string | ProvidedKey<string, unknown, DependencyMap | undefined> | OptionalDependency<unknown> | FallbackDependency<unknown> | ConditionalDependency<unknown>;
|
|
240
|
+
type DependencyDeclarations = Record<string, DependencyDeclaration>;
|
|
241
|
+
/** The resolved value of an optional dependency. */
|
|
242
|
+
interface OptionalValue<T> {
|
|
243
|
+
readonly value: T;
|
|
244
|
+
readonly status: ServiceStatus;
|
|
245
|
+
}
|
|
246
|
+
type InferProvided<T> = T extends ProvidedKey<any, infer P, any> ? P : T extends ProvidedBy<infer P> ? P : never;
|
|
247
|
+
/** A required dependency is its value. An optional dependency is `{ value, status }` or `undefined`. */
|
|
248
|
+
type ResolveDependencyDeclaration<Deps extends DependencyDeclarations> = { [K in keyof Deps]: Deps[K] extends OptionalDependency<infer T> ? OptionalValue<T> | undefined : Deps[K] extends FallbackDependency<infer T> ? T : Deps[K] extends ConditionalDependency<infer T> ? T : Deps[K] extends ProvidedKey<any, infer T, any> ? T : Deps[K] extends ProvidedBy<infer T> ? T : any; };
|
|
249
|
+
/** The hooks that `on` registers in `build` and in an invocation callback. */
|
|
250
|
+
type ServiceHook = 'start' | 'stop' | 'dependency-change' | 'dependency-status-change';
|
|
251
|
+
/** The hooks that run when a dependency changes. Their context has `dependsOn` and `changes`. */
|
|
252
|
+
type DependencyHook = 'dependency-change' | 'dependency-status-change';
|
|
253
|
+
interface DecisionOptions {
|
|
254
|
+
readonly reason?: string;
|
|
255
|
+
}
|
|
256
|
+
interface ExponentialBackoff {
|
|
257
|
+
readonly kind: 'exponential';
|
|
258
|
+
readonly initial: number;
|
|
259
|
+
readonly max: number;
|
|
260
|
+
readonly jitter?: number;
|
|
261
|
+
}
|
|
262
|
+
interface RequeueOptions extends DecisionOptions {
|
|
263
|
+
/** A fixed delay in milliseconds. */
|
|
264
|
+
readonly after?: number;
|
|
265
|
+
readonly backoff?: ExponentialBackoff;
|
|
266
|
+
readonly maxAttempts?: number;
|
|
267
|
+
}
|
|
268
|
+
/** The fields that injeca fills from the hook context. */
|
|
269
|
+
interface DecisionSource {
|
|
270
|
+
/** The name of the service, or of the invocation. */
|
|
271
|
+
readonly service: string;
|
|
272
|
+
readonly instanceId: string;
|
|
273
|
+
readonly hook: ServiceHook;
|
|
274
|
+
readonly attempt: number;
|
|
275
|
+
/** The time of the container clock when `decide` created the decision. */
|
|
276
|
+
readonly issuedAt: number;
|
|
277
|
+
}
|
|
278
|
+
interface HandledDecision extends DecisionSource, DecisionOptions {
|
|
279
|
+
readonly kind: 'handled';
|
|
280
|
+
}
|
|
281
|
+
interface RebuildDecision extends DecisionSource, DecisionOptions {
|
|
282
|
+
readonly kind: 'rebuild';
|
|
283
|
+
}
|
|
284
|
+
interface RequeueDecision extends DecisionSource, RequeueOptions {
|
|
285
|
+
readonly kind: 'requeue';
|
|
286
|
+
}
|
|
287
|
+
interface StopDecision extends DecisionSource, DecisionOptions {
|
|
288
|
+
readonly kind: 'stop';
|
|
289
|
+
}
|
|
290
|
+
interface FailDecision extends DecisionSource, DecisionOptions {
|
|
291
|
+
readonly kind: 'fail';
|
|
292
|
+
readonly error: unknown;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The value that a hook returns to tell injeca what to do next. Only `decide` in the hook context creates it.
|
|
296
|
+
*/
|
|
297
|
+
type Decision = HandledDecision | RebuildDecision | RequeueDecision | StopDecision | FailDecision;
|
|
298
|
+
type DecisionKind = Decision['kind'];
|
|
299
|
+
/** The decision kinds that a hook accepts. */
|
|
300
|
+
type HookDecisionKind<H extends ServiceHook> = H extends 'start' ? 'handled' | 'requeue' | 'stop' | 'fail' : H extends 'stop' ? 'handled' | 'fail' : DecisionKind;
|
|
301
|
+
/** The decisions that a hook accepts. */
|
|
302
|
+
type DecisionFor<H extends ServiceHook> = Extract<Decision, {
|
|
303
|
+
readonly kind: HookDecisionKind<H>;
|
|
304
|
+
}>;
|
|
305
|
+
/**
|
|
306
|
+
* The value that a hook handler can return.
|
|
307
|
+
*
|
|
308
|
+
* A decision tells injeca what to do next. Any other value, for example the result of `app.listen()`, selects the default of the hook.
|
|
309
|
+
* So the shorthand `on('start', () => app.listen(port))` type-checks.
|
|
310
|
+
* The `decide` of each hook has only the methods that the hook accepts. A decision from another run fails at run time with `invalid-decision`.
|
|
311
|
+
*/
|
|
312
|
+
type HookResult<_H extends ServiceHook = ServiceHook> = unknown;
|
|
313
|
+
/** All decision constructors. A hook context has only the constructors that its hook accepts. */
|
|
314
|
+
interface Decide {
|
|
315
|
+
readonly handled: (options?: DecisionOptions) => HandledDecision;
|
|
316
|
+
readonly rebuild: (options?: DecisionOptions) => RebuildDecision;
|
|
317
|
+
readonly requeue: (options?: RequeueOptions) => RequeueDecision;
|
|
318
|
+
readonly stop: (options?: DecisionOptions) => StopDecision;
|
|
319
|
+
readonly fail: (error: unknown, options?: DecisionOptions) => FailDecision;
|
|
320
|
+
}
|
|
321
|
+
/** The `decide` object of a hook context. A method that the hook does not accept is a type error. */
|
|
322
|
+
type DecideFor<H extends ServiceHook> = Pick<Decide, HookDecisionKind<H>>;
|
|
323
|
+
/** The context of an `onTimeout` handler. `hook` tells which hook timed out, and selects the methods of `decide`. */
|
|
324
|
+
type TimeoutContext = { readonly [H in 'start' | 'stop']: {
|
|
325
|
+
readonly hook: H;
|
|
326
|
+
/** The configured timeout in milliseconds. */
|
|
327
|
+
readonly timeoutMs: number;
|
|
328
|
+
/** The attempt of the hook run that timed out. */
|
|
329
|
+
readonly attempt: number;
|
|
330
|
+
/** The last decision of this hook for this instance. */
|
|
331
|
+
readonly previous: DecisionFor<H> | undefined;
|
|
332
|
+
readonly decide: DecideFor<H>;
|
|
333
|
+
}; }['start' | 'stop'];
|
|
334
|
+
/**
|
|
335
|
+
* Decides what happens when a `start` or `stop` hook times out. It runs synchronously.
|
|
336
|
+
*
|
|
337
|
+
* A value that is not a decision, a promise, or a throw gives `fail` with `hook-timeout`.
|
|
338
|
+
*/
|
|
339
|
+
type TimeoutHandler = (context: TimeoutContext) => unknown;
|
|
340
|
+
/** The timeouts of the `start` and `stop` hooks in milliseconds. A missing value means no timeout. */
|
|
341
|
+
interface HookTimeouts {
|
|
342
|
+
/** The time for all `start` hooks of one attempt. */
|
|
343
|
+
start?: number;
|
|
344
|
+
/** The time for all `stop` hooks and effect disposers of one instance. */
|
|
345
|
+
stop?: number;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* The retry and timeout options of a service or a container. injeca has no built-in values.
|
|
349
|
+
*
|
|
350
|
+
* A service value overrides a container value. A container without a value uses the value of its nearest ancestor that has one.
|
|
351
|
+
*/
|
|
352
|
+
interface PolicyOptions {
|
|
353
|
+
/**
|
|
354
|
+
* Limits the attempts of a hook that returns `requeue`. A `maxAttempts` on the decision overrides it.
|
|
355
|
+
* Without a limit, the requeue continues until the dependency or the container changes.
|
|
356
|
+
*/
|
|
357
|
+
maxAttempts?: number;
|
|
358
|
+
/** The timeouts of the `start` and `stop` hooks. Each field overrides the same field of the container. */
|
|
359
|
+
timeouts?: HookTimeouts;
|
|
360
|
+
/** Decides what happens when a hook times out. Without it, the result is `fail` with `hook-timeout`. */
|
|
361
|
+
onTimeout?: TimeoutHandler;
|
|
362
|
+
}
|
|
363
|
+
interface Container {
|
|
364
|
+
logger: Logger;
|
|
365
|
+
readonly owner: OwnerRecord;
|
|
366
|
+
readonly parent: Container | undefined;
|
|
367
|
+
}
|
|
368
|
+
/** The options of `createContainer`. `maxAttempts`, `timeouts`, and `onTimeout` apply to each service of the container and of its descendants that does not set its own value. */
|
|
369
|
+
interface ContainerOptions extends LoggerOptions, PolicyOptions {
|
|
370
|
+
/** Makes a child container. It resolves keys from its own registrations and from those of its ancestors. */
|
|
371
|
+
parent?: Container;
|
|
372
|
+
/** A serializable owner record. It defaults to an empty record. */
|
|
373
|
+
owner?: OwnerRecord;
|
|
374
|
+
/** The time source. Only a root container reads it. A child container uses the clock of its root. */
|
|
375
|
+
clock?: Clock;
|
|
376
|
+
/**
|
|
377
|
+
* The random source for the backoff jitter. It returns a number from 0 up to, but not including, 1. It defaults to `Math.random`.
|
|
378
|
+
* Only a root container reads it. A child container uses the random source of its root.
|
|
379
|
+
*/
|
|
380
|
+
random?: () => number;
|
|
381
|
+
/**
|
|
382
|
+
* The keys that do not resolve from the ancestors. The container and its descendants resolve them only from their own registrations.
|
|
383
|
+
* An isolated key also ends the resolution area of an exclusive key of an ancestor.
|
|
384
|
+
*/
|
|
385
|
+
isolate?: readonly KeyReference[];
|
|
386
|
+
}
|
|
387
|
+
type HookDependency<V> = [Exclude<V, undefined>] extends [OptionalValue<infer T>] ? DependencySnapshot<T> | undefined : DependencySnapshot<V>;
|
|
388
|
+
/** The snapshot of a dependency hook: each dependency with its value, `instanceId`, and effective status. An optional dependency can be `undefined`. */
|
|
389
|
+
type HookDependencies<D> = D extends DependencyMap ? { readonly [K in keyof D]: HookDependency<D[K]>; } : Readonly<Record<string, DependencySnapshot<unknown> | undefined>>;
|
|
390
|
+
type Disposer = () => void | Promise<void>;
|
|
391
|
+
type EffectSetup = () => Disposer | void;
|
|
392
|
+
/** The context that each hook handler gets. */
|
|
393
|
+
interface HookContext<H extends ServiceHook> {
|
|
394
|
+
/** Creates the decisions that this hook accepts. Each decision is bound to this run. */
|
|
395
|
+
readonly decide: DecideFor<H>;
|
|
396
|
+
/** The number of the current run of this hook for this instance. The first run is `1`. A requeue adds one. */
|
|
397
|
+
readonly attempt: number;
|
|
398
|
+
/** The last decision of this hook for this instance. */
|
|
399
|
+
readonly previous: DecisionFor<H> | undefined;
|
|
400
|
+
/** Aborts when a newer target supersedes this run, or when the instance is disposed. */
|
|
401
|
+
readonly signal: AbortSignal;
|
|
402
|
+
}
|
|
403
|
+
/** The context of `dependency-change` and `dependency-status-change`. */
|
|
404
|
+
interface DependencyHookContext<H extends DependencyHook, D = undefined> extends HookContext<H> {
|
|
405
|
+
/** The current snapshot of all dependencies. Decide from it, not from one change only. */
|
|
406
|
+
readonly dependsOn: HookDependencies<D>;
|
|
407
|
+
/** The difference between the last handled snapshot and the current snapshot. */
|
|
408
|
+
readonly changes: readonly DependencyChange[];
|
|
409
|
+
}
|
|
410
|
+
type HookContextFor<H extends ServiceHook, D = undefined> = H extends DependencyHook ? DependencyHookContext<H, D> : HookContext<H>;
|
|
411
|
+
type HookHandler<H extends ServiceHook = ServiceHook, D = undefined> = (context: HookContextFor<H, D>) => HookResult<H> | Promise<HookResult<H>>;
|
|
412
|
+
/** The lifecycle members that `build` and an invocation callback get. */
|
|
413
|
+
interface LifecycleContext<D = undefined> {
|
|
414
|
+
/** Registers a hook. It is valid only while `build` or the callback runs. A later call throws `hook-outside-build`. */
|
|
415
|
+
on: <H extends ServiceHook>(hook: H, handler: HookHandler<H, D>) => void;
|
|
416
|
+
/** Runs `setup` and stores the returned disposer on the instance. */
|
|
417
|
+
effect: (setup: EffectSetup) => void;
|
|
418
|
+
/** Aborts when a newer target supersedes the build, or when the instance is disposed. */
|
|
419
|
+
signal: AbortSignal;
|
|
420
|
+
}
|
|
421
|
+
type BuildContext<D extends DependencyMap | undefined = undefined> = {
|
|
422
|
+
container: Container;
|
|
423
|
+
name: string;
|
|
424
|
+
/** The id of the instance that this build creates. */
|
|
425
|
+
instanceId: string;
|
|
426
|
+
/** The owner record of the consumer container, when the service has `perConsumer: true`. */
|
|
427
|
+
consumer?: OwnerRecord;
|
|
428
|
+
/**
|
|
429
|
+
* Sets the own status of the instance. It stays valid after `build` returns.
|
|
430
|
+
* After the instance is disposed, a call has no effect and goes to the observe stream.
|
|
431
|
+
*/
|
|
432
|
+
setStatus: (status: ServiceStatus, reasonOrOptions?: string | SetStatusOptions) => void;
|
|
433
|
+
} & LifecycleContext<D> & (D extends undefined ? {
|
|
434
|
+
dependsOn?: unknown;
|
|
435
|
+
} : {
|
|
436
|
+
dependsOn: D;
|
|
437
|
+
});
|
|
438
|
+
type InvocationContext<D = undefined> = LifecycleContext<D>;
|
|
439
|
+
/** One service, invocation, or declared service in a graph query result. */
|
|
440
|
+
interface GraphService {
|
|
441
|
+
/** The key name of the service, or the name of the invocation. */
|
|
442
|
+
readonly key: string;
|
|
443
|
+
readonly kind: 'service' | 'invocation';
|
|
444
|
+
/** The owner record of the container of the service. */
|
|
445
|
+
readonly owner: OwnerRecord;
|
|
446
|
+
readonly phase: ServicePhase;
|
|
447
|
+
/** The effective status of a running service. */
|
|
448
|
+
readonly status?: ServiceStatus;
|
|
449
|
+
readonly instanceId?: string;
|
|
450
|
+
readonly metadata: ServiceMetadata;
|
|
451
|
+
readonly exclusive: boolean;
|
|
452
|
+
readonly perConsumer: boolean;
|
|
453
|
+
/** The owner record of the consumer container of a `perConsumer` instance. */
|
|
454
|
+
readonly consumer?: OwnerRecord;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* How a declared edge resolves now.
|
|
458
|
+
*
|
|
459
|
+
* - `resolved`: a running provider serves the edge.
|
|
460
|
+
* - `not-running`: a provider exists, but it does not run.
|
|
461
|
+
* - `missing`: no provider exists.
|
|
462
|
+
* - `rejected`: a resolution condition rejected the provider.
|
|
463
|
+
* - `conflict`: the provider is an exclusive key with more than one declaration.
|
|
464
|
+
*/
|
|
465
|
+
type GraphResolution = 'resolved' | 'not-running' | 'missing' | 'rejected' | 'conflict';
|
|
466
|
+
/** One declared edge of a service. */
|
|
467
|
+
interface GraphDependency {
|
|
468
|
+
/** The local name in `dependsOn`. */
|
|
469
|
+
readonly name: string;
|
|
470
|
+
/** The key names of the edge. A `firstAvailable` edge has its list. */
|
|
471
|
+
readonly keys: readonly string[];
|
|
472
|
+
readonly optional: boolean;
|
|
473
|
+
readonly fallback: boolean;
|
|
474
|
+
/** `true` when the edge has a resolution condition from `where`. */
|
|
475
|
+
readonly conditional: boolean;
|
|
476
|
+
readonly resolution: GraphResolution;
|
|
477
|
+
/** The provider that the edge selects now. A `missing` edge has none. */
|
|
478
|
+
readonly provider?: GraphService;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* A proposed change for `impact`.
|
|
482
|
+
*
|
|
483
|
+
* - `withdraw`: the service of `key` is withdrawn.
|
|
484
|
+
* - `replace`: the service of `key` gets a new instance.
|
|
485
|
+
* - `dispose`: `container` and its descendants are disposed.
|
|
486
|
+
*/
|
|
487
|
+
type ImpactChange = {
|
|
488
|
+
readonly kind: 'withdraw';
|
|
489
|
+
readonly key: KeyReference;
|
|
490
|
+
} | {
|
|
491
|
+
readonly kind: 'replace';
|
|
492
|
+
readonly key: KeyReference;
|
|
493
|
+
} | {
|
|
494
|
+
readonly kind: 'dispose';
|
|
495
|
+
readonly container: Container;
|
|
496
|
+
};
|
|
497
|
+
/** The services that a proposed change affects. Each list has only services that have an instance now. */
|
|
498
|
+
interface ImpactResult {
|
|
499
|
+
/** The services that stop: the withdrawn services, and the dependents that lose a required dependency. */
|
|
500
|
+
readonly stopped: readonly GraphService[];
|
|
501
|
+
/** The dependents that rebuild, because a dependency changes and they have no `dependency-change` handler. */
|
|
502
|
+
readonly rebuilt: readonly GraphService[];
|
|
503
|
+
/** The dependents that get a `dependency-change` call. Their handler decides what happens. */
|
|
504
|
+
readonly notified: readonly GraphService[];
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* The graph queries of a container. They are pure reads and never change state.
|
|
508
|
+
*
|
|
509
|
+
* The queries cover the container and its descendants. A key resolves as for a consumer in the container: from the container, then from its ancestors.
|
|
510
|
+
*/
|
|
511
|
+
interface Graph {
|
|
512
|
+
/** All services and invocations, with the declared services of open transactions. */
|
|
513
|
+
readonly services: () => readonly GraphService[];
|
|
514
|
+
/** The declared edges of the service of `key`. */
|
|
515
|
+
readonly dependencies: (key: KeyReference) => readonly GraphDependency[];
|
|
516
|
+
/** The services whose edges select the service of `key` now. */
|
|
517
|
+
readonly dependents: (key: KeyReference) => readonly GraphService[];
|
|
518
|
+
/**
|
|
519
|
+
* The topological order: each provider comes before its dependents.
|
|
520
|
+
* With `keys`, the order has only those services and their transitive dependencies. The members of one cycle come together, in registration order.
|
|
521
|
+
*/
|
|
522
|
+
readonly order: (keys?: readonly KeyReference[]) => readonly GraphService[];
|
|
523
|
+
/** Each dependency cycle, as a list of services. */
|
|
524
|
+
readonly cycles: () => readonly (readonly GraphService[])[];
|
|
525
|
+
/** The services that a proposed change stops, rebuilds, or notifies. It runs on a copy of the graph. */
|
|
526
|
+
readonly impact: (change: ImpactChange) => ImpactResult;
|
|
527
|
+
/** Why the service of `key` is not `running`: missing, conflicting, rejected, failed, or unavailable dependencies. */
|
|
528
|
+
readonly explain: (key: KeyReference) => ServiceExplanation | undefined;
|
|
529
|
+
}
|
|
530
|
+
/** The registration options that each object form of `provide` accepts. */
|
|
531
|
+
interface RegistrationOptions extends PolicyOptions {
|
|
532
|
+
/** A record that resolution conditions and graph queries read. injeca freezes a copy. */
|
|
533
|
+
metadata?: ServiceMetadata;
|
|
534
|
+
/**
|
|
535
|
+
* Runs `build` once for each consumer container. The build context then has `consumer`.
|
|
536
|
+
* Each instance disposes with its consumer container.
|
|
537
|
+
*/
|
|
538
|
+
perConsumer?: boolean;
|
|
539
|
+
}
|
|
540
|
+
type ProvideOptionObject<T, D extends DependencyMap | undefined = undefined> = {
|
|
541
|
+
build: (context: BuildContext<D>) => T | Promise<T>;
|
|
542
|
+
} & RegistrationOptions & (D extends undefined ? {
|
|
543
|
+
dependsOn?: Record<string, never>;
|
|
544
|
+
} : {
|
|
545
|
+
dependsOn: { [K in keyof D]: string; };
|
|
546
|
+
});
|
|
547
|
+
type ProvideOptionFunc<T, D extends DependencyMap | undefined = undefined> = (context: BuildContext<D>) => T | Promise<T>;
|
|
548
|
+
type ProvideOption<T, D extends DependencyMap | undefined = undefined> = ProvideOptionObject<T, D> | ProvideOptionFunc<T, D>;
|
|
549
|
+
interface ProvideOptionObjectWithKeys<T, Deps extends DependencyDeclarations> extends RegistrationOptions {
|
|
550
|
+
build: (context: BuildContext<ResolveDependencyDeclaration<Deps>>) => T | Promise<T>;
|
|
551
|
+
dependsOn: Deps;
|
|
552
|
+
}
|
|
553
|
+
type ProvideOptionWithKeys<T, Deps extends DependencyDeclarations> = ProvideOptionObjectWithKeys<T, Deps>;
|
|
554
|
+
type InvokeOptionObject<D extends DependencyMap | undefined = undefined> = {
|
|
555
|
+
callback: (dependencies: D, context: InvocationContext<D>) => void | Promise<void>;
|
|
556
|
+
} & (D extends undefined ? {
|
|
557
|
+
dependsOn?: Record<string, never>;
|
|
558
|
+
} : {
|
|
559
|
+
dependsOn: { [K in keyof D]: string; };
|
|
560
|
+
});
|
|
561
|
+
type InvokeOptionFunc<D extends DependencyMap | undefined = undefined> = (dependencies: D, context: InvocationContext<D>) => void | Promise<void>;
|
|
562
|
+
type InvokeOption<D extends DependencyMap | undefined = undefined> = InvokeOptionObject<D> | InvokeOptionFunc<D>;
|
|
563
|
+
interface InvokeOptionObjectWithKeys<Deps extends DependencyDeclarations> {
|
|
564
|
+
callback: (dependencies: ResolveDependencyDeclaration<Deps>, context: InvocationContext<ResolveDependencyDeclaration<Deps>>) => void | Promise<void>;
|
|
565
|
+
dependsOn: Deps;
|
|
566
|
+
}
|
|
567
|
+
type InvokeOptionWithKeys<Deps extends DependencyDeclarations> = InvokeOptionObjectWithKeys<Deps>;
|
|
568
|
+
/**
|
|
569
|
+
* The `replace()` of a registration. It takes the function shorthand, or the object form with or without `dependsOn`.
|
|
570
|
+
* An option without `metadata`, `maxAttempts`, `timeouts`, or `onTimeout` keeps that value of the registration. `perConsumer` does not change.
|
|
571
|
+
*/
|
|
572
|
+
interface ReplaceFunction<T> {
|
|
573
|
+
<Deps extends DependencyDeclarations>(option: ProvideOptionWithKeys<T, Deps>): Promise<boolean>;
|
|
574
|
+
(option: ProvideOption<T, undefined>): Promise<boolean>;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* The result of `provide`: the typed key of the service, with `withdraw()` and `replace()`.
|
|
578
|
+
*/
|
|
579
|
+
interface Registration<Key, T, D extends DependencyMap | undefined> extends ProvidedKey<Key, T, D> {
|
|
580
|
+
/**
|
|
581
|
+
* Withdraws the service. Dependents stop first. Then the service runs its `stop` hooks and effect disposers.
|
|
582
|
+
*
|
|
583
|
+
* Resolves `false` for a stale registration and does not change any service. Rejects with the teardown errors.
|
|
584
|
+
*/
|
|
585
|
+
readonly withdraw: () => Promise<boolean>;
|
|
586
|
+
/**
|
|
587
|
+
* Replaces the instance of the service without a gap.
|
|
588
|
+
*
|
|
589
|
+
* The old instance keeps serving with its status while the new instance runs `build` and `start`. The swap is one batch.
|
|
590
|
+
* Resolves `true` after the swap. Resolves `false` for a stale registration, or when a newer `replace` or a withdrawal supersedes this call.
|
|
591
|
+
* Rejects with the build or start error of the new instance, and the old instance does not change.
|
|
592
|
+
* Rejects with `replace-while-stopping` when the service is in `stopping`.
|
|
593
|
+
*/
|
|
594
|
+
readonly replace: ReplaceFunction<T>;
|
|
595
|
+
}
|
|
596
|
+
/** The result of `invoke`. */
|
|
597
|
+
interface InvocationHandle {
|
|
598
|
+
/** Withdraws the invocation. Resolves `false` when it is already withdrawn. Rejects with the teardown errors. */
|
|
599
|
+
readonly withdraw: () => Promise<boolean>;
|
|
600
|
+
}
|
|
601
|
+
interface DeclareOptions {
|
|
602
|
+
/** The declared edges. A later `tx.provide` without `dependsOn` uses them. */
|
|
603
|
+
dependsOn?: DependencyDeclarations;
|
|
604
|
+
/** An optional declaration does not need a `tx.provide`. Without one, the commit drops it. */
|
|
605
|
+
optional?: boolean;
|
|
606
|
+
}
|
|
607
|
+
/** The `provide` of a transaction. It takes a name or a key, as `provide` does. */
|
|
608
|
+
interface TransactionProvide {
|
|
609
|
+
<T, Key extends string, Deps extends DependencyDeclarations>(name: Key, option: ProvideOptionWithKeys<T, Deps>): Registration<Key, T, ResolveDependencyDeclaration<Deps>>;
|
|
610
|
+
<D extends DependencyMap | undefined, T = unknown, Key extends string = string>(name: Key, option: ProvideOption<T, D>): Registration<Key, T, D>;
|
|
611
|
+
<T, Key extends string, Deps extends DependencyDeclarations>(key: ProvidedKey<Key, T, DependencyMap | undefined>, option: ProvideOptionWithKeys<NoInfer<T>, Deps>): Registration<Key, T, ResolveDependencyDeclaration<Deps>>;
|
|
612
|
+
<T, Key extends string>(key: ProvidedKey<Key, T, DependencyMap | undefined>, option: ProvideOption<NoInfer<T>, undefined>): Registration<Key, T, undefined>;
|
|
613
|
+
}
|
|
614
|
+
/** The `replace` of a transaction. It takes the current registration of the key at the commit. */
|
|
615
|
+
interface TransactionReplace {
|
|
616
|
+
<T, Deps extends DependencyDeclarations>(key: ProvidedKey<string, T, DependencyMap | undefined> | string, option: ProvideOptionWithKeys<NoInfer<T>, Deps>): void;
|
|
617
|
+
<T>(key: ProvidedKey<string, T, DependencyMap | undefined> | string, option: ProvideOption<NoInfer<T>, undefined>): void;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* A set of registrations that publish together. `transaction(container)` creates it.
|
|
621
|
+
*
|
|
622
|
+
* Nothing is visible to consumers before `commit()`. A failed build publishes nothing.
|
|
623
|
+
*/
|
|
624
|
+
interface Transaction {
|
|
625
|
+
/** Reserves a service. Graph queries see it as `declared`. Consumers cannot resolve it. */
|
|
626
|
+
readonly declare: (key: KeyReference, options?: DeclareOptions) => void;
|
|
627
|
+
/** Fills a declared service, or adds a new service. The registration becomes current at the commit. */
|
|
628
|
+
readonly provide: TransactionProvide;
|
|
629
|
+
/** Replaces the current registration of `key` in the container at the commit, as `replace()` does. */
|
|
630
|
+
readonly replace: TransactionReplace;
|
|
631
|
+
/**
|
|
632
|
+
* Builds the services in dependency order, then publishes them in one batch. Then the `start` hooks run.
|
|
633
|
+
*
|
|
634
|
+
* A service whose required dependencies are not available goes to `pending`. That is not a failure.
|
|
635
|
+
* If one build fails, nothing publishes, no `start` hook runs, and the promise rejects with the build error.
|
|
636
|
+
* Resolves after the publish. It does not wait for the `start` hooks.
|
|
637
|
+
*/
|
|
638
|
+
readonly commit: () => Promise<void>;
|
|
639
|
+
/** Removes all declared and built services of the transaction. A build that settles later cannot publish. */
|
|
640
|
+
readonly abort: () => Promise<void>;
|
|
641
|
+
}
|
|
642
|
+
export { HookResult as $, HookContextFor as A, ServiceStatus as At, TimeoutHandler as B, ImpactChange as C, DependencyState as Ct, Disposer as D, ServiceExplanation as Dt, DependencyHookContext as E, ServiceBlocker as Et, Container as F, Logger as Ft, DecisionKind as G, DecideFor as H, ContainerOptions as I, LoggerOptions as It, DependencyHook as J, DecisionOptions as K, HookTimeouts as L, createDefaultLogger as Lt, HookHandler as M, StatusCause as Mt, InvocationContext as N, Clock as Nt, EffectSetup as O, ServicePhase as Ot, LifecycleContext as P, systemClock as Pt, HookDecisionKind as Q, PolicyOptions as R, createLoggLogger as Rt, GraphService as S, DependencySnapshot as St, BuildContext as T, OwnerValue as Tt, Decision as U, Decide as V, DecisionFor as W, FailDecision as X, ExponentialBackoff as Y, HandledDecision as Z, RegistrationOptions as _, ProviderInfo as _t, InvocationHandle as a, ConditionalDependency as at, GraphDependency as b, ServiceMetadata as bt, InvokeOptionObject as c, DependencyMap as ct, ProvideOption as d, KeyOptions as dt, RebuildDecision as et, ProvideOptionFunc as f, KeyReference as ft, Registration as g, ProvidedKey as gt, ProvideOptionWithKeys as h, ProvidedBy as ht, TransactionReplace as i, StopDecision as it, HookDependencies as j, SetStatusOptions as jt, HookContext as k, ServiceState as kt, InvokeOptionObjectWithKeys as l, FallbackDependency as lt, ProvideOptionObjectWithKeys as m, OptionalValue as mt, Transaction as n, RequeueOptions as nt, InvokeOption as o, DependencyDeclaration as ot, ProvideOptionObject as p, OptionalDependency as pt, DecisionSource as q, TransactionProvide as r, ServiceHook as rt, InvokeOptionFunc as s, DependencyDeclarations as st, DeclareOptions as t, RequeueDecision as tt, InvokeOptionWithKeys as u, InferProvided as ut, ReplaceFunction as v, ResolutionCondition as vt, ImpactResult as w, OwnerRecord as wt, GraphResolution as x, DependencyChange as xt, Graph as y, ResolveDependencyDeclaration as yt, TimeoutContext as z, createNoopLogger as zt };
|
|
643
|
+
//# sourceMappingURL=index-DXguNx2M.d.mts.map
|