ripple-di 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,379 @@
1
+ //#region src/value.d.ts
2
+ declare const asValueBrand: unique symbol;
3
+ /**
4
+ * A factory result marked as the dependency value itself.
5
+ *
6
+ * Create it with `asValue`.
7
+ */
8
+ interface AsValue<T> {
9
+ readonly [asValueBrand]: (value: T) => T;
10
+ }
11
+ /** What a dependency factory may return: the value, or a marked value. */
12
+ type FactoryResult<T> = T | AsValue<T>;
13
+ /**
14
+ * Uses a factory result as the dependency value even when it is a `Promise`.
15
+ *
16
+ * A factory that returns a promise is normally rejected, because dependency
17
+ * reads made after an `await` are not tracked.
18
+ * Wrap the result when the promise itself is the value the dependency holds.
19
+ * A value that merely implements `then`, such as a query builder, is an
20
+ * ordinary value and does not need this.
21
+ */
22
+ declare function asValue<T>(value: T): AsValue<T>;
23
+ //#endregion
24
+ //#region src/provide.d.ts
25
+ declare const provisionBrand: unique symbol;
26
+ /**
27
+ * A value or factory prepared for a scope or runtime installation.
28
+ *
29
+ * Create provisions with `provide` or `provideFactory`.
30
+ */
31
+ interface Provision {
32
+ readonly [provisionBrand]: true;
33
+ }
34
+ /** One provision or a list accepted by scopes, installations, and overrides. */
35
+ type ProvisionInput = Provision | readonly Provision[];
36
+ /** Ownership options for an existing value supplied with `provide`. */
37
+ interface ProvideOptions<T> {
38
+ /**
39
+ * Cleanup called when the receiving scope or installation closes.
40
+ *
41
+ * Pass `true` to use the dependency's cleanup callback, or pass a different
42
+ * callback explicitly.
43
+ * Either form transfers ownership of the value to Ripple DI.
44
+ */
45
+ readonly dispose?: Disposer<T> | true;
46
+ }
47
+ /**
48
+ * Uses an existing value for a dependency in a scope or installation.
49
+ *
50
+ * Ripple DI cleans up the value only when `options.dispose` is provided.
51
+ * Pass `true` to reuse cleanup configured by `defineDependency`, or pass a
52
+ * callback to override it.
53
+ * A function passed as the value remains a value rather than becoming a factory.
54
+ * A provision that transfers ownership can be used in only one scope or
55
+ * installation.
56
+ */
57
+ declare function provide<T>(dependency: Dependency<T>, value: NoInfer<T>, options?: ProvideOptions<NoInfer<T>>): Provision;
58
+ /**
59
+ * Creates a dependency override on demand in the receiving scope or
60
+ * installation.
61
+ *
62
+ * The factory must be synchronous.
63
+ * Calls to other dependencies inside it are tracked automatically.
64
+ * The receiving scope or installation owns the created value.
65
+ * When the dependency has a configured `dispose` callback, that callback
66
+ * cleans up the override when its owner closes.
67
+ */
68
+ declare function provideFactory<T>(dependency: Dependency<T>, factory: () => FactoryResult<NoInfer<T>>): Provision;
69
+ //#endregion
70
+ //#region src/scope.d.ts
71
+ /** Current lifecycle phase of a scope. */
72
+ type ScopeState = "active" | "retiring" | "closing" | "closed";
73
+ /**
74
+ * An isolated view of dependency values that inherits from a parent scope.
75
+ *
76
+ * A scope can replace selected dependencies without changing its parent.
77
+ * Scope management and lifecycle methods cannot be called from a dependency
78
+ * factory or disposer in the same runtime.
79
+ */
80
+ interface Scope {
81
+ /** Returns a dependency value explicitly from this scope. */
82
+ resolve<T>(dependency: Dependency<T>): T;
83
+ /** Creates a child scope with optional dependency overrides. */
84
+ createScope(provisions?: ProvisionInput): Scope;
85
+ /** Makes this scope current while the callback runs without closing it. */
86
+ run<TCallbackResult>(callback: () => TCallbackResult): TCallbackResult;
87
+ /** Runs a callback in a temporary child scope and cleans it up afterward. */
88
+ withOverrides<TCallbackResult>(provisions: ProvisionInput, callback: (scope: Scope) => TCallbackResult): Promise<Awaited<TCallbackResult>>;
89
+ /** Waits for existing child scopes before cleaning up this scope. */
90
+ retire(): Promise<void>;
91
+ /** Closes all child scopes and then cleans up this scope. */
92
+ close(): Promise<void>;
93
+ }
94
+ //#endregion
95
+ //#region src/overrides.d.ts
96
+ /** Builds the provisions used by one call. */
97
+ type ProvisionFactory = () => ProvisionInput;
98
+ /**
99
+ * A prepared set of overrides applied separately to each call.
100
+ *
101
+ * Use it when a long-lived object runs every operation in its own short-lived
102
+ * scope with the same providers.
103
+ */
104
+ interface OverrideRunner {
105
+ /**
106
+ * Runs a callback with this runner's overrides.
107
+ *
108
+ * Every call gets its own scope, so concurrent calls stay isolated, and the
109
+ * scope is cleaned up when the callback finishes.
110
+ */
111
+ run<TCallbackResult>(callback: (scope: Scope) => TCallbackResult): Promise<Awaited<TCallbackResult>>;
112
+ /**
113
+ * Returns a function that runs the given one with these overrides.
114
+ *
115
+ * Every call of the returned function is one `run` call that forwards the
116
+ * arguments and the receiver it was called with, so nothing exists before
117
+ * the returned function is called.
118
+ */
119
+ wrap<TThis, TArgs extends unknown[], TCallbackResult>(callback: (this: TThis, ...args: TArgs) => TCallbackResult): (this: TThis, ...args: TArgs) => Promise<Awaited<TCallbackResult>>;
120
+ /**
121
+ * Returns a runner that adds more overrides on top of these ones.
122
+ *
123
+ * The added overrides replace the ones they share a dependency with, and
124
+ * this runner keeps working on its own.
125
+ */
126
+ extend(factory: ProvisionFactory): OverrideRunner;
127
+ }
128
+ /**
129
+ * Replaces one dependency with a value for the duration of a callback.
130
+ *
131
+ * Create it with `createValueOverride` for a dependency that application code
132
+ * replaces the same way again and again.
133
+ */
134
+ type ValueOverride<T> = <TCallbackResult>(value: T, callback: (scope: Scope) => TCallbackResult) => Promise<Awaited<TCallbackResult>>;
135
+ //#endregion
136
+ //#region src/runtime.d.ts
137
+ /** Options for starting an independent dependency graph. */
138
+ interface RuntimeOptions {
139
+ /** Human-readable name used in scope names and error messages. */
140
+ readonly name?: string;
141
+ }
142
+ /**
143
+ * Long-lived providers used as the default application wiring for a runtime.
144
+ *
145
+ * Close the installation to remove its providers and clean up the scopes and
146
+ * owned values created beneath it.
147
+ */
148
+ interface Installation {
149
+ /** Removes these providers and closes everything owned beneath them. */
150
+ close(): Promise<void>;
151
+ }
152
+ /**
153
+ * An independent dependency graph with its own definitions, cached values,
154
+ * and lifecycle.
155
+ *
156
+ * Most applications can use the module-level functions and do not need to
157
+ * create a runtime explicitly.
158
+ * Installation and scope management methods cannot be called from one of this
159
+ * runtime's dependency factories or disposers.
160
+ */
161
+ interface Runtime {
162
+ /**
163
+ * Defines a dependency with no built-in value.
164
+ *
165
+ * Supply it through an installation or scope before reading it.
166
+ * A configured disposer applies only to values Ripple DI owns.
167
+ */
168
+ defineDependency<T>(options?: DependencyOptions<T>): Dependency<T>;
169
+ /**
170
+ * Defines a dependency with a lazy built-in factory.
171
+ *
172
+ * The result is cached. A scope gets a separate result when it overrides a
173
+ * dependency that the factory called.
174
+ */
175
+ defineDependency<T>(factory: () => FactoryResult<T>, options?: DependencyOptions<T>): Dependency<T>;
176
+ /**
177
+ * Installs long-lived providers as the fallback beneath scoped overrides.
178
+ *
179
+ * A runtime can have one active installation, and previously created scopes
180
+ * must be fully closed before this method is called.
181
+ */
182
+ install(provisions: ProvisionInput): Installation;
183
+ /** Returns a dependency value from the current scope. */
184
+ resolve<T>(dependency: Dependency<T>): T;
185
+ /** Creates a manually managed child of the current scope. */
186
+ createScope(provisions?: ProvisionInput): Scope;
187
+ /**
188
+ * Runs a callback with temporary overrides and cleans up everything created
189
+ * for the callback afterward.
190
+ */
191
+ withOverrides<TCallbackResult>(provisions: ProvisionInput, callback: (scope: Scope) => TCallbackResult): Promise<Awaited<TCallbackResult>>;
192
+ /**
193
+ * Prepares overrides that are applied again to each call of the returned
194
+ * runner.
195
+ */
196
+ createOverrideRunner(factory: ProvisionFactory): OverrideRunner;
197
+ /**
198
+ * Prepares a reusable helper that replaces one dependency with a value for
199
+ * one callback.
200
+ */
201
+ createValueOverride<T>(dependency: Dependency<T>, options?: ProvideOptions<NoInfer<T>>): ValueOverride<T>;
202
+ /** Closes every scope and cleans up every value owned by this runtime. */
203
+ dispose(): Promise<void>;
204
+ }
205
+ /**
206
+ * Creates an independent dependency graph.
207
+ *
208
+ * Define its dependencies through the methods on the returned runtime.
209
+ */
210
+ declare function createRuntime(options?: RuntimeOptions): Runtime;
211
+ /**
212
+ * Defines a dependency with no built-in value.
213
+ *
214
+ * Supply it through an installation or scope before reading it.
215
+ * A configured disposer applies only to values Ripple DI owns.
216
+ */
217
+ declare function defineDependency<T>(options?: DependencyOptions<T>): Dependency<T>;
218
+ /**
219
+ * Defines a dependency with a lazy built-in factory.
220
+ *
221
+ * The result is cached. A scope gets a separate result when it overrides a
222
+ * dependency that the factory called.
223
+ */
224
+ declare function defineDependency<T>(factory: () => FactoryResult<T>, options?: DependencyOptions<T>): Dependency<T>;
225
+ /**
226
+ * Installs long-lived providers for module-level dependencies.
227
+ *
228
+ * Scoped overrides still take priority. Close the returned installation to
229
+ * remove its providers and clean up everything created from them.
230
+ */
231
+ declare function install(provisions: ProvisionInput): Installation;
232
+ /** Returns a dependency value from the current scope. */
233
+ declare function resolve<T>(dependency: Dependency<T>): T;
234
+ /** Creates a manually managed scope with optional dependency overrides. */
235
+ declare function createScope(provisions?: ProvisionInput): Scope;
236
+ /**
237
+ * Runs a callback with temporary dependency overrides.
238
+ *
239
+ * Overrides remain active across `await`, stay isolated from concurrent
240
+ * callbacks, and are cleaned up when the callback finishes.
241
+ */
242
+ declare function withOverrides<TCallbackResult>(provisions: ProvisionInput, callback: (scope: Scope) => TCallbackResult): Promise<Awaited<TCallbackResult>>;
243
+ /**
244
+ * Prepares dependency overrides that are applied again to each call of the
245
+ * returned runner.
246
+ *
247
+ * The factory runs again for every call, so a call can own the values it
248
+ * provides.
249
+ */
250
+ declare function createOverrideRunner(factory: ProvisionFactory): OverrideRunner;
251
+ /**
252
+ * Prepares a helper that replaces one dependency with a value for one callback.
253
+ *
254
+ * Use it for a dependency that application code supplies the same way in many
255
+ * places, such as a client or a request context.
256
+ * Ownership options given here apply to every value the helper receives.
257
+ */
258
+ declare function createValueOverride<T>(dependency: Dependency<T>, options?: ProvideOptions<NoInfer<T>>): ValueOverride<T>;
259
+ /** Closes every scope and cleans up every owned value. */
260
+ declare function dispose(): Promise<void>;
261
+ //#endregion
262
+ //#region src/dependency.d.ts
263
+ declare const dependencyBrand: unique symbol;
264
+ /**
265
+ * A function that returns the dependency value for the current scope.
266
+ *
267
+ * Pass the same function to `provide` to replace its value or to
268
+ * `scope.resolve` when you need to read from a specific scope.
269
+ */
270
+ type Dependency<T> = (() => T) & {
271
+ readonly [dependencyBrand]: (value: T) => T;
272
+ };
273
+ /** Cleans up a value when Ripple DI no longer needs it. */
274
+ type Disposer<T> = (value: T) => void | Promise<void>;
275
+ /** Optional diagnostics and cleanup for a dependency. */
276
+ interface DependencyOptions<T> {
277
+ /** Optional name used only in error messages and resolution paths. */
278
+ readonly name?: string;
279
+ /**
280
+ * Cleans up values owned by Ripple DI.
281
+ *
282
+ * This applies to the built-in factory, `provideFactory`, and values passed
283
+ * through `provide` with `dispose: true`.
284
+ * Plain values passed through `provide` remain borrowed.
285
+ */
286
+ readonly dispose?: Disposer<T>;
287
+ }
288
+ //#endregion
289
+ //#region src/errors.d.ts
290
+ /** Base class for errors thrown by Ripple DI. */
291
+ declare class RippleError extends Error {}
292
+ /** The dependency was requested without a provider or built-in factory. */
293
+ declare class MissingProviderError extends RippleError {
294
+ readonly dependencyName: string;
295
+ readonly path: readonly string[];
296
+ constructor(dependencyName: string, path: readonly string[]);
297
+ }
298
+ /** A dependency was used with a different runtime than the one that defined it. */
299
+ declare class CrossRuntimeDependencyError extends RippleError {
300
+ readonly dependencyName: string;
301
+ readonly dependencyRuntimeName: string;
302
+ readonly requestedRuntimeName: string;
303
+ constructor(dependencyName: string, dependencyRuntimeName: string, requestedRuntimeName: string);
304
+ }
305
+ /** `install()` was called while another installation or scope was unfinished. */
306
+ declare class InstallationConflictError extends RippleError {
307
+ readonly runtimeName: string;
308
+ readonly reason: "active-installation" | "closing-installation" | "live-scopes";
309
+ readonly scopeNames: readonly string[];
310
+ constructor(runtimeName: string, reason: "active-installation" | "closing-installation" | "live-scopes", scopeNames?: readonly string[]);
311
+ }
312
+ /** The same dependency appears more than once in one provision list. */
313
+ declare class DuplicateProviderError extends RippleError {
314
+ readonly dependencyName: string;
315
+ constructor(dependencyName: string);
316
+ }
317
+ /** One owned-value provision was installed for more than one owner. */
318
+ declare class OwnedProvisionReuseError extends RippleError {
319
+ readonly dependencyName: string;
320
+ constructor(dependencyName: string);
321
+ }
322
+ /** Dependency factories called one another in a cycle. */
323
+ declare class DependencyCycleError extends RippleError {
324
+ readonly path: readonly string[];
325
+ constructor(path: readonly string[]);
326
+ }
327
+ /** A dependency factory returned a `Promise` instead of the value. */
328
+ declare class AsyncFactoryError extends RippleError {
329
+ readonly dependencyName: string;
330
+ readonly path: readonly string[];
331
+ constructor(dependencyName: string, path: readonly string[]);
332
+ }
333
+ /** A dependency factory threw an error available through this error's `cause`. */
334
+ declare class FactoryError extends RippleError {
335
+ readonly dependencyName: string;
336
+ readonly path: readonly string[];
337
+ constructor(dependencyName: string, path: readonly string[], cause: unknown);
338
+ }
339
+ /** An operation tried to use a scope that is retiring, closing, or closed. */
340
+ declare class ScopeClosedError extends RippleError {
341
+ readonly targetName: string;
342
+ readonly scopeName: string;
343
+ readonly scopeId: number;
344
+ readonly state: ScopeState;
345
+ constructor(targetName: string, scopeName: string, scopeId: number, state: ScopeState);
346
+ }
347
+ /** A factory tried to read explicitly from a different scope. */
348
+ declare class CrossScopeResolutionError extends RippleError {
349
+ readonly dependencyName: string;
350
+ readonly factoryScopeName: string;
351
+ readonly requestedScopeName: string;
352
+ constructor(dependencyName: string, factoryScopeName: string, requestedScopeName: string);
353
+ }
354
+ /** A dependency factory tried to manage runtime context or lifecycle. */
355
+ declare class FactoryScopeOperationError extends RippleError {
356
+ readonly dependencyName: string;
357
+ readonly operation: string;
358
+ constructor(dependencyName: string, operation: string);
359
+ }
360
+ /** Code running in or started by a disposer used the runtime being closed. */
361
+ declare class DisposerContextError extends RippleError {
362
+ readonly targetName: string;
363
+ readonly scopeName: string;
364
+ readonly scopeId: number;
365
+ constructor(targetName: string, scopeName: string, scopeId: number);
366
+ }
367
+ /**
368
+ * A `withOverrides` callback created child scopes and returned without closing
369
+ * them.
370
+ *
371
+ * Ripple DI force-closes the leaked scopes before throwing this error.
372
+ */
373
+ declare class LeakedChildScopeError extends RippleError {
374
+ readonly scopeName: string;
375
+ readonly leakedChildCount: number;
376
+ constructor(scopeName: string, leakedChildCount: number);
377
+ }
378
+ //#endregion
379
+ export { type AsValue, AsyncFactoryError, CrossRuntimeDependencyError, CrossScopeResolutionError, type Dependency, DependencyCycleError, type DependencyOptions, type Disposer, DisposerContextError, DuplicateProviderError, FactoryError, type FactoryResult, FactoryScopeOperationError, Installation, InstallationConflictError, LeakedChildScopeError, MissingProviderError, type OverrideRunner, OwnedProvisionReuseError, type ProvideOptions, type Provision, type ProvisionFactory, type ProvisionInput, RippleError, Runtime, RuntimeOptions, type Scope, ScopeClosedError, type ScopeState, type ValueOverride, asValue, createOverrideRunner, createRuntime, createScope, createValueOverride, defineDependency, dispose, install, provide, provideFactory, resolve, withOverrides };