better-effect 0.10.0 → 0.12.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.
Files changed (74) hide show
  1. package/README.md +464 -11
  2. package/dist/adapters/iti.d.mts +4 -4
  3. package/dist/adapters/iti.d.mts.map +1 -1
  4. package/dist/adapters/iti.mjs +20 -14
  5. package/dist/adapters/iti.mjs.map +1 -1
  6. package/dist/effect-CK4YZaX0.mjs +559 -0
  7. package/dist/effect-CK4YZaX0.mjs.map +1 -0
  8. package/dist/hono.d.mts +18 -13
  9. package/dist/hono.d.mts.map +1 -1
  10. package/dist/hono.mjs +9 -5
  11. package/dist/hono.mjs.map +1 -1
  12. package/dist/{index-DklNCz7w.d.mts → index-B1nH4luq.d.mts} +74 -7
  13. package/dist/index-B1nH4luq.d.mts.map +1 -0
  14. package/dist/index-BMdU_Z72.d.mts +18 -0
  15. package/dist/index-BMdU_Z72.d.mts.map +1 -0
  16. package/dist/{index-BafDna0B.d.mts → index-CX6iAoCB.d.mts} +168 -174
  17. package/dist/index-CX6iAoCB.d.mts.map +1 -0
  18. package/dist/index-GYJ4qm9K.d.mts +179 -0
  19. package/dist/index-GYJ4qm9K.d.mts.map +1 -0
  20. package/dist/{index-CULgSzUw.d.mts → index-heuaRmXR.d.mts} +5 -5
  21. package/dist/{index-CULgSzUw.d.mts.map → index-heuaRmXR.d.mts.map} +1 -1
  22. package/dist/index.d.mts +6 -5
  23. package/dist/index.mjs +9 -539
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/{internal-identity-DmUpBeeL.mjs → internal-identity-CbXoZIfw.mjs} +3 -3
  26. package/dist/internal-identity-CbXoZIfw.mjs.map +1 -0
  27. package/dist/{signal-C1bagvrO.mjs → layer-D56fRdLt.mjs} +62 -64
  28. package/dist/layer-D56fRdLt.mjs.map +1 -0
  29. package/dist/node-context-DWsCUBRa.d.mts +12 -0
  30. package/dist/node-context-DWsCUBRa.d.mts.map +1 -0
  31. package/dist/node-context-lggRF4bR.mjs +25 -0
  32. package/dist/node-context-lggRF4bR.mjs.map +1 -0
  33. package/dist/node.d.mts +51 -0
  34. package/dist/node.d.mts.map +1 -0
  35. package/dist/node.mjs +233 -0
  36. package/dist/node.mjs.map +1 -0
  37. package/dist/{index-C7KX5rAP.d.mts → outcome-CB43bnFW.d.mts} +140 -27
  38. package/dist/outcome-CB43bnFW.d.mts.map +1 -0
  39. package/dist/program-metadata-DhQCCirO.mjs +260 -0
  40. package/dist/program-metadata-DhQCCirO.mjs.map +1 -0
  41. package/dist/registration-drnZk0SY.mjs +182 -0
  42. package/dist/registration-drnZk0SY.mjs.map +1 -0
  43. package/dist/runtime/explicit.d.mts +1 -1
  44. package/dist/runtime/node.d.mts +3 -12
  45. package/dist/runtime/node.mjs +2 -24
  46. package/dist/runtime-CBMrX8Wl.mjs +776 -0
  47. package/dist/runtime-CBMrX8Wl.mjs.map +1 -0
  48. package/dist/signal-D2UTcaaG.mjs +105 -0
  49. package/dist/signal-D2UTcaaG.mjs.map +1 -0
  50. package/dist/{standard-services-DW-i4UuA.mjs → standard-services-GBZ32tll.mjs} +200 -16
  51. package/dist/standard-services-GBZ32tll.mjs.map +1 -0
  52. package/dist/standard-services.d.mts +3 -3
  53. package/dist/standard-services.mjs +3 -3
  54. package/dist/testing.d.mts +257 -2
  55. package/dist/testing.d.mts.map +1 -0
  56. package/dist/testing.mjs +1159 -2
  57. package/dist/testing.mjs.map +1 -0
  58. package/package.json +8 -3
  59. package/dist/effect-DAMqvegy.mjs +0 -544
  60. package/dist/effect-DAMqvegy.mjs.map +0 -1
  61. package/dist/errors-Dnjhzbt0.mjs +0 -99
  62. package/dist/errors-Dnjhzbt0.mjs.map +0 -1
  63. package/dist/index-BafDna0B.d.mts.map +0 -1
  64. package/dist/index-C7KX5rAP.d.mts.map +0 -1
  65. package/dist/index-DklNCz7w.d.mts.map +0 -1
  66. package/dist/internal-identity-DmUpBeeL.mjs.map +0 -1
  67. package/dist/map-layer-backend-gal-mcRv.mjs +0 -53
  68. package/dist/map-layer-backend-gal-mcRv.mjs.map +0 -1
  69. package/dist/map-layer-backend-rNwfH0Bz.d.mts +0 -42
  70. package/dist/map-layer-backend-rNwfH0Bz.d.mts.map +0 -1
  71. package/dist/runtime/node.d.mts.map +0 -1
  72. package/dist/runtime/node.mjs.map +0 -1
  73. package/dist/signal-C1bagvrO.mjs.map +0 -1
  74. package/dist/standard-services-DW-i4UuA.mjs.map +0 -1
