better-effect 0.10.0 → 0.11.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 (48) hide show
  1. package/README.md +244 -5
  2. package/dist/adapters/iti.d.mts +3 -4
  3. package/dist/adapters/iti.d.mts.map +1 -1
  4. package/dist/adapters/iti.mjs +9 -4
  5. package/dist/adapters/iti.mjs.map +1 -1
  6. package/dist/effect-2ZcGZI8A.mjs +513 -0
  7. package/dist/effect-2ZcGZI8A.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-BafDna0B.d.mts → index-C7Qild0_.d.mts} +158 -28
  13. package/dist/index-C7Qild0_.d.mts.map +1 -0
  14. package/dist/{index-DklNCz7w.d.mts → index-DStz0JMN.d.mts} +4 -4
  15. package/dist/{index-DklNCz7w.d.mts.map → index-DStz0JMN.d.mts.map} +1 -1
  16. package/dist/{index-CULgSzUw.d.mts → index-heuaRmXR.d.mts} +5 -5
  17. package/dist/{index-CULgSzUw.d.mts.map → index-heuaRmXR.d.mts.map} +1 -1
  18. package/dist/{index-C7KX5rAP.d.mts → index-rQhZk3Nt.d.mts} +127 -24
  19. package/dist/index-rQhZk3Nt.d.mts.map +1 -0
  20. package/dist/index.d.mts +4 -5
  21. package/dist/index.mjs +7 -538
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/runtime/explicit.d.mts +1 -1
  24. package/dist/runtime/node.d.mts +1 -1
  25. package/dist/runtime-DnMn0X0X.mjs +613 -0
  26. package/dist/runtime-DnMn0X0X.mjs.map +1 -0
  27. package/dist/scope-GGnmTQck.mjs +245 -0
  28. package/dist/scope-GGnmTQck.mjs.map +1 -0
  29. package/dist/{signal-C1bagvrO.mjs → signal-B97cs85Z.mjs} +81 -2
  30. package/dist/signal-B97cs85Z.mjs.map +1 -0
  31. package/dist/{standard-services-DW-i4UuA.mjs → standard-services-BFBq-4lo.mjs} +2 -2
  32. package/dist/{standard-services-DW-i4UuA.mjs.map → standard-services-BFBq-4lo.mjs.map} +1 -1
  33. package/dist/standard-services.d.mts +2 -2
  34. package/dist/standard-services.mjs +2 -2
  35. package/dist/testing.d.mts +198 -2
  36. package/dist/testing.d.mts.map +1 -0
  37. package/dist/testing.mjs +976 -2
  38. package/dist/testing.mjs.map +1 -0
  39. package/package.json +1 -1
  40. package/dist/effect-DAMqvegy.mjs +0 -544
  41. package/dist/effect-DAMqvegy.mjs.map +0 -1
  42. package/dist/index-BafDna0B.d.mts.map +0 -1
  43. package/dist/index-C7KX5rAP.d.mts.map +0 -1
  44. package/dist/map-layer-backend-gal-mcRv.mjs +0 -53
  45. package/dist/map-layer-backend-gal-mcRv.mjs.map +0 -1
  46. package/dist/map-layer-backend-rNwfH0Bz.d.mts +0 -42
  47. package/dist/map-layer-backend-rNwfH0Bz.d.mts.map +0 -1
  48. package/dist/signal-C1bagvrO.mjs.map +0 -1