package/dist/node.mjs ADDED
@@ -0,0 +1,233 @@
1
+ import { h as RuntimeContextNotConfiguredError } from "./context-BUEf1qjL.mjs";
2
+ import { n as nodeRuntimeContextStorage, t as NodeRuntimeContextStorage } from "./node-context-lggRF4bR.mjs";
3
+ import { n as linkAbortSignals } from "./signal-D2UTcaaG.mjs";
4
+ import { t as Runtime } from "./runtime-CBMrX8Wl.mjs";
5
+ import { Err, Ok } from "better-result";
6
+ //#region src/runtime/node-runtime.ts
7
+ const DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
8
+ const isLayerBackend = (value) => {
9
+ if (value === null || typeof value !== "object") return false;
10
+ return "register" in value && "resolve" in value && "disposeAll" in value && typeof value.register === "function" && typeof value.resolve === "function" && typeof value.disposeAll === "function";
11
+ };
12
+ const isAbortSignal = (value) => {
13
+ if (value === null || typeof value !== "object") return false;
14
+ return typeof value.aborted === "boolean" && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function";
15
+ };
16
+ const isOptionsObject = (value) => {
17
+ return value !== null && typeof value === "object" && !Array.isArray(value);
18
+ };
19
+ const validateExitCode = (code) => {
20
+ if (!Number.isSafeInteger(code) || code < 0) throw new RangeError("NodeRuntime exit codes must be non-negative safe integers");
21
+ return code;
22
+ };
23
+ const ensureFailureExitCode = (code) => code === 0 ? 1 : code;
24
+ const validateSignals = (signals) => {
25
+ if (signals !== void 0 && !Array.isArray(signals)) throw new TypeError("NodeRuntime signals must be an array of supported signal names");
26
+ for (const signal of signals ?? DEFAULT_SIGNALS) if (typeof signal !== "string" || signal !== "SIGINT" && signal !== "SIGTERM") throw new RangeError(`NodeRuntime signal "${String(signal)}" is not supported`);
27
+ };
28
+ const validateRuntimeOptions = (options) => {
29
+ if (options.signal !== void 0 && !isAbortSignal(options.signal)) throw new TypeError("NodeRuntime signal must be an AbortSignal");
30
+ };
31
+ const validateCallbacks = (options) => {
32
+ if (options.onSuccess !== void 0 && typeof options.onSuccess !== "function") throw new TypeError("NodeRuntime onSuccess must be a function");
33
+ if (options.onFailure !== void 0 && typeof options.onFailure !== "function") throw new TypeError("NodeRuntime onFailure must be a function");
34
+ if (options.onDefect !== void 0 && typeof options.onDefect !== "function") throw new TypeError("NodeRuntime onDefect must be a function");
35
+ if (options.onCleanupFailure !== void 0 && typeof options.onCleanupFailure !== "function") throw new TypeError("NodeRuntime onCleanupFailure must be a function");
36
+ };
37
+ const validateOptions = (options) => {
38
+ validateSignals(options.signals);
39
+ validateRuntimeOptions(options);
40
+ validateCallbacks(options);
41
+ if (options.observers !== void 0 && !Array.isArray(options.observers)) throw new TypeError("NodeRuntime observers must be an array");
42
+ };
43
+ const normalizeSignals = (signals) => {
44
+ const unique = /* @__PURE__ */ new Set();
45
+ for (const signal of signals ?? DEFAULT_SIGNALS) unique.add(signal);
46
+ return [...unique];
47
+ };
48
+ const removeSignalListeners = (listeners) => {
49
+ const failures = [];
50
+ for (const { signal, listener } of listeners) try {
51
+ process.removeListener(signal, listener);
52
+ } catch (cause) {
53
+ failures.push(cause);
54
+ }
55
+ listeners.length = 0;
56
+ return failures;
57
+ };
58
+ const combineFailures = (failures) => {
59
+ if (failures.length === 0) return [];
60
+ if (failures.length === 1) return [failures[0]];
61
+ return [new AggregateError(failures, "NodeRuntime cleanup failed")];
62
+ };
63
+ const setExitCode = (code) => {
64
+ process.exitCode = validateExitCode(code);
65
+ };
66
+ const reportDefect = (cause, handler) => {
67
+ let exitCode = 1;
68
+ if (handler) try {
69
+ const requestedExitCode = handler(cause);
70
+ if (requestedExitCode !== void 0) exitCode = validateExitCode(requestedExitCode);
71
+ } catch {
72
+ exitCode = 1;
73
+ }
74
+ setExitCode(ensureFailureExitCode(exitCode));
75
+ };
76
+ const installSignalListeners = (signals, listeners, onSignal) => {
77
+ for (const signal of signals) {
78
+ const listener = () => onSignal(signal);
79
+ process.on(signal, listener);
80
+ listeners.push({
81
+ signal,
82
+ listener
83
+ });
84
+ }
85
+ };
86
+ /** Node.js/Bun process lifecycle helpers. */
87
+ var NodeRuntime = class {
88
+ static async runMain(layer, backendOrProgramOrOptions, programOrOptions, legacyOptions) {
89
+ let backend;
90
+ let program;
91
+ let options;
92
+ if (typeof backendOrProgramOrOptions === "function") {
93
+ program = backendOrProgramOrOptions;
94
+ options = programOrOptions;
95
+ } else if (isLayerBackend(backendOrProgramOrOptions)) {
96
+ backend = backendOrProgramOrOptions;
97
+ program = programOrOptions;
98
+ options = legacyOptions;
99
+ } else {
100
+ options = backendOrProgramOrOptions;
101
+ program = programOrOptions;
102
+ }
103
+ if (options !== void 0 && !isOptionsObject(options)) throw new TypeError("NodeRuntime options must be a non-array object");
104
+ const normalizedOptions = options ?? {};
105
+ validateOptions(normalizedOptions);
106
+ const shutdownController = new AbortController();
107
+ const configuredSignals = normalizeSignals(normalizedOptions.signals);
108
+ const { onSuccess, onFailure, onDefect, signal: callerSignal, ...runtimeOptions } = normalizedOptions;
109
+ const signalLink = linkAbortSignals(callerSignal, shutdownController.signal);
110
+ const listeners = [];
111
+ const cleanupFailures = [];
112
+ let runtime;
113
+ let disposalPromise;
114
+ let disposalObserved = false;
115
+ let firstSignal;
116
+ let setupFailed = false;
117
+ let setupFailure;
118
+ let programFailed = false;
119
+ let programFailure;
120
+ let executionCleanupFailed = false;
121
+ let executionOutcome;
122
+ let programSettled = false;
123
+ let programValue;
124
+ const requestDispose = () => {
125
+ if (disposalPromise) return disposalPromise;
126
+ try {
127
+ disposalPromise = runtime.dispose();
128
+ } catch (cause) {
129
+ disposalPromise = Promise.reject(cause);
130
+ }
131
+ return disposalPromise;
132
+ };
133
+ const observeDisposal = async () => {
134
+ if (!runtime || disposalObserved) return;
135
+ disposalObserved = true;
136
+ try {
137
+ await requestDispose();
138
+ } catch (cause) {
139
+ cleanupFailures.push(cause);
140
+ }
141
+ };
142
+ const onSignal = (signal) => {
143
+ if (firstSignal !== void 0) return;
144
+ firstSignal = signal;
145
+ try {
146
+ shutdownController.abort(signal);
147
+ } finally {
148
+ requestDispose().catch(() => {});
149
+ }
150
+ };
151
+ try {
152
+ const executionObserver = { onExecutionEnd: ({ outcome }) => {
153
+ executionOutcome = outcome;
154
+ } };
155
+ const runtimeOptionsWithSignal = {
156
+ ...runtimeOptions,
157
+ observers: [executionObserver, ...runtimeOptions.observers ?? []],
158
+ signal: signalLink.signal
159
+ };
160
+ runtime = backend ? await Runtime.make(layer, backend, runtimeOptionsWithSignal) : await Runtime.make(layer, runtimeOptionsWithSignal);
161
+ installSignalListeners(configuredSignals, listeners, onSignal);
162
+ try {
163
+ programValue = await runtime.run(program);
164
+ programSettled = true;
165
+ } catch (cause) {
166
+ if (executionOutcome?.status === "success") executionCleanupFailed = true;
167
+ else programFailed = true;
168
+ programFailure = cause;
169
+ }
170
+ await observeDisposal();
171
+ } catch (cause) {
172
+ setupFailed = true;
173
+ setupFailure = cause;
174
+ } finally {
175
+ await observeDisposal();
176
+ cleanupFailures.push(...removeSignalListeners(listeners));
177
+ try {
178
+ signalLink.dispose();
179
+ } catch (cause) {
180
+ cleanupFailures.push(cause);
181
+ }
182
+ }
183
+ const cleanupFailureValues = combineFailures(cleanupFailures);
184
+ const hasCleanupFailure = cleanupFailureValues.length > 0;
185
+ const cleanupFailure = cleanupFailureValues[0];
186
+ if (setupFailed) {
187
+ reportDefect(setupFailure, onDefect);
188
+ throw setupFailure;
189
+ }
190
+ if (programFailed) {
191
+ reportDefect(programFailure, onDefect);
192
+ throw programFailure;
193
+ }
194
+ if (executionCleanupFailed) {
195
+ setExitCode(1);
196
+ throw programFailure;
197
+ }
198
+ if (!programSettled) {
199
+ const failure = /* @__PURE__ */ new Error("NodeRuntime main program did not settle");
200
+ reportDefect(failure, onDefect);
201
+ throw failure;
202
+ }
203
+ if (programValue instanceof Err) {
204
+ let exitCode = 1;
205
+ try {
206
+ if (onFailure) exitCode = validateExitCode(onFailure(programValue.error));
207
+ } catch (cause) {
208
+ reportDefect(cause, onDefect);
209
+ throw cause;
210
+ }
211
+ setExitCode(exitCode);
212
+ return programValue;
213
+ }
214
+ let exitCode = 0;
215
+ try {
216
+ if (onSuccess) {
217
+ const successValue = programValue instanceof Ok ? programValue.value : programValue;
218
+ exitCode = validateExitCode(onSuccess(successValue));
219
+ }
220
+ } catch (cause) {
221
+ reportDefect(cause, onDefect);
222
+ throw cause;
223
+ }
224
+ if (hasCleanupFailure) exitCode = ensureFailureExitCode(exitCode);
225
+ setExitCode(exitCode);
226
+ if (hasCleanupFailure) throw cleanupFailure;
227
+ return programValue;
228
+ }
229
+ };
230
+ //#endregion
231
+ export { NodeRuntime, NodeRuntimeContextStorage, RuntimeContextNotConfiguredError, nodeRuntimeContextStorage };
232
+
233
+ //# sourceMappingURL=node.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.mjs","names":[],"sources":["../src/runtime/node-runtime.ts"],"sourcesContent":["import { Err, Ok } from 'better-result'\n\nimport type { Result as ResultType } from 'better-result'\n\nimport type { EffectError, EffectSuccess } from '../effect'\nimport type { LayerBackend } from '../layer/backend'\nimport type {\n CompleteExecution,\n CompleteInput,\n LayerInput,\n ProvidedEnvironment\n} from '../layer/inference'\nimport { Runtime } from './runtime'\nimport { linkAbortSignals } from './signal'\n\nimport type { RuntimeOptions } from './outcome'\nimport type { RuntimeExecutionEndEvent, RuntimeObserver } from './observer'\nimport type { ScopeOutcome } from '../scope'\n\n/** Process signals supported by the Node.js/Bun process boundary. */\nexport type NodeRuntimeSignal = 'SIGINT' | 'SIGTERM'\n\n/** Translate a successful main result to a process exit code. */\nexport type NodeRuntimeSuccessHandler<Success> = (value: Success) => number\n\n/** Translate a typed main failure to a process exit code. */\nexport type NodeRuntimeFailureHandler<Failure> = (error: Failure) => number\n\n/** Observe a thrown or rejected main defect while it remains a rejected Promise. */\nexport type NodeRuntimeDefectHandler = (cause: unknown) => number | void\n\n/** Options for the Node.js/Bun process boundary. */\nexport type NodeRuntimeOptions<Success = unknown, Failure = unknown> = RuntimeOptions & {\n /** Process signals that request cooperative shutdown. Defaults to SIGINT and SIGTERM. */\n readonly signals?: readonly NodeRuntimeSignal[]\n /** Map a nominal Result.ok value, or a plain successful value, to an exit code. */\n readonly onSuccess?: NodeRuntimeSuccessHandler<Success>\n /** Map a nominal Result.err error to an exit code. */\n readonly onFailure?: NodeRuntimeFailureHandler<Failure>\n /** Observe a defect. Defects are rethrown after the handler runs. */\n readonly onDefect?: NodeRuntimeDefectHandler\n}\n\ntype NonResultMainSuccess<Value> = Value extends ResultType<any, any> ? never : Value\n\ntype PlainMainSuccess<Value> = NonResultMainSuccess<Awaited<Value>>\n\ntype MainSuccess<Value> = EffectSuccess<Value> | PlainMainSuccess<Value>\n\ntype MainFailure<Value> = EffectError<Value>\n\ntype MainOptions<Value> = NodeRuntimeOptions<MainSuccess<Value>, MainFailure<Value>>\n\nconst DEFAULT_SIGNALS = ['SIGINT', 'SIGTERM'] as const satisfies readonly NodeRuntimeSignal[]\n\ntype InstalledSignalListener = {\n readonly signal: NodeRuntimeSignal\n readonly listener: () => void\n}\n\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- backend overload dispatch validates an opaque runtime value.\nconst isLayerBackend = (value: unknown): value is LayerBackend => {\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- runtime overload dispatch must inspect the backend shape.\n if (value === null || typeof value !== 'object') {\n return false\n }\n\n return (\n 'register' in value &&\n 'resolve' in value &&\n 'disposeAll' in value &&\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- the backend contract is validated at this runtime boundary.\n typeof value.register === 'function' &&\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- the backend contract is validated at this runtime boundary.\n typeof value.resolve === 'function' &&\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- the backend contract is validated at this runtime boundary.\n typeof value.disposeAll === 'function'\n )\n}\n\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- AbortSignal validation receives an opaque public option.\nconst isAbortSignal = (value: unknown): value is AbortSignal => {\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate the structural host signal contract.\n if (value === null || typeof value !== 'object') {\n return false\n }\n\n return (\n // SAFETY: the preceding guard establishes that the opaque value is an object; these are the required AbortSignal members.\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate the structural host signal contract.\n typeof (value as AbortSignal).aborted === 'boolean' &&\n // SAFETY: the preceding guard establishes that the opaque value is an object; these are the required AbortSignal members.\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate the structural host signal contract.\n typeof (value as AbortSignal).addEventListener === 'function' &&\n // SAFETY: the preceding guard establishes that the opaque value is an object; these are the required AbortSignal members.\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate the structural host signal contract.\n typeof (value as AbortSignal).removeEventListener === 'function'\n )\n}\n\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- options are validated at the public boundary.\nconst isOptionsObject = (value: unknown): value is object => {\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate the public options boundary before installing listeners.\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nconst validateExitCode = (code: number): number => {\n if (!Number.isSafeInteger(code) || code < 0) {\n throw new RangeError('NodeRuntime exit codes must be non-negative safe integers')\n }\n\n return code\n}\n\nconst ensureFailureExitCode = (code: number): number => (code === 0 ? 1 : code)\n\nconst validateSignals = <Success, Failure>(\n signals: NodeRuntimeOptions<Success, Failure>['signals']\n): void => {\n if (signals !== undefined && !Array.isArray(signals)) {\n throw new TypeError('NodeRuntime signals must be an array of supported signal names')\n }\n\n for (const signal of signals ?? DEFAULT_SIGNALS) {\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate untyped options before process.on receives them.\n if (typeof signal !== 'string' || (signal !== 'SIGINT' && signal !== 'SIGTERM')) {\n throw new RangeError(`NodeRuntime signal \"${String(signal)}\" is not supported`)\n }\n }\n}\n\nconst validateRuntimeOptions = <Success, Failure>(\n options: NodeRuntimeOptions<Success, Failure>\n): void => {\n if (options.signal !== undefined && !isAbortSignal(options.signal)) {\n throw new TypeError('NodeRuntime signal must be an AbortSignal')\n }\n}\n\nconst validateCallbacks = <Success, Failure>(\n options: NodeRuntimeOptions<Success, Failure>\n): void => {\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate untyped options before invoking the callback.\n if (options.onSuccess !== undefined && typeof options.onSuccess !== 'function') {\n throw new TypeError('NodeRuntime onSuccess must be a function')\n }\n\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate untyped options before invoking the callback.\n if (options.onFailure !== undefined && typeof options.onFailure !== 'function') {\n throw new TypeError('NodeRuntime onFailure must be a function')\n }\n\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate untyped options before invoking the callback.\n if (options.onDefect !== undefined && typeof options.onDefect !== 'function') {\n throw new TypeError('NodeRuntime onDefect must be a function')\n }\n\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- validate untyped options before Runtime invokes the observer.\n if (options.onCleanupFailure !== undefined && typeof options.onCleanupFailure !== 'function') {\n throw new TypeError('NodeRuntime onCleanupFailure must be a function')\n }\n}\n\nconst validateOptions = <Success, Failure>(options: NodeRuntimeOptions<Success, Failure>): void => {\n validateSignals(options.signals)\n validateRuntimeOptions(options)\n validateCallbacks(options)\n\n if (options.observers !== undefined && !Array.isArray(options.observers)) {\n throw new TypeError('NodeRuntime observers must be an array')\n }\n}\n\nconst normalizeSignals = (\n signals: readonly NodeRuntimeSignal[] | undefined\n): readonly NodeRuntimeSignal[] => {\n const unique = new Set<NodeRuntimeSignal>()\n\n for (const signal of signals ?? DEFAULT_SIGNALS) {\n unique.add(signal)\n }\n\n return [...unique]\n}\n\nconst removeSignalListeners = (listeners: InstalledSignalListener[]): readonly unknown[] => {\n const failures: unknown[] = []\n\n for (const { signal, listener } of listeners) {\n try {\n process.removeListener(signal, listener)\n } catch (cause) {\n failures.push(cause)\n }\n }\n\n listeners.length = 0\n\n return failures\n}\n\nconst combineFailures = (failures: readonly unknown[]): readonly unknown[] => {\n if (failures.length === 0) {\n return []\n }\n\n if (failures.length === 1) {\n return [failures[0]]\n }\n\n return [new AggregateError(failures, 'NodeRuntime cleanup failed')]\n}\n\nconst setExitCode = (code: number): void => {\n process.exitCode = validateExitCode(code)\n}\n\nconst reportDefect = (cause: unknown, handler: NodeRuntimeDefectHandler | undefined): void => {\n let exitCode = 1\n\n if (handler) {\n try {\n const requestedExitCode = handler(cause)\n\n if (requestedExitCode !== undefined) {\n exitCode = validateExitCode(requestedExitCode)\n }\n } catch {\n exitCode = 1\n }\n }\n\n setExitCode(ensureFailureExitCode(exitCode))\n}\n\nconst installSignalListeners = (\n signals: readonly NodeRuntimeSignal[],\n listeners: InstalledSignalListener[],\n onSignal: (signal: NodeRuntimeSignal) => void\n): void => {\n for (const signal of signals) {\n const listener = (): void => onSignal(signal)\n process.on(signal, listener)\n listeners.push({ signal, listener })\n }\n}\n\n/** Node.js/Bun process lifecycle helpers. */\nexport class NodeRuntime {\n /**\n * Run a typed main Program, translate its final result to `process.exitCode`,\n * and dispose the Runtime when the program or a configured process signal settles.\n */\n static runMain<A, L extends LayerInput>(\n layer: L & CompleteInput<L>,\n backend: LayerBackend,\n program: CompleteExecution<ProvidedEnvironment<L>, A>,\n options?: MainOptions<A>\n ): Promise<Awaited<A>>\n\n static runMain<A, L extends LayerInput>(\n layer: L & CompleteInput<L>,\n program: CompleteExecution<ProvidedEnvironment<L>, A>,\n options?: MainOptions<A>\n ): Promise<Awaited<A>>\n\n static runMain<A, L extends LayerInput>(\n layer: L & CompleteInput<L>,\n options: MainOptions<A>,\n program: CompleteExecution<ProvidedEnvironment<L>, A>\n ): Promise<Awaited<A>>\n\n static async runMain<A, L extends LayerInput>(\n layer: L & CompleteInput<L>,\n backendOrProgramOrOptions:\n | LayerBackend\n | MainOptions<A>\n | CompleteExecution<ProvidedEnvironment<L>, A>,\n programOrOptions?: CompleteExecution<ProvidedEnvironment<L>, A> | MainOptions<A>,\n legacyOptions?: MainOptions<A>\n ): Promise<Awaited<A>> {\n let backend: LayerBackend | undefined\n let program!: CompleteExecution<ProvidedEnvironment<L>, A>\n let options: MainOptions<A> | undefined\n\n // oxlint-disable-next-line anti-slop/no-runtime-typeof -- overload dispatch distinguishes the Program callback from configuration.\n if (typeof backendOrProgramOrOptions === 'function') {\n program = backendOrProgramOrOptions\n // SAFETY: this branch is selected by the Program overload, so the optional value is its options object.\n options = programOrOptions as MainOptions<A> | undefined\n } else if (isLayerBackend(backendOrProgramOrOptions)) {\n backend = backendOrProgramOrOptions\n // SAFETY: the backend overload requires a Program in the third argument.\n program = programOrOptions as CompleteExecution<ProvidedEnvironment<L>, A>\n options = legacyOptions\n } else {\n options = backendOrProgramOrOptions\n // SAFETY: the options overload requires a Program in the third argument.\n program = programOrOptions as CompleteExecution<ProvidedEnvironment<L>, A>\n }\n\n if (options !== undefined && !isOptionsObject(options)) {\n throw new TypeError('NodeRuntime options must be a non-array object')\n }\n\n // SAFETY: validation above establishes an object; the empty object is the omitted-options case.\n const normalizedOptions = (options ?? {}) as MainOptions<A>\n validateOptions(normalizedOptions)\n\n const shutdownController = new AbortController()\n const configuredSignals = normalizeSignals(normalizedOptions.signals)\n const {\n onSuccess,\n onFailure,\n onDefect,\n signal: callerSignal,\n ...runtimeOptions\n } = normalizedOptions\n const signalLink = linkAbortSignals(callerSignal, shutdownController.signal)\n const listeners: InstalledSignalListener[] = []\n const cleanupFailures: unknown[] = []\n\n let runtime: Runtime<ProvidedEnvironment<L>> | undefined\n let disposalPromise: Promise<void> | undefined\n let disposalObserved = false\n let firstSignal: NodeRuntimeSignal | undefined\n let setupFailed = false\n let setupFailure: unknown\n let programFailed = false\n let programFailure: unknown\n let executionCleanupFailed = false\n let executionOutcome: ScopeOutcome | undefined\n let programSettled = false\n let programValue!: Awaited<A>\n\n const requestDispose = (): Promise<void> => {\n if (disposalPromise) {\n return disposalPromise\n }\n\n try {\n disposalPromise = runtime!.dispose()\n } catch (cause) {\n disposalPromise = Promise.reject(cause)\n }\n\n return disposalPromise\n }\n\n const observeDisposal = async (): Promise<void> => {\n if (!runtime || disposalObserved) {\n return\n }\n\n disposalObserved = true\n\n try {\n await requestDispose()\n } catch (cause) {\n cleanupFailures.push(cause)\n }\n }\n\n const onSignal = (signal: NodeRuntimeSignal): void => {\n if (firstSignal !== undefined) {\n return\n }\n\n firstSignal = signal\n\n try {\n shutdownController.abort(signal)\n } finally {\n void requestDispose().catch(() => {})\n }\n }\n\n try {\n const executionObserver: RuntimeObserver = {\n onExecutionEnd: ({ outcome }: RuntimeExecutionEndEvent): void => {\n executionOutcome = outcome\n }\n }\n const runtimeOptionsWithSignal: RuntimeOptions = {\n ...runtimeOptions,\n observers: [executionObserver, ...(runtimeOptions.observers ?? [])],\n signal: signalLink.signal\n }\n\n runtime = backend\n ? await Runtime.make(layer, backend, runtimeOptionsWithSignal)\n : await Runtime.make(layer, runtimeOptionsWithSignal)\n\n installSignalListeners(configuredSignals, listeners, onSignal)\n\n try {\n programValue = await runtime.run(program)\n programSettled = true\n } catch (cause) {\n if (executionOutcome?.status === 'success') {\n executionCleanupFailed = true\n } else {\n programFailed = true\n }\n programFailure = cause\n }\n\n await observeDisposal()\n } catch (cause) {\n setupFailed = true\n setupFailure = cause\n } finally {\n await observeDisposal()\n cleanupFailures.push(...removeSignalListeners(listeners))\n\n try {\n signalLink.dispose()\n } catch (cause) {\n cleanupFailures.push(cause)\n }\n }\n\n const cleanupFailureValues = combineFailures(cleanupFailures)\n const hasCleanupFailure = cleanupFailureValues.length > 0\n const cleanupFailure = cleanupFailureValues[0]\n\n if (setupFailed) {\n reportDefect(setupFailure, onDefect)\n throw setupFailure\n }\n\n if (programFailed) {\n reportDefect(programFailure, onDefect)\n throw programFailure\n }\n\n if (executionCleanupFailed) {\n setExitCode(1)\n throw programFailure\n }\n\n if (!programSettled) {\n const failure = new Error('NodeRuntime main program did not settle')\n reportDefect(failure, onDefect)\n throw failure\n }\n\n if (programValue instanceof Err) {\n let exitCode = 1\n\n try {\n if (onFailure) {\n // SAFETY: Err carries the failure channel represented by MainFailure<A>.\n exitCode = validateExitCode(onFailure(programValue.error as MainFailure<A>))\n }\n } catch (cause) {\n reportDefect(cause, onDefect)\n throw cause\n }\n\n setExitCode(exitCode)\n return programValue\n }\n\n let exitCode = 0\n\n try {\n if (onSuccess) {\n const successValue = programValue instanceof Ok ? programValue.value : programValue\n // SAFETY: Ok is unwrapped above; plain successful values retain the MainSuccess<A> channel.\n exitCode = validateExitCode(onSuccess(successValue as MainSuccess<A>))\n }\n } catch (cause) {\n reportDefect(cause, onDefect)\n throw cause\n }\n\n if (hasCleanupFailure) {\n exitCode = ensureFailureExitCode(exitCode)\n }\n\n setExitCode(exitCode)\n\n if (hasCleanupFailure) {\n throw cleanupFailure\n }\n\n return programValue\n }\n}\n\n/** Type-level aliases for the Node.js/Bun process boundary. */\nexport declare namespace NodeRuntime {\n /** Options for `NodeRuntime.runMain`. */\n export type Options<Success = unknown, Failure = unknown> = NodeRuntimeOptions<Success, Failure>\n\n /** A process signal accepted by `NodeRuntime.runMain`. */\n export type Signal = NodeRuntimeSignal\n}\n"],"mappings":"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"}
@@ -1,11 +1,13 @@
1
- import { F as ServiceContract, H as ServiceToken, L as ServiceIdentityTypeId, M as AnyService, N as AnyServiceToken, P as ServiceClass, T as EffectRequirements, U as ServiceTokenOf, V as ServiceTagOf, c as RuntimeContextStorage, d as CleanupFailureDiagnostic, h as ScopeOutcome, j as ServiceRequirement, p as MaybePromise, u as Scope, z as ServiceRequirements } from "./index-CULgSzUw.mjs";
2
- import { a as LayerRegistration, i as LayerGeneratorRequirements, n as LayerBackend, o as MaybePromise$1, r as LayerGenerator } from "./map-layer-backend-rNwfH0Bz.mjs";
1
+ import { F as ServiceContract, H as ServiceToken, L as ServiceIdentityTypeId, M as AnyService, N as AnyServiceToken, O as InferYieldRequirements, P as ServiceClass, T as EffectRequirements, U as ServiceTokenOf, V as ServiceTagOf, a as ServiceResolver, c as RuntimeContextStorage, d as CleanupFailureDiagnostic, f as DisposableResource, h as ScopeOutcome, j as ServiceRequirement, m as ScopeFinalizer, p as MaybePromise$1, u as Scope, z as ServiceRequirements } from "./index-heuaRmXR.mjs";
3
2
  //#region src/internal/variance.d.ts