@@ -0,0 +1,613 @@
1
+ import { a as ServiceTagCollisionError, c as ServiceNotFoundError, i as LayerRegistrationError, n as LayerDisposeError, o as CircularDependencyError, s as ServiceAcquisitionError, t as DuplicateServiceError } from "./errors-Dnjhzbt0.mjs";
2
+ import { i as getRuntimeContext, l as makeRuntimeContext, u as runRuntimeContext } from "./context-BUEf1qjL.mjs";
3
+ import { f as defaultRuntimeContextStorage, n as linkAbortSignals } from "./signal-B97cs85Z.mjs";
4
+ import { n as runScoped, r as ScopeRuntime, t as Scope } from "./scope-GGnmTQck.mjs";
5
+ import { t as assertServiceCompatibility } from "./internal-identity-DmUpBeeL.mjs";
6
+ import { Err } from "better-result";
7
+ //#region src/layer/map-layer-backend.ts
8
+ /** Native map-backed Layer backend used by Runtime when no adapter is supplied. */
9
+ var MapLayerBackend = class {
10
+ providers = /* @__PURE__ */ new Map();
11
+ instances = /* @__PURE__ */ new Map();
12
+ pending = /* @__PURE__ */ new Map();
13
+ /** Register a provider, rejecting duplicate or colliding Service tags. */
14
+ register(registration) {
15
+ const tag = registration.service.serviceTag;
16
+ const existing = this.providers.get(tag);
17
+ if (existing) {
18
+ if (existing.service !== registration.service) throw new ServiceTagCollisionError(existing.service, registration.service);
19
+ throw new DuplicateServiceError(registration.service);
20
+ }
21
+ this.providers.set(tag, registration);
22
+ }
23
+ /** Resolve and cache a provider instance by Service tag. */
24
+ async resolve(token) {
25
+ const tag = token.serviceTag;
26
+ const provider = this.providers.get(tag);
27
+ if (!provider) throw new ServiceNotFoundError(token);
28
+ const validate = (instance) => {
29
+ assertServiceCompatibility(token, provider.service, instance);
30
+ return instance;
31
+ };
32
+ const cached = this.instances.get(tag);
33
+ if (cached !== void 0) return validate(cached);
34
+ const pending = this.pending.get(tag);
35
+ if (pending) return validate(await pending);
36
+ const acquisition = Promise.resolve().then(() => provider.acquire()).then((instance) => {
37
+ validate(instance);
38
+ this.instances.set(tag, instance);
39
+ return instance;
40
+ }).finally(() => {
41
+ this.pending.delete(tag);
42
+ });
43
+ this.pending.set(tag, acquisition);
44
+ return validate(await acquisition);
45
+ }
46
+ /** Clear pending acquisitions, cached instances, and provider registrations. */
47
+ async disposeAll(options) {
48
+ const acquisitions = [...this.pending.values()];
49
+ if (acquisitions.length > 0) {
50
+ const observePending = options?.onPendingAcquisitions;
51
+ if (observePending) await observePending(acquisitions);
52
+ await Promise.allSettled(acquisitions);
53
+ }
54
+ this.instances.clear();
55
+ this.pending.clear();
56
+ this.providers.clear();
57
+ }
58
+ };
59
+ //#endregion
60
+ //#region src/runtime/outcome.ts
61
+ /** Classify only a nominal better-result Err as a failed Runtime outcome. */
62
+ const classifyRuntimeOutcome = (value) => {
63
+ if (value instanceof Err) return {
64
+ status: "failure",
65
+ cause: value.error
66
+ };
67
+ return { status: "success" };
68
+ };
69
+ //#endregion
70
+ //#region src/runtime/observer.ts
71
+ /** Compose best-effort Runtime observers into one observer. */
72
+ const RuntimeObserver = { compose: (...observers) => ({
73
+ onServiceResolve: (event) => {
74
+ notifyRuntimeObservers(observers, (observer) => observer.onServiceResolve, event);
75
+ },
76
+ onServiceAcquire: (event) => {
77
+ notifyRuntimeObservers(observers, (observer) => observer.onServiceAcquire, event);
78
+ },
79
+ onExecutionStart: (event) => {
80
+ notifyRuntimeObservers(observers, (observer) => observer.onExecutionStart, event);
81
+ },
82
+ onExecutionEnd: (event) => {
83
+ notifyRuntimeObservers(observers, (observer) => observer.onExecutionEnd, event);
84
+ },
85
+ onResourceRelease: (event) => {
86
+ notifyRuntimeObservers(observers, (observer) => observer.onResourceRelease, event);
87
+ }
88
+ }) };
89
+ const notifyRuntimeObservers = (observers, select, event) => {
90
+ for (const observer of observers) {
91
+ const callback = select(observer);
92
+ if (!callback) continue;
93
+ try {
94
+ Promise.resolve(callback(event)).catch(() => {});
95
+ } catch {}
96
+ }
97
+ };
98
+ //#endregion
99
+ //#region src/layer/resolution.ts
100
+ const findCycleStart = (path, token) => path.findIndex((current) => current.serviceTag === token.serviceTag);
101
+ const shouldPreserve = (cause) => cause instanceof CircularDependencyError || cause instanceof ServiceAcquisitionError || cause instanceof ServiceNotFoundError || cause instanceof ServiceTagCollisionError;
102
+ /** Wrap a backend with Runtime-local resolution paths and acquisition errors. */
103
+ const createResolutionResolver = (resolver, storage = defaultRuntimeContextStorage, observers = []) => {
104
+ const wrapped = { async resolve(token) {
105
+ const context = getRuntimeContext(storage);
106
+ const path = context?.resolutionPath ?? [];
107
+ const cycleStart = findCycleStart(path, token);
108
+ const resolutionPath = [...path, token];
109
+ const notifyResolve = (outcome) => {
110
+ notifyRuntimeObservers(observers, (observer) => observer.onServiceResolve, {
111
+ service: token,
112
+ resolutionPath,
113
+ outcome
114
+ });
115
+ };
116
+ if (cycleStart >= 0) {
117
+ const error = new CircularDependencyError([...path.slice(cycleStart), token]);
118
+ notifyResolve({
119
+ status: "failure",
120
+ cause: error
121
+ });
122
+ throw error;
123
+ }
124
+ const nextContext = makeRuntimeContext(wrapped, context?.scope, resolutionPath, context?.signal, context);
125
+ return await runRuntimeContext(storage, nextContext, async () => {
126
+ try {
127
+ const instance = await resolver.resolve(token);
128
+ notifyResolve({ status: "success" });
129
+ return instance;
130
+ } catch (cause) {
131
+ if (shouldPreserve(cause)) {
132
+ notifyResolve({
133
+ status: "failure",
134
+ cause
135
+ });
136
+ throw cause;
137
+ }
138
+ const error = new ServiceAcquisitionError(token, resolutionPath, cause);
139
+ notifyResolve({
140
+ status: "failure",
141
+ cause: error
142
+ });
143
+ throw error;
144
+ }
145
+ });
146
+ } };
147
+ return wrapped;
148
+ };
149
+ //#endregion
150
+ //#region src/layer/runtime.ts
151
+ const SCOPE_SUCCESS = Object.freeze({ status: "success" });
152
+ var RuntimeHandleDisposedError = class extends Error {
153
+ constructor() {
154
+ super("Cannot run a program using a disposed Layer");
155
+ this.name = "RuntimeHandleDisposedError";
156
+ }
157
+ };
158
+ const normalizeDisposeCauses = (cause) => {
159
+ if (cause instanceof AggregateError) return [...cause.errors];
160
+ return [cause];
161
+ };
162
+ const isScopeOutcome = (input) => input !== void 0 && "status" in input;
163
+ const validateDisposeOptions = (options) => {
164
+ const { gracePeriod } = options;
165
+ if (gracePeriod !== void 0 && (!Number.isFinite(gracePeriod) || gracePeriod < 0)) throw new RangeError("Runtime dispose gracePeriod must be a finite non-negative number");
166
+ };
167
+ const notifyShutdownFailure = async (observer, diagnostic) => {
168
+ if (!observer) return;
169
+ try {
170
+ await observer(diagnostic);
171
+ } catch {}
172
+ };
173
+ const releaseLayerResource = async (service, release, outcome, observers) => {
174
+ try {
175
+ await release(outcome);
176
+ notifyRuntimeObservers(observers, (observer) => observer.onResourceRelease, {
177
+ service,
178
+ outcome
179
+ });
180
+ } catch (cause) {
181
+ notifyRuntimeObservers(observers, (observer) => observer.onResourceRelease, {
182
+ service,
183
+ outcome,
184
+ error: cause
185
+ });
186
+ throw cause;
187
+ }
188
+ };
189
+ const bindProviderToScope = (provider, scope, contextStorage, resolver, observers) => ({
190
+ service: provider.service,
191
+ acquire: () => {
192
+ const current = getRuntimeContext(contextStorage);
193
+ const context = makeRuntimeContext(resolver, scope, current?.resolutionPath ?? [], current?.signal, current);
194
+ return runRuntimeContext(contextStorage, context, () => ScopeRuntime.run(scope, async () => {
195
+ const resolutionPath = current?.resolutionPath ?? [provider.service];
196
+ try {
197
+ const instance = provider.acquireWithRelease ? (await scope.acquire(provider.acquireWithRelease, (acquired, outcome) => releaseLayerResource(provider.service, acquired.release, outcome, observers))).instance : provider.release ? await scope.acquire(() => provider.acquire(), (resource, outcome) => releaseLayerResource(provider.service, (releaseOutcome) => provider.release(resource, releaseOutcome), outcome, observers)) : await provider.acquire();
198
+ notifyRuntimeObservers(observers, (observer) => observer.onServiceAcquire, {
199
+ service: provider.service,
200
+ resolutionPath,
201
+ outcome: SCOPE_SUCCESS
202
+ });
203
+ return instance;
204
+ } catch (cause) {
205
+ notifyRuntimeObservers(observers, (observer) => observer.onServiceAcquire, {
206
+ service: provider.service,
207
+ resolutionPath,
208
+ outcome: {
209
+ status: "failure",
210
+ cause
211
+ }
212
+ });
213
+ throw cause;
214
+ }
215
+ }, contextStorage));
216
+ }
217
+ });
218
+ /** Resolve request-local providers first, then fall back to the Runtime root. */
219
+ var ExecutionLayerBackend = class {
220
+ local;
221
+ root;
222
+ localTags = /* @__PURE__ */ new Set();
223
+ constructor(local, root) {
224
+ this.local = local;
225
+ this.root = root;
226
+ }
227
+ register(registration) {
228
+ this.localTags.add(registration.service.serviceTag);
229
+ this.local.register(registration);
230
+ }
231
+ async resolve(token) {
232
+ if (this.localTags.has(token.serviceTag)) return await this.local.resolve(token);
233
+ return await this.root.resolve(token);
234
+ }
235
+ async disposeAll() {
236
+ await this.local.disposeAll();
237
+ this.localTags.clear();
238
+ }
239
+ };
240
+ var RuntimeHandleImpl = class {
241
+ backend;
242
+ resolver;
243
+ rootScope;
244
+ onCleanupFailure;
245
+ contextStorage;
246
+ signal;
247
+ observers;
248
+ services;
249
+ disposePromise;
250
+ warmupPromise;
251
+ executions = /* @__PURE__ */ new Set();
252
+ shutdownController = new AbortController();
253
+ state = "active";
254
+ constructor(backend, resolver, rootScope, onCleanupFailure, contextStorage, signal, observers, services) {
255
+ this.backend = backend;
256
+ this.resolver = resolver;
257
+ this.rootScope = rootScope;
258
+ this.onCleanupFailure = onCleanupFailure;
259
+ this.contextStorage = contextStorage;
260
+ this.signal = signal;
261
+ this.observers = observers;
262
+ this.services = services;
263
+ }
264
+ run(program, options) {
265
+ this.assertActive();
266
+ const executionScope = this.rootScope.fork();
267
+ const signalLink = linkAbortSignals(this.signal, options?.signal, this.shutdownController.signal);
268
+ return this.startExecution(signalLink, () => this.runExecution(executionScope, program, this.resolver, signalLink.signal));
269
+ }
270
+ runWith(layer, program, options) {
271
+ this.assertActive();
272
+ const executionScope = this.rootScope.fork();
273
+ const localBackend = new MapLayerBackend();
274
+ const backend = new ExecutionLayerBackend(localBackend, this.backend);
275
+ const resolver = createResolutionResolver(backend, this.contextStorage, this.observers);
276
+ const signalLink = linkAbortSignals(this.signal, options?.signal, this.shutdownController.signal);
277
+ return this.startExecution(signalLink, async () => {
278
+ try {
279
+ return await this.runExecution(executionScope, async () => {
280
+ for (const provider of layer.providers) backend.register(bindProviderToScope(provider, executionScope, this.contextStorage, resolver, this.observers));
281
+ return await program();
282
+ }, resolver, signalLink.signal);
283
+ } finally {
284
+ await localBackend.disposeAll();
285
+ }
286
+ });
287
+ }
288
+ warmup() {
289
+ this.assertActive();
290
+ if (this.warmupPromise) return this.warmupPromise;
291
+ const warmup = runRuntimeContext(this.contextStorage, makeRuntimeContext(this.resolver, this.rootScope, [], this.signal), async () => {
292
+ for (const service of this.services) await this.resolver.resolve(service);
293
+ });
294
+ this.warmupPromise = warmup;
295
+ warmup.then(() => {
296
+ if (this.warmupPromise === warmup) this.warmupPromise = void 0;
297
+ }, () => {
298
+ if (this.warmupPromise === warmup) this.warmupPromise = void 0;
299
+ });
300
+ return warmup;
301
+ }
302
+ startExecution(signalLink, run) {
303
+ let resolveExecution;
304
+ let rejectExecution;
305
+ const execution = new Promise((resolve, reject) => {
306
+ resolveExecution = resolve;
307
+ rejectExecution = reject;
308
+ });
309
+ const activeExecution = { promise: execution };
310
+ this.executions.add(activeExecution);
311
+ execution.then(() => {
312
+ this.executions.delete(activeExecution);
313
+ signalLink.dispose();
314
+ }, () => {
315
+ this.executions.delete(activeExecution);
316
+ signalLink.dispose();
317
+ });
318
+ try {
319
+ run().then((value) => {
320
+ resolveExecution(value);
321
+ }, (cause) => {
322
+ rejectExecution(cause);
323
+ });
324
+ } catch (cause) {
325
+ rejectExecution(cause);
326
+ }
327
+ return execution;
328
+ }
329
+ runExecution(executionScope, program, resolver = this.resolver, signal = this.shutdownController.signal) {
330
+ let outcome;
331
+ const onOutcome = (determinedOutcome) => {
332
+ outcome = determinedOutcome;
333
+ };
334
+ const runOptions = this.onCleanupFailure ? {
335
+ classify: classifyRuntimeOutcome,
336
+ onOutcome,
337
+ onCleanupFailure: this.onCleanupFailure
338
+ } : {
339
+ classify: classifyRuntimeOutcome,
340
+ onOutcome
341
+ };
342
+ notifyRuntimeObservers(this.observers, (observer) => observer.onExecutionStart, { scope: executionScope });
343
+ return runScoped(executionScope, program, {
344
+ ...runOptions,
345
+ contextStorage: this.contextStorage,
346
+ context: makeRuntimeContext(resolver, executionScope, [], signal)
347
+ }).then((value) => {
348
+ notifyRuntimeObservers(this.observers, (observer) => observer.onExecutionEnd, {
349
+ scope: executionScope,
350
+ outcome
351
+ });
352
+ return value;
353
+ }, (cause) => {
354
+ notifyRuntimeObservers(this.observers, (observer) => observer.onExecutionEnd, {
355
+ scope: executionScope,
356
+ outcome
357
+ });
358
+ throw cause;
359
+ });
360
+ }
361
+ dispose(input) {
362
+ if (this.disposePromise) return this.disposePromise;
363
+ const outcome = isScopeOutcome(input) || input === void 0 ? input ?? SCOPE_SUCCESS : SCOPE_SUCCESS;
364
+ const options = isScopeOutcome(input) || input === void 0 ? {} : input;
365
+ validateDisposeOptions(options);
366
+ this.state = "disposing";
367
+ const executions = [...this.executions];
368
+ this.disposePromise = this.performDispose(executions, outcome, options);
369
+ return this.disposePromise;
370
+ }
371
+ async performDispose(executions, outcome, options) {
372
+ const failures = [];
373
+ await Promise.allSettled(this.warmupPromise ? [this.warmupPromise] : []);
374
+ await this.waitForExecutions(executions, options);
375
+ try {
376
+ const signalLink = linkAbortSignals(this.signal, this.shutdownController.signal);
377
+ try {
378
+ await runRuntimeContext(this.contextStorage, makeRuntimeContext(this.resolver, this.rootScope, [], signalLink.signal), () => this.rootScope.close(outcome));
379
+ } finally {
380
+ signalLink.dispose();
381
+ }
382
+ } catch (cause) {
383
+ failures.push(cause);
384
+ }
385
+ try {
386
+ await this.backend.disposeAll();
387
+ } catch (cause) {
388
+ failures.push(cause);
389
+ }
390
+ this.state = "disposed";
391
+ if (failures.length > 0) {
392
+ const error = new LayerDisposeError(failures.flatMap(normalizeDisposeCauses));
393
+ await notifyShutdownFailure(this.onCleanupFailure, {
394
+ outcome,
395
+ error
396
+ });
397
+ throw error;
398
+ }
399
+ }
400
+ async waitForExecutions(executions, options) {
401
+ const settled = Promise.allSettled(executions.map((execution) => execution.promise));
402
+ if (options.abortAfterGracePeriod !== true || executions.length === 0) {
403
+ await settled;
404
+ return;
405
+ }
406
+ const gracePeriod = options.gracePeriod ?? 0;
407
+ let timer;
408
+ const timedOut = await Promise.race([settled.then(() => false), new Promise((resolve) => {
409
+ timer = setTimeout(() => resolve(true), gracePeriod);
410
+ })]);
411
+ if (timer !== void 0) clearTimeout(timer);
412
+ if (timedOut && !this.shutdownController.signal.aborted) this.shutdownController.abort(/* @__PURE__ */ new Error("Runtime shutdown grace period exceeded"));
413
+ await settled;
414
+ }
415
+ assertActive() {
416
+ if (this.state !== "active") throw new RuntimeHandleDisposedError();
417
+ }
418
+ };
419
+ /** Build a Runtime handle for a complete Layer and register its providers. */
420
+ const createRuntimeHandle = async (layer, backend, options = {}) => {
421
+ const rootScope = Scope.make();
422
+ const contextStorage = options.contextStorage ?? defaultRuntimeContextStorage;
423
+ const observers = options.observers ?? [];
424
+ const resolver = createResolutionResolver(backend, contextStorage, observers);
425
+ ScopeRuntime.bind(rootScope, contextStorage);
426
+ let current;
427
+ try {
428
+ for (const provider of layer.providers) {
429
+ current = provider;
430
+ await backend.register(bindProviderToScope(provider, rootScope, contextStorage, resolver, observers));
431
+ }
432
+ } catch (registrationCause) {
433
+ const outcome = {
434
+ status: "failure",
435
+ cause: registrationCause
436
+ };
437
+ const cleanupCauses = [];
438
+ try {
439
+ await runRuntimeContext(contextStorage, makeRuntimeContext(resolver, rootScope, [], options.signal), () => rootScope.close(outcome));
440
+ } catch (cause) {
441
+ cleanupCauses.push(cause);
442
+ }
443
+ try {
444
+ await backend.disposeAll();
445
+ } catch (cause) {
446
+ cleanupCauses.push(cause);
447
+ }
448
+ if (cleanupCauses.length > 0) {
449
+ const shutdownError = new LayerDisposeError(cleanupCauses.flatMap(normalizeDisposeCauses));
450
+ await notifyShutdownFailure(options.onCleanupFailure, {
451
+ outcome,
452
+ error: shutdownError
453
+ });
454
+ }
455
+ const cleanupCause = cleanupCauses.length === 1 ? cleanupCauses[0] : cleanupCauses.length > 1 ? new LayerDisposeError(cleanupCauses.flatMap(normalizeDisposeCauses)) : void 0;
456
+ throw new LayerRegistrationError(current?.service, registrationCause, cleanupCause);
457
+ }
458
+ return new RuntimeHandleImpl(backend, resolver, rootScope, options.onCleanupFailure, contextStorage, options.signal, observers, layer.providers.map((provider) => provider.service));
459
+ };
460
+ //#endregion
461
+ //#region src/runtime/runtime.ts
462
+ const isLayerBackend = (value) => value !== void 0 && "register" in value && "resolve" in value && "disposeAll" in value;
463
+ const resolveRuntimeConfig = (backendOrOptions, legacyOptions) => {
464
+ if (isLayerBackend(backendOrOptions)) return {
465
+ backend: backendOrOptions,
466
+ options: legacyOptions ?? {}
467
+ };
468
+ const options = backendOrOptions ?? {};
469
+ return {
470
+ backend: options.backend ?? new MapLayerBackend(),
471
+ options
472
+ };
473
+ };
474
+ /**
475
+ * Long-lived execution environment backed by a complete Layer.
476
+ *
477
+ * A Runtime owns Layer resources until `dispose()` is called. Each `run()` is
478
+ * isolated in a child Scope, while Layer-scoped resources remain shared.
479
+ *
480
+ * @example
481
+ * ```ts
482
+ * const runtime = await Runtime.make(AppLive)
483
+ * const result = await runtime.run(loadUser('u1'))
484
+ * await runtime.dispose()
485
+ * ```
486
+ *
487
+ * @typeParam Provided The branded Service instances supplied by the Layer.
488
+ */
489
+ var Runtime = class Runtime {
490
+ handle;
491
+ constructor(handle) {
492
+ this.handle = handle;
493
+ }
494
+ static async make(layer, backendOrOptions, legacyOptions) {
495
+ const { backend, options } = resolveRuntimeConfig(backendOrOptions, legacyOptions);
496
+ const handle = await createRuntimeHandle(layer, backend, options);
497
+ const runtime = new Runtime(handle);
498
+ if (options.warmup) await runtime.warmup();
499
+ return runtime;
500
+ }
501
+ static async run(layer, backendOrProgramOrOptions, programOrOptions, legacyOptions) {
502
+ let program;
503
+ let backendOrOptions;
504
+ let options;
505
+ if (typeof backendOrProgramOrOptions === "function") {
506
+ program = backendOrProgramOrOptions;
507
+ backendOrOptions = programOrOptions;
508
+ options = void 0;
509
+ } else {
510
+ backendOrOptions = backendOrProgramOrOptions;
511
+ program = programOrOptions;
512
+ options = legacyOptions;
513
+ }
514
+ const config = resolveRuntimeConfig(backendOrOptions, options);
515
+ let programOutcome;
516
+ const outcomeObserver = { onExecutionEnd: ({ outcome }) => {
517
+ programOutcome = outcome;
518
+ } };
519
+ const runtimeOptions = {
520
+ ...config.options,
521
+ observers: [outcomeObserver, ...config.options.observers ?? []]
522
+ };
523
+ const runtime = await Runtime.make(layer, config.backend, runtimeOptions);
524
+ let value;
525
+ let executionFailed = false;
526
+ let executionFailure;
527
+ try {
528
+ value = await runtime.runUnchecked(program);
529
+ } catch (cause) {
530
+ executionFailed = true;
531
+ executionFailure = cause;
532
+ }
533
+ const outcome = programOutcome ?? {
534
+ status: "failure",
535
+ cause: executionFailure
536
+ };
537
+ try {
538
+ await runtime.disposeWithOutcome(outcome);
539
+ } catch (shutdownFailure) {
540
+ if (!executionFailed && outcome.status === "success") throw shutdownFailure;
541
+ }
542
+ if (executionFailed) throw executionFailure;
543
+ return value;
544
+ }
545
+ static async use(layer, use, options) {
546
+ const runtime = await Runtime.make(layer, options);
547
+ let value;
548
+ let executionFailed = false;
549
+ let executionFailure;
550
+ let programOutcome;
551
+ try {
552
+ value = await use(runtime);
553
+ programOutcome = classifyRuntimeOutcome(value);
554
+ } catch (cause) {
555
+ executionFailed = true;
556
+ executionFailure = cause;
557
+ programOutcome = {
558
+ status: "failure",
559
+ cause
560
+ };
561
+ }
562
+ const outcome = programOutcome ?? {
563
+ status: "failure",
564
+ cause: executionFailure
565
+ };
566
+ try {
567
+ await runtime.disposeWithOutcome(outcome);
568
+ } catch (shutdownFailure) {
569
+ if (!executionFailed && outcome.status === "success") throw shutdownFailure;
570
+ }
571
+ if (executionFailed) throw executionFailure;
572
+ return value;
573
+ }
574
+ /** Resolve every Layer provider and dispose the Runtime if warmup fails. */
575
+ async warmup() {
576
+ try {
577
+ await this.handle.warmup();
578
+ } catch (cause) {
579
+ try {
580
+ await this.handle.dispose({
581
+ status: "failure",
582
+ cause
583
+ });
584
+ } catch {}
585
+ throw cause;
586
+ }
587
+ }
588
+ /** Run one execution in this Runtime's child Scope. */
589
+ run(program, options) {
590
+ return this.handle.run(program, options);
591
+ }
592
+ /** Run one execution with a Layer owned by that execution's child Scope. */
593
+ runWith(layer, program, options) {
594
+ return this.handle.runWith(layer, program, options);
595
+ }
596
+ runUnchecked(program) {
597
+ return this.handle.run(program);
598
+ }
599
+ dispose(optionsOrOutcome) {
600
+ return this.handle.dispose(optionsOrOutcome);
601
+ }
602
+ /** Release Runtime-owned resources through JavaScript's async disposal protocol. */
603
+ async [Symbol.asyncDispose]() {
604
+ await this.dispose();
605
+ }
606
+ disposeWithOutcome(outcome) {
607
+ return this.handle.dispose(outcome);
608
+ }
609
+ };
610
+ //#endregion
611
+ export { MapLayerBackend as i, RuntimeObserver as n, classifyRuntimeOutcome as r, Runtime as t };
612
+
613
+ //# sourceMappingURL=runtime-DnMn0X0X.mjs.map