4
3
  /** Type-level marker for a value produced by `A`. */
5
4
  type Covariant<A> = () => A;
6
5
  /** Type-level marker that both consumes and produces `A`. */
7
6
  type Invariant<A> = (value: A) => A;
8
7
  //#endregion
8
+ //#region src/utils/types.d.ts
9
+ type MaybePromise<T> = T | PromiseLike<T>;
10
+ //#endregion
9
11
  //#region src/internal/missing-dependencies.d.ts
10
12
  type MissingDependencies<Missing extends AnyService> = {
11
13
  /** Names the Services that must be supplied before execution. */
@@ -33,7 +35,7 @@ interface LayerProvenance<out Entries extends ProviderEntry<AnyService, AnyServi
33
35
  //#region src/layer/inference.d.ts
34
36
  type IsAny<T> = 0 extends 1 & T ? true : false;
35
37
  type IsNever<T> = [T] extends [never] ? true : false;
36
- type IsUnion<T, Candidate = T> = T extends unknown ? [Candidate] extends [T] ? false : true : never;
38
+ type IsUnion$1<T, Candidate = T> = T extends unknown ? [Candidate] extends [T] ? false : true : never;
37
39
  /** Any Layer shape accepted by type-level inference helpers. */
38
40
  type LayerInput = Layer<any, any> | Layer<never, any>;
39
41
  /** Extract the public Service environment channels from a Layer. */
@@ -65,21 +67,22 @@ type PreciseEntries<L extends LayerInput> = L extends LayerProvenance<infer Entr
65
67
  * explicitly annotated Layer.
66
68
  */
67
69
  type ErasedEntries<L extends LayerInput> = L extends LayerProvenance<any, infer Erased> ? Erased : [ProvidedEnvironment<L> | RequiredEnvironment<L>] extends [never] ? never : ErasedProvenance<ProvidedEnvironment<L>, RequiredEnvironment<L>>;
70
+ type PossibleProvidedEnvironment<L extends LayerInput> = EntryProvided<PreciseEntries<L>> | ErasedProvided<ErasedEntries<L>>;
68
71
  type LayerMetadata<Entries extends AnyProviderEntry, Erased extends AnyErasedProvenance> = [Entries | Erased] extends [never] ? unknown : LayerProvenance<Entries, Erased>;
69
72
  /** Opaque internal result type used by Layer constructors and combinators. */
70
- type LayerResult<Entries extends AnyProviderEntry, Erased extends AnyErasedProvenance = never> = Layer<EntryProvided<Entries> | ErasedProvided<Erased>, LayerExternalRequirements<EntryRequired<Entries> | ErasedRequired<Erased>, EntryProvided<Entries> | ErasedProvided<Erased>>> & LayerMetadata<Entries, Erased>;
73
+ type LayerResult<Entries extends AnyProviderEntry, Erased extends AnyErasedProvenance = never, VisibleProvided extends AnyService = EntryProvided<Entries> | ErasedProvided<Erased>> = Layer<VisibleProvided, LayerExternalRequirements<EntryRequired<Entries> | ErasedRequired<Erased>, VisibleProvided>> & LayerMetadata<Entries, Erased>;
71
74
  type LayerChannelPair<L> = L extends Layer<infer Provided, infer Required> ? [Provided, Required] : never;
72
75
  type ExactUncheckedArm<L> = LayerChannelPair<L> extends [infer Provided extends AnyService, infer Required extends AnyService] ? IsAny<Provided> extends true ? IsAny<Required> extends true ? true : false : IsNever<Provided> extends true ? IsAny<Required> extends true ? true : false : false : false;
73
76
  type HasUncheckedProvidedArm<L> = L extends unknown ? LayerChannelPair<L> extends [infer Provided, infer Required] ? IsAny<Provided> extends true ? IsAny<Required> extends true ? true : false : false : false : never;
74
77
  type HasUncheckedEmptyArm<L> = L extends unknown ? LayerChannelPair<L> extends [infer Provided, infer Required] ? IsNever<Provided> extends true ? IsAny<Required> extends true ? true : false : false : false : never;
75
78
  type HasNonUncheckedArm<L> = L extends unknown ? ExactUncheckedArm<L> extends true ? false : true : never;
76
79
  /** Recognize only the documented exact unchecked Layer sentinels. */
77
- type IsExactUncheckedLayer<L> = IsUnion<L> extends false ? ExactUncheckedArm<L> : true extends HasNonUncheckedArm<L> ? false : true extends HasUncheckedProvidedArm<L> ? true extends HasUncheckedEmptyArm<L> ? true : false : false;
80
+ type IsExactUncheckedLayer<L> = IsUnion$1<L> extends false ? ExactUncheckedArm<L> : true extends HasNonUncheckedArm<L> ? false : true extends HasUncheckedProvidedArm<L> ? true extends HasUncheckedEmptyArm<L> ? true : false : false;
78
81
  type PartialAnyArm<L> = LayerChannelPair<L> extends [infer Provided extends AnyService, infer Required extends AnyService] ? IsAny<Provided> extends true ? IsAny<Required> extends true ? false : true : IsAny<Required> extends true ? IsNever<Provided> extends true ? false : true : false : false;
79
82
  /** Detect any Layer constituent with only one erased generic channel. */
80
83
  type HasPartialAnyChannel<L> = true extends (L extends unknown ? PartialAnyArm<L> : never) ? true : false;
81
84
  /** Detect a concrete union of Layer values, preserving the original shape. */
82
- type IsConcreteUnion<L> = IsAny<L> extends true ? false : IsUnion<L> extends true ? IsExactUncheckedLayer<L> extends true ? false : true : false;
85
+ type IsConcreteUnion<L> = IsAny<L> extends true ? false : IsUnion$1<L> extends true ? IsExactUncheckedLayer<L> extends true ? false : true : false;
83
86
  type LayerInputState<L> = IsExactUncheckedLayer<L> extends true ? 'unchecked' : HasPartialAnyChannel<L> extends true ? 'invalid-partial-any' : IsConcreteUnion<L> extends true ? 'invalid-union' : 'typed';
84
87
  type InvalidLayerErasure = {
85
88
  readonly __betterEffectInvalidLayerErasure: unique symbol;
@@ -100,11 +103,16 @@ type ReplacePreciseOne<Entries extends AnyProviderEntry, Replacement extends Lay
100
103
  type ReplaceErasedOne<Erased extends AnyErasedProvenance, Replacement extends LayerInput> = Erased extends ErasedProvenance<infer Provided, infer StickyRequired> ? ErasedProvenance<RemoveCompatibleServices<Provided, Extract<ProvidedEnvironment<Replacement>, AnyService>>, StickyRequired> : never;
101
104
  type ApplyPreciseOverrides<Entries extends AnyProviderEntry, Overrides extends readonly LayerInput[]> = Overrides extends readonly [infer Head extends LayerInput, ...infer Tail extends readonly LayerInput[]] ? ApplyPreciseOverrides<ReplacePreciseOne<Entries, Head>, Tail> : Entries;
102
105
  type ApplyErasedOverrides<Erased extends AnyErasedProvenance, Overrides extends readonly LayerInput[]> = Overrides extends readonly [infer Head extends LayerInput, ...infer Tail extends readonly LayerInput[]] ? ApplyErasedOverrides<ReplaceErasedOne<Erased, Head> | Extract<ErasedEntries<Head>, AnyErasedProvenance>, Tail> : Erased;
103
- type HasUncheckedLayerInTuple<Layers extends readonly LayerInput[]> = true extends (Layers[number] extends unknown ? IsExactUncheckedLayer<Layers[number]> : never) ? true : false;
106
+ type HasMatchingService<Candidate extends AnyService, Available extends AnyService> = true extends (Available extends AnyService ? SameService<Candidate, Available> : never) ? true : false;
107
+ type GuaranteedServiceCandidates<Candidates extends AnyService, Branches extends LayerInput> = Candidates extends AnyService ? false extends (Branches extends LayerInput ? HasMatchingService<Candidates, Extract<ProvidedEnvironment<Branches>, AnyService>> : never) ? never : Candidates : never;
108
+ type GuaranteedProvided<Branch extends LayerInput, Branches extends LayerInput = Branch> = Branch extends LayerInput ? GuaranteedServiceCandidates<Extract<ProvidedEnvironment<Branch>, AnyService>, Branches> : never;
109
+ type HasUncheckedLayerInTuple<Layers extends readonly LayerInput[]> = true extends { [Index in keyof Layers]: IsExactUncheckedLayer<Layers[Index]>; }[number] ? true : false;
104
110
  type MergeLayerResult<Layers extends readonly LayerInput[]> = HasUncheckedLayerInTuple<Layers> extends true ? Layer<any, any> : LayerResult<PreciseEntries<Layers[number]>, ErasedEntries<Layers[number]>>;
105
111
  /** Internal result type for Layer.merge. */
106
112
  type MergeResult<Layers extends readonly LayerInput[]> = MergeLayerResult<Layers>;
107
- type OverrideLayerResultUnchecked<Base extends LayerInput, Overrides extends readonly LayerInput[]> = HasUncheckedLayerInTuple<[Base, ...Overrides]> extends true ? Layer<any, any> : LayerResult<ApplyPreciseOverrides<PreciseEntries<Base>, Overrides>, ApplyErasedOverrides<ErasedEntries<Base>, Overrides>>;
113
+ type ApplyVisibleOverrides<CurrentProvided extends AnyService, Overrides extends readonly LayerInput[]> = Overrides extends readonly [infer Head extends LayerInput, ...infer Tail extends readonly LayerInput[]] ? ApplyVisibleOverrides<RemoveCompatibleServices<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>> | Extract<ProvidedEnvironment<Head>, AnyService>, Tail> : CurrentProvided;
114
+ type OverrideLayerBranches<Base extends LayerInput, Overrides extends readonly LayerInput[]> = Overrides extends readonly LayerInput[] ? Layer<ApplyVisibleOverrides<Extract<ProvidedEnvironment<Base>, AnyService>, Overrides>, never> : never;
115
+ type OverrideLayerResultUnchecked<Base extends LayerInput, Overrides extends readonly LayerInput[]> = HasUncheckedLayerInTuple<[Base, ...Overrides]> extends true ? Layer<any, any> : LayerResult<ApplyPreciseOverrides<PreciseEntries<Base>, Overrides>, ApplyErasedOverrides<ErasedEntries<Base>, Overrides>, Extract<GuaranteedProvided<OverrideLayerBranches<Base, Overrides>>, AnyService>>;
108
116
  /** Internal result type for an ordered override tuple. */
109
117
  type OverrideLayerResult<Base extends LayerInput, Overrides extends readonly LayerInput[]> = OverrideLayerResultUnchecked<Base, Overrides>;
110
118
  type IncompatibleOverridePair<Current extends AnyService, Replacement extends AnyService> = SameServiceTag<Current, Replacement> extends true ? SameServiceContract<Current, Replacement> extends true ? never : ServiceTokenOf<Replacement> : never;
@@ -117,7 +125,10 @@ type InvalidWidenedProvidedEnvironment = {
117
125
  readonly __betterEffectWidenedProvidedEnvironment: unique symbol;
118
126
  };
119
127
  type ValidateOverrideLayerInput<L extends LayerInput> = IsExactUncheckedLayer<L> extends true ? unknown : ValidateLayerInput<L> & (true extends HasWidenedTag<Extract<ProvidedEnvironment<L>, AnyService>> ? InvalidWidenedProvidedEnvironment : unknown);
128
+ type UnionToIntersection<Union> = (Union extends unknown ? (value: Union) => void : never) extends ((value: infer Intersection) => void) ? Intersection : never;
129
+ type ValidationFailuresToConstraint<Failures> = [Failures] extends [never] ? unknown : UnionToIntersection<Failures>;
120
130
  type ValidateOverrideTuple<Overrides extends readonly LayerInput[]> = { [Index in keyof Overrides]: ValidateOverrideLayerInput<Overrides[Index]>; };
131
+ type ValidateOverrideTupleFailures<Overrides extends readonly LayerInput[]> = ValidationFailuresToConstraint<Overrides extends readonly LayerInput[] ? ValidationFailureWitness<{ [Index in keyof Overrides]: ValidateOverrideLayerInput<Overrides[Index]>; }> : never>;
121
132
  type ServiceAtTag<Services, Tag extends string> = Tag extends keyof Services ? Extract<Services[Tag], AnyService> : never;
122
133
  type ServiceTagMap<Services extends AnyService> = { [Tag in ServiceTagOf<Services>]: Extract<Services, {
123
134
  readonly [ServiceIdentityTypeId]: Tag;
@@ -133,11 +144,32 @@ type ValidateOverridePair<CurrentProvided extends AnyService, ReplacementProvide
133
144
  * Rebuilding the full Layer provenance for every step is quadratic and can
134
145
  * exhaust TypeScript's instantiation depth on otherwise simple override lists.
135
146
  */
136
- type ValidateOverridesFromState<Overrides extends readonly LayerInput[], BaseMap, CurrentProvided extends AnyService, CurrentChanged extends boolean, CurrentUnchecked extends boolean> = Overrides extends readonly [infer Head extends LayerInput, ...infer Tail extends readonly LayerInput[]] ? CurrentUnchecked extends true ? ValidateOverridesFromState<Tail, BaseMap, AnyService, true, true> : IsExactUncheckedLayer<Head> extends true ? ValidateOverridesFromState<Tail, BaseMap, AnyService, true, true> : CurrentChanged extends false ? CanSkipBaseOverride<BaseMap, Extract<ProvidedEnvironment<Head>, AnyService>> extends true ? ValidateOverridesFromState<Tail, BaseMap, CurrentProvided, false, false> : ValidateOverridePair<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>> & ValidateOverridesFromState<Tail, BaseMap, ApplyValidationOverride<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>>, true, false> : ValidateOverridePair<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>> & ValidateOverridesFromState<Tail, BaseMap, ApplyValidationOverride<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>>, true, false> : unknown;
147
+ type ValidateOverridesFromStateForArm<Overrides extends readonly LayerInput[], BaseMap, CurrentProvided extends AnyService, CurrentChanged extends boolean, CurrentUnchecked extends boolean> = Overrides extends readonly [infer Head extends LayerInput, ...infer Tail extends readonly LayerInput[]] ? CurrentUnchecked extends true ? ValidateOverridesFromStateForArm<Tail, BaseMap, AnyService, true, true> : IsExactUncheckedLayer<Head> extends true ? ValidateOverridesFromStateForArm<Tail, BaseMap, AnyService, true, true> : CurrentChanged extends false ? CanSkipBaseOverride<BaseMap, Extract<ProvidedEnvironment<Head>, AnyService>> extends true ? ValidateOverridesFromStateForArm<Tail, BaseMap, CurrentProvided, false, false> : ValidateOverridePair<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>> & ValidateOverridesFromStateForArm<Tail, BaseMap, ApplyValidationOverride<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>>, true, false> : ValidateOverridePair<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>> & ValidateOverridesFromStateForArm<Tail, BaseMap, ApplyValidationOverride<CurrentProvided, Extract<ProvidedEnvironment<Head>, AnyService>>, true, false> : unknown;
148
+ /** Validate every possible override tuple arm instead of accepting one valid arm. */
149
+ type ValidateOverridesFromState<Overrides extends readonly LayerInput[], BaseMap, CurrentProvided extends AnyService, CurrentChanged extends boolean, CurrentUnchecked extends boolean> = ValidationFailuresToConstraint<Overrides extends readonly LayerInput[] ? ValidationFailureWitness<ValidateOverridesFromStateForArm<Overrides, BaseMap, CurrentProvided, CurrentChanged, CurrentUnchecked>> : never>;
137
150
  /** Validate one override against the currently accumulated Layer state. */
138
- type ValidateOneOverride<Current extends LayerInput, Replacement extends LayerInput> = ValidateOverrideLayerInput<Current> & ValidateOverrideLayerInput<Replacement> & (IsExactUncheckedLayer<Current> extends true ? unknown : IsExactUncheckedLayer<Replacement> extends true ? unknown : [IncompatibleOverridePairs<Extract<ProvidedEnvironment<Current>, AnyService>, Extract<ProvidedEnvironment<Replacement>, AnyService>>] extends [never] ? unknown : IncompatibleLayerOverride<IncompatibleOverridePairs<Extract<ProvidedEnvironment<Current>, AnyService>, Extract<ProvidedEnvironment<Replacement>, AnyService>>>);
151
+ type ValidateOneOverride<Current extends LayerInput, Replacement extends LayerInput> = ValidateOverrideLayerInput<Current> & ValidateOverrideLayerInput<Replacement> & (IsExactUncheckedLayer<Current> extends true ? unknown : IsExactUncheckedLayer<Replacement> extends true ? unknown : [IncompatibleOverridePairs<Extract<PossibleProvidedEnvironment<Current>, AnyService>, Extract<PossibleProvidedEnvironment<Replacement>, AnyService>>] extends [never] ? unknown : IncompatibleLayerOverride<IncompatibleOverridePairs<Extract<PossibleProvidedEnvironment<Current>, AnyService>, Extract<PossibleProvidedEnvironment<Replacement>, AnyService>>>);
152
+ type IsTuple<Values extends readonly unknown[]> = number extends Values['length'] ? false : true;
153
+ type InvalidWidenedOverrideList = {
154
+ readonly __betterEffectWidenedOverrideList: unique symbol;
155
+ };
139
156
  /** Validate ordered overrides against the state produced by earlier overrides. */
140
- type ValidateOverrides<Base extends LayerInput, Overrides extends readonly LayerInput[]> = Overrides extends readonly [] ? unknown : ValidateOverrideLayerInput<Base> & ValidateOverrideTuple<Overrides> & ValidateOverridesFromState<Overrides, ServiceTagMap<Extract<ProvidedEnvironment<Base>, AnyService>>, Extract<ProvidedEnvironment<Base>, AnyService>, false, IsExactUncheckedLayer<Base>>;
157
+ type ValidateOverrides<Base extends LayerInput, Overrides extends readonly LayerInput[]> = [Overrides] extends [never] ? unknown : IsTuple<Overrides> extends false ? IsExactUncheckedLayer<Base> extends true ? unknown : InvalidWidenedOverrideList : ValidateOverrideLayerInput<Base> & ValidateOverrideTuple<Overrides> & ValidationFailuresToConstraint<Overrides extends readonly LayerInput[] ? [Overrides] extends [readonly []] ? never : ValidationFailureWitness<ValidateOverrideTuple<Overrides> & ValidateOverrideTupleFailures<Overrides> & ValidateOverridesFromState<Overrides, ServiceTagMap<Extract<PossibleProvidedEnvironment<Base>, AnyService>>, Extract<PossibleProvidedEnvironment<Base>, AnyService>, false, IsExactUncheckedLayer<Base>>> : never>;
158
+ type ValidationFailureWitness<Value> = Value extends {
159
+ readonly __betterEffectIncompatibleLayerOverride: infer Tokens;
160
+ } ? {
161
+ readonly __betterEffectIncompatibleLayerOverride: Tokens;
162
+ } : Value extends {
163
+ readonly __betterEffectInvalidLayerErasure: unique symbol;
164
+ } ? Value : Value extends {
165
+ readonly __betterEffectAmbiguousLayerUnion: unique symbol;
166
+ } ? Value : Value extends {
167
+ readonly __betterEffectWidenedProvidedEnvironment: unique symbol;
168
+ } ? Value : Value extends {
169
+ readonly __betterEffectWidenedOverrideList: unique symbol;
170
+ } ? Value : Value extends readonly (infer Element)[] ? ValidationFailureWitness<Element> : never;
171
+ /** Reduce Layer override validation to a usable call-site diagnostic witness. */
172
+ type ValidateOverridesWitness<Base extends LayerInput, Overrides extends readonly LayerInput[]> = ValidationFailureWitness<ValidateOverrides<Base, Overrides>> extends (infer Failure) ? [Failure] extends [never] ? unknown : Failure : never;
141
173
  /** A Layer accepted by Runtime boundaries after completeness validation. */
142
174
  type CompleteInput<L extends LayerInput> = ValidateLayerInput<L> & (LayerInputState<L> extends 'unchecked' ? L : LayerInputState<L> extends 'typed' ? [RequiredEnvironment<L>] extends [never] ? L : L & MissingDependencies<Extract<RequiredEnvironment<L>, AnyService>> : L);
143
175
  type ExecutionRequirementsMissing<RootProvided extends AnyService, Request extends LayerInput> = MissingServices<Extract<RequiredEnvironment<Request>, AnyService>, Extract<RootProvided, AnyService>>;
@@ -150,18 +182,58 @@ type CompleteExecutionWithRequirements<Provided extends AnyService, A, Required
150
182
  /** Keep execution callbacks unchanged when their Effect requirements are met. */
151
183
  type CompleteExecution<Provided extends AnyService, A> = CompleteExecutionWithRequirements<Provided, A, EffectRequirements<A>>;
152
184
  //#endregion
185
+ //#region src/layer/types.d.ts
186
+ /** Runtime-facing provider registration supplied by a Layer backend. */
187
+ interface LayerRegistration {
188
+ /** The class-backed Service token provided by this registration. */
189
+ readonly service: ServiceClass<any, any>;
190
+ /**
191
+ * The canonical tag captured when the provider was created.
192
+ *
193
+ * This remains optional for direct backend registrations created against the
194
+ * pre-inspection API; backends capture the token tag synchronously when it is
195
+ * omitted.
196
+ */
197
+ readonly serviceTag?: string;
198
+ /** Lazily acquire the Service instance; concrete types are erased at this backend boundary. */
199
+ readonly acquire: () => MaybePromise<unknown>;
200
+ }
201
+ /** Generator shape used by `Layer.gen` and `Layer.scopedGen`. */
202
+ type LayerGenerator<S extends ServiceClass<any, any>, Yield extends ServiceRequirement<unknown> = ServiceRequirement<unknown>> = () => AsyncGenerator<Yield, ServiceContract<InstanceType<S>>, unknown>;
203
+ /** Service requirements inferred from a provider's methods and generator. */
204
+ type LayerGeneratorRequirements<S extends ServiceClass<any, any>, Yield extends ServiceRequirement<unknown>> = ServiceRequirements<InstanceType<S>> | InferYieldRequirements<Yield>;
205
+ //#endregion
153
206
  //#region src/layer/layer.d.ts
154
207
  declare const LayerTypeId: unique symbol;
155
208
  interface LayerVariance<in out Provided, out Required> {
156
209
  readonly _Provided: Invariant<Provided>;
157
210
  readonly _Required: Covariant<Required>;
158
211
  }
212
+ type CapturedLayerAcquisition = {
213
+ readonly instance: unknown;
214
+ readonly release: ScopeFinalizer;
215
+ };
159
216
  interface LayerProvider extends LayerRegistration {
217
+ /** The tag captured before this provider can cross an asynchronous boundary. */
218
+ readonly serviceTag: string;
160
219
  /** Provider storage deliberately erases the concrete instance type. */
161
- readonly release?: (instance: unknown, outcome: ScopeOutcome) => MaybePromise$1<void>;
220
+ readonly release?: (instance: unknown, outcome: ScopeOutcome) => MaybePromise<void>;
221
+ /** Capture acquisition-local cleanup without retaining the acquired instance. */
222
+ readonly acquireWithRelease?: () => MaybePromise<CapturedLayerAcquisition>;
162
223
  }
163
224
  /** A Service class whose constructor can be called without arguments. */
164
225
  type DefaultConstructibleServiceClass<Tag extends string = string, Instance extends AnyService = AnyService> = ServiceClass<Tag, Instance> & (new () => Instance);
226
+ type IsUnion<Type, Candidate = Type> = Type extends unknown ? [Candidate] extends [Type] ? false : true : never;
227
+ type InvalidUnionAliasToken = {
228
+ readonly __betterEffectUnionLayerAliasToken: unique symbol;
229
+ };
230
+ type RejectUnionAliasToken<Token> = IsUnion<Token> extends true ? InvalidUnionAliasToken : unknown;
231
+ type LayerAliasOptions<From extends ServiceClass<any, any>, To extends ServiceClass<any, any>> = {
232
+ readonly from: From;
233
+ readonly to: To;
234
+ } & RejectUnionAliasToken<From> & RejectUnionAliasToken<To> & ([ServiceContract<InstanceType<From>>] extends [ServiceContract<InstanceType<To>>] ? unknown : {
235
+ readonly __betterEffectIncompatibleLayerAlias: unique symbol;
236
+ });
165
237
  /**
166
238
  * Declarative collection of Service providers.
167
239
  *
@@ -184,15 +256,21 @@ declare class Layer<in out Provided extends AnyService = AnyService, out Require
184
256
  /** The provider registrations retained by this Layer. */
185
257
  readonly providers: readonly LayerProvider[];
186
258
  private constructor();
259
+ /** A stable provider-free Layer for composition roots with no Services. */
260
+ static readonly empty: Layer<never, never>;
187
261
  /** Create a Layer that lazily acquires a Service instance. */
188
262
  static make<S extends DefaultConstructibleServiceClass<any, any>>(service: S): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
189
- static make<S extends ServiceClass<any, any>>(service: S, acquire: () => MaybePromise$1<ServiceContract<InstanceType<S>>>): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
263
+ static make<S extends ServiceClass<any, any>>(service: S, acquire: () => MaybePromise<ServiceContract<InstanceType<S>>>): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
190
264
  /** Create a Layer from an already-constructed Service instance. */
191
265
  static succeed<S extends ServiceClass<any, any>>(service: S, instance: ServiceContract<InstanceType<S>>): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
266
+ /** Alias a source Service under a compatible target contract. */
267
+ static alias<From extends ServiceClass<any, any>, To extends ServiceClass<any, any>>(options: LayerAliasOptions<From, To>): LayerResult<ProviderEntry<InstanceType<To>, InstanceType<From> | ServiceRequirements<InstanceType<To>>>>;
192
268
  /** Define a provider with Runtime-root cleanup. */
193
- static scoped<S extends ServiceClass<any, any>>(service: S, acquire: () => MaybePromise$1<ServiceContract<InstanceType<S>>>, release: (instance: InstanceType<S>, outcome: ScopeOutcome) => MaybePromise$1<void>): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
269
+ static scoped<S extends ServiceClass<any, any>>(service: S, acquire: () => MaybePromise<ServiceContract<InstanceType<S>>>, release: (instance: InstanceType<S>, outcome: ScopeOutcome) => MaybePromise<void>): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
270
+ /** Define a provider with Runtime-root cleanup through its disposal protocol. */
271
+ static scopedDisposable<S extends ServiceClass<any, any>>(service: S, acquire: () => MaybePromise<ServiceContract<InstanceType<S>> & DisposableResource>): LayerResult<ProviderEntry<InstanceType<S>, ServiceRequirements<InstanceType<S>>>>;
194
272
  /** Define a provider whose acquisition can yield contextual Services. */
195
- static scopedGen<S extends ServiceClass<any, any>, Yield extends ServiceRequirement<unknown>>(service: S, factory: LayerGenerator<S, Yield>, release: (instance: InstanceType<S>, outcome: ScopeOutcome) => MaybePromise$1<void>): LayerResult<ProviderEntry<InstanceType<S>, LayerGeneratorRequirements<S, Yield>>>;
273
+ static scopedGen<S extends ServiceClass<any, any>, Yield extends ServiceRequirement<unknown>>(service: S, factory: LayerGenerator<S, Yield>, release: (instance: InstanceType<S>, outcome: ScopeOutcome) => MaybePromise<void>): LayerResult<ProviderEntry<InstanceType<S>, LayerGeneratorRequirements<S, Yield>>>;
196
274
  /** Define a provider whose acquisition can yield contextual Services. */
197
275
  static gen<S extends ServiceClass<any, any>, Yield extends ServiceRequirement<unknown>>(service: S, factory: LayerGenerator<S, Yield>): LayerResult<ProviderEntry<InstanceType<S>, LayerGeneratorRequirements<S, Yield>>>;
198
276
  /** Compose Layers without replacing providers. */
@@ -202,7 +280,7 @@ declare class Layer<in out Provided extends AnyService = AnyService, out Require
202
280
  /** Replace providers in a base Layer, using tag identity and compatible contracts. */
203
281
  static override<Base extends LayerInput>(base: Base & ValidateLayerInput<Base>): OverrideLayerResult<Base, readonly []>;
204
282
  static override<Base extends LayerInput, const Overrides extends readonly [LayerInput, ...LayerInput[]]>(base: Base & ValidateLayerInput<Base>, ...overrides: Overrides & ValidateOverrides<Base, Overrides>): OverrideLayerResult<Base, Overrides>;
205
- static override<Base extends LayerInput, const Overrides extends readonly LayerInput[]>(base: Base & ValidateLayerInput<Base>, ...overrides: Overrides extends readonly [LayerInput, ...LayerInput[]] ? never : Overrides & ValidateOverrides<Base, Overrides>): OverrideLayerResult<Base, Overrides>;
283
+ static override<Base extends LayerInput, const Overrides extends readonly LayerInput[]>(base: Base & ValidateLayerInput<Base>, ...overrides: Overrides & ValidateOverrides<Base, Overrides>): OverrideLayerResult<Base, Overrides>;
206
284
  }
207
285
  /** Type-level aliases for inspecting Layer environments and completeness. */
208
286
  declare namespace Layer {
@@ -218,6 +296,23 @@ declare namespace Layer {
218
296
  type Complete<L extends LayerInput> = CompleteInput<L>;
219
297
  }
220
298
  //#endregion
299
+ //#region src/layer/backend.d.ts
300
+ /** Observation hook invoked for acquisitions that disposal will await. */
301
+ type LayerBackendDisposeOptions = {
302
+ /**
303
+ * Receives the in-flight acquisition Promises when disposal begins. The callback
304
+ * is invoked synchronously and awaited before the backend clears its state.
305
+ */
306
+ readonly onPendingAcquisitions?: (acquisitions: readonly Promise<unknown>[]) => void | PromiseLike<void>;
307
+ };
308
+ /** Runtime adapter responsible for registering, resolving, and disposing Layer providers. */
309
+ interface LayerBackend extends ServiceResolver {
310
+ /** Register one Service provider with the backend. */
311
+ register(registration: LayerRegistration): MaybePromise<void>;
312
+ /** Dispose all backend-owned instances and provider registrations. */
313
+ disposeAll(options?: LayerBackendDisposeOptions): MaybePromise<void>;
314
+ }
315
+ //#endregion
221
316
  //#region src/layer/errors.d.ts
222
317
  type LayerCause = Extract<ScopeOutcome, {
223
318
  readonly status: 'failure';
@@ -264,14 +359,26 @@ type RuntimeServiceAcquireEvent = {
264
359
  readonly resolutionPath: readonly AnyServiceToken[];
265
360
  readonly outcome: ScopeOutcome;
266
361
  };
362
+ /** Values supplied to one Runtime execution for diagnostic correlation. */
363
+ type RuntimeExecutionAttributes = Readonly<Record<string, unknown>>;
364
+ /** Metadata shared by the start and end events for one execution. */
365
+ type RuntimeExecutionMetadata = {
366
+ readonly executionId: string;
367
+ readonly name?: string;
368
+ readonly attributes?: RuntimeExecutionAttributes;
369
+ /** Monotonic host timestamp captured immediately before the Program starts. */
370
+ readonly startedAt: number;
371
+ };
267
372
  /** Event emitted immediately before a program starts in an execution Scope. */
268
- type RuntimeExecutionStartEvent = {
373
+ type RuntimeExecutionStartEvent = RuntimeExecutionMetadata & {
269
374
  readonly scope: Scope;
270
375
  };
271
376
  /** Event emitted after a program and its execution Scope settle. */
272
- type RuntimeExecutionEndEvent = {
377
+ type RuntimeExecutionEndEvent = RuntimeExecutionMetadata & {
273
378
  readonly scope: Scope;
274
379
  readonly outcome: ScopeOutcome;
380
+ /** Monotonic elapsed time for the Program and its execution cleanup. */
381
+ readonly durationMs: number;
275
382
  };
276
383
  /** Event emitted after a Layer provider release callback settles. */
277
384
  type RuntimeResourceReleaseEvent = {
@@ -281,11 +388,15 @@ type RuntimeResourceReleaseEvent = {
281
388
  };
282
389
  /** Optional best-effort hooks for Runtime lifecycle and resolution events. */
283
390
  type RuntimeObserver = {
284
- readonly onServiceResolve?: (event: RuntimeServiceResolveEvent) => MaybePromise$1<void>;
285
- readonly onServiceAcquire?: (event: RuntimeServiceAcquireEvent) => MaybePromise$1<void>;
286
- readonly onExecutionStart?: (event: RuntimeExecutionStartEvent) => MaybePromise$1<void>;
287
- readonly onExecutionEnd?: (event: RuntimeExecutionEndEvent) => MaybePromise$1<void>;
288
- readonly onResourceRelease?: (event: RuntimeResourceReleaseEvent) => MaybePromise$1<void>;
391
+ readonly onServiceResolve?: (event: RuntimeServiceResolveEvent) => MaybePromise<void>;
392
+ readonly onServiceAcquire?: (event: RuntimeServiceAcquireEvent) => MaybePromise<void>;
393
+ readonly onExecutionStart?: (event: RuntimeExecutionStartEvent) => MaybePromise<void>;
394
+ readonly onExecutionEnd?: (event: RuntimeExecutionEndEvent) => MaybePromise<void>;
395
+ readonly onResourceRelease?: (event: RuntimeResourceReleaseEvent) => MaybePromise<void>;
396
+ };
397
+ /** Compose best-effort Runtime observers into one observer. */
398
+ declare const RuntimeObserver: {
399
+ compose: (...observers: readonly RuntimeObserver[]) => RuntimeObserver;
289
400
  };
290
401
  //#endregion
291
402
  //#region src/runtime/outcome.d.ts
@@ -297,7 +408,7 @@ type RuntimeShutdownDiagnostic = {
297
408
  readonly error: LayerDisposeError;
298
409
  };
299
410
  /** Observer notified about cleanup failures without changing primary results. */
300
- type CleanupFailureObserver = (diagnostic: CleanupFailureDiagnostic | RuntimeShutdownDiagnostic) => MaybePromise<void>;
411
+ type CleanupFailureObserver = (diagnostic: CleanupFailureDiagnostic | RuntimeShutdownDiagnostic) => MaybePromise$1<void>;
301
412
  /** Optional Runtime configuration for cleanup diagnostics. */
302
413
  type RuntimeOptions = {
303
414
  /** Backend used to register and resolve the Layer. Defaults to MapLayerBackend. */
@@ -313,9 +424,11 @@ type RuntimeOptions = {
313
424
  /** Optional signal exposed through the RuntimeContext. */
314
425
  readonly signal?: AbortSignal;
315
426
  };
316
- /** Optional signal supplied to one managed Runtime execution. */
427
+ /** Optional signal and diagnostic attributes supplied to one Runtime execution. */
317
428
  type RuntimeRunOptions = {
318
429
  readonly signal?: AbortSignal;
430
+ /** Copied once and exposed as a readonly event view. */
431
+ readonly attributes?: RuntimeExecutionAttributes;
319
432
  };
320
433
  /** Cooperative shutdown policy for a managed Runtime. */
321
434
  type RuntimeDisposeOptions = {
@@ -325,5 +438,5 @@ type RuntimeDisposeOptions = {
325
438
  readonly abortAfterGracePeriod?: boolean;
326
439
  };
327
440
  //#endregion
328
- export { MissingDependencies as A, LayerResult as C, ValidateLayerInput as D, RequiredEnvironment as E, ValidateOneOverride as O, LayerInput as S, ProvidedEnvironment as T, Layer as _, RuntimeShutdownDiagnostic as a, CompleteInput as b, RuntimeObserver as c, RuntimeServiceResolveEvent as d, DuplicateServiceError as f, ServiceTagCollisionError as g, LayerRegistrationError as h, RuntimeRunOptions as i, ProviderEntry as k, RuntimeResourceReleaseEvent as l, LayerGeneratorYieldError as m, RuntimeDisposeOptions as n, RuntimeExecutionEndEvent as o, LayerDisposeError as p, RuntimeOptions as r, RuntimeExecutionStartEvent as s, CleanupFailureObserver as t, RuntimeServiceAcquireEvent as u, CompleteExecution as v, MissingServices as w, ExecutionMissing as x, CompleteExecutionLayer as y };
329
- //# sourceMappingURL=index-C7KX5rAP.d.mts.map
441
+ export { MissingServices as A, CompleteExecution as C, LayerInput as D, ExecutionMissing as E, ValidateOneOverride as F, ValidateOverrides as I, ValidateOverridesWitness as L, ProvidedEnvironment as M, RequiredEnvironment as N, LayerInputState as O, ValidateLayerInput as P, ProviderEntry as R, LayerRegistration as S, CompleteInput as T, LayerRegistrationError as _, RuntimeShutdownDiagnostic as a, LayerBackendDisposeOptions as b, RuntimeExecutionMetadata as c, RuntimeResourceReleaseEvent as d, RuntimeServiceAcquireEvent as f, LayerGeneratorYieldError as g, LayerDisposeError as h, RuntimeRunOptions as i, OverrideLayerResult as j, LayerResult as k, RuntimeExecutionStartEvent as l, DuplicateServiceError as m, RuntimeDisposeOptions as n, RuntimeExecutionAttributes as o, RuntimeServiceResolveEvent as p, RuntimeOptions as r, RuntimeExecutionEndEvent as s, CleanupFailureObserver as t, RuntimeObserver as u, ServiceTagCollisionError as v, CompleteExecutionLayer as w, Layer as x, LayerBackend as y, MissingDependencies as z };
442
+ //# sourceMappingURL=outcome-CB43bnFW.d.mts.map