better-effect 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +52 -16
- package/dist/adapters/iti.d.mts +10 -4
- package/dist/adapters/iti.d.mts.map +1 -1
- package/dist/adapters/iti.mjs +24 -4
- package/dist/adapters/iti.mjs.map +1 -1
- package/dist/context-BUEf1qjL.mjs +152 -0
- package/dist/context-BUEf1qjL.mjs.map +1 -0
- package/dist/{effect-CZdZCZLW.mjs → effect-DAMqvegy.mjs} +35 -13
- package/dist/effect-DAMqvegy.mjs.map +1 -0
- package/dist/errors-BKcsQ0ip.d.mts +12 -0
- package/dist/errors-BKcsQ0ip.d.mts.map +1 -0
- package/dist/hono.d.mts +52 -18
- package/dist/hono.d.mts.map +1 -1
- package/dist/hono.mjs +36 -41
- package/dist/hono.mjs.map +1 -1
- package/dist/{index-BsPr7qHf.d.mts → index-BafDna0B.d.mts} +4 -4
- package/dist/{index-BsPr7qHf.d.mts.map → index-BafDna0B.d.mts.map} +1 -1
- package/dist/{index-EJlskfAW.d.mts → index-C7KX5rAP.d.mts} +8 -4
- package/dist/index-C7KX5rAP.d.mts.map +1 -0
- package/dist/{index-1NLNdkJy.d.mts → index-CULgSzUw.d.mts} +4 -4
- package/dist/{index-1NLNdkJy.d.mts.map → index-CULgSzUw.d.mts.map} +1 -1
- package/dist/{index-CITM15SE.d.mts → index-DklNCz7w.d.mts} +4 -4
- package/dist/{index-CITM15SE.d.mts.map → index-DklNCz7w.d.mts.map} +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +31 -34
- package/dist/index.mjs.map +1 -1
- package/dist/{map-layer-backend-DMJauecV.d.mts → map-layer-backend-rNwfH0Bz.d.mts} +2 -2
- package/dist/{map-layer-backend-DMJauecV.d.mts.map → map-layer-backend-rNwfH0Bz.d.mts.map} +1 -1
- package/dist/runtime/explicit.d.mts +11 -7
- package/dist/runtime/explicit.d.mts.map +1 -1
- package/dist/runtime/explicit.mjs +96 -23
- package/dist/runtime/explicit.mjs.map +1 -1
- package/dist/runtime/node.d.mts +2 -2
- package/dist/runtime/node.d.mts.map +1 -1
- package/dist/runtime/node.mjs +10 -6
- package/dist/runtime/node.mjs.map +1 -1
- package/dist/{signal-Cl9tqGyX.mjs → signal-C1bagvrO.mjs} +6 -5
- package/dist/signal-C1bagvrO.mjs.map +1 -0
- package/dist/{standard-services-QseopL9g.mjs → standard-services-DW-i4UuA.mjs} +2 -2
- package/dist/{standard-services-QseopL9g.mjs.map → standard-services-DW-i4UuA.mjs.map} +1 -1
- package/dist/standard-services.d.mts +2 -2
- package/dist/standard-services.mjs +2 -2
- package/dist/testing.d.mts +1 -1
- package/package.json +6 -3
- package/dist/context-B4yO5LaH.mjs +0 -80
- package/dist/context-B4yO5LaH.mjs.map +0 -1
- package/dist/effect-CZdZCZLW.mjs.map +0 -1
- package/dist/errors-BXKc7juX.d.mts +0 -8
- package/dist/errors-BXKc7juX.d.mts.map +0 -1
- package/dist/index-EJlskfAW.d.mts.map +0 -1
- package/dist/signal-Cl9tqGyX.mjs.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bruno Alves
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -10,6 +10,10 @@ Use Services directly inside `Effect.fn` Programs (or eager `Effect.gen` workflo
|
|
|
10
10
|
bun add better-effect better-result
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
The published Runtime entrypoint is officially supported on Node.js and Bun.
|
|
14
|
+
The tested runtime matrix is Node.js 24 and Bun 1.3.14, and the default runtime
|
|
15
|
+
context uses Node/Bun async context propagation.
|
|
16
|
+
|
|
13
17
|
## TypeScript knows what your application needs
|
|
14
18
|
|
|
15
19
|
```ts
|
|
@@ -109,14 +113,20 @@ const inspectDatabase = Effect.fn(async function* () {
|
|
|
109
113
|
await runtime.run(inspectDatabase)
|
|
110
114
|
```
|
|
111
115
|
|
|
116
|
+
Runtime boundaries inspect only nominal `better-result` values: `Result.err`
|
|
117
|
+
becomes a failed execution, while a plain object with `status: 'error'` is
|
|
118
|
+
still a successful value. Intermediate Results do not close the execution
|
|
119
|
+
Scope.
|
|
120
|
+
|
|
112
121
|
`Effect.gen` remains eager for code that already runs inside a resolver and
|
|
113
122
|
Scope. `Effect.fn` captures the generator as a lazy `Program` for Runtime
|
|
114
123
|
boundaries; the callback form remains supported for compatibility.
|
|
115
124
|
|
|
116
125
|
`Program.all` keeps a collection lazy until the returned Program is run. Pass
|
|
117
126
|
`{ concurrency: n }` for a positive bounded FIFO worker pool; values retain
|
|
118
|
-
input order
|
|
119
|
-
|
|
127
|
+
input order. If a Program returns an error or throws, scheduling stops, already-
|
|
128
|
+
started Programs are allowed to settle, and the deterministic primary failure remains selected;
|
|
129
|
+
there is no cancellation or Fiber scheduler.
|
|
120
130
|
|
|
121
131
|
`Runtime.make(AppLive)` and `Runtime.run(AppLive, program)` use the built-in
|
|
122
132
|
`MapLayerBackend`. Pass `{ backend: new ItiLayerBackend() }` when an external
|
|
@@ -168,7 +178,8 @@ const runtime = await Runtime.make(AppLive, {
|
|
|
168
178
|
|
|
169
179
|
Cancellation is cooperative and uses `AbortSignal`; no scheduler or fibers are
|
|
170
180
|
created. Pass a signal to one execution and read it from the program when an
|
|
171
|
-
I/O operation supports cancellation
|
|
181
|
+
I/O operation supports cancellation. Runtime disposal waits for active work;
|
|
182
|
+
it does not forcibly terminate arbitrary Promises:
|
|
172
183
|
|
|
173
184
|
```ts
|
|
174
185
|
const result = await runtime.run(program, { signal: request.signal })
|
|
@@ -186,7 +197,9 @@ const result = await runtime.runWith(RequestLive, handleRequest)
|
|
|
186
197
|
```
|
|
187
198
|
|
|
188
199
|
The request Layer may use root Services, while its scoped providers are closed
|
|
189
|
-
with the execution Scope and never change the shared Runtime environment.
|
|
200
|
+
with the execution Scope and never change the shared Runtime environment. Its
|
|
201
|
+
external requirements must be provided by the Runtime, and the Hono failure
|
|
202
|
+
handler/request-Layer types are checked at the adapter boundary.
|
|
190
203
|
|
|
191
204
|
### Hono request boundaries
|
|
192
205
|
|
|
@@ -201,7 +214,7 @@ import { Result } from 'better-result'
|
|
|
201
214
|
import { HonoEffect } from 'better-effect/hono'
|
|
202
215
|
|
|
203
216
|
const http = HonoEffect.make(runtime, {
|
|
204
|
-
onFailure: (
|
|
217
|
+
onFailure: (_error, c) => c.json({ error: 'Request failed' }, 400)
|
|
205
218
|
})
|
|
206
219
|
const app = new Hono()
|
|
207
220
|
|
|
@@ -216,9 +229,9 @@ app.get(
|
|
|
216
229
|
)
|
|
217
230
|
```
|
|
218
231
|
|
|
219
|
-
Hono validators can
|
|
220
|
-
|
|
221
|
-
|
|
232
|
+
Hono validators can precede the generator or handler callback. Their validated
|
|
233
|
+
`c.req.valid(...)` inputs are combined and inferred without a manual `Input`
|
|
234
|
+
helper:
|
|
222
235
|
|
|
223
236
|
```ts
|
|
224
237
|
import { sValidator } from '@hono/standard-validator'
|
|
@@ -239,17 +252,40 @@ app.post(
|
|
|
239
252
|
)
|
|
240
253
|
```
|
|
241
254
|
|
|
255
|
+
For multiple validators, pass them in order before the callback:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
app.post(
|
|
259
|
+
'/work-orders/:id',
|
|
260
|
+
http.gen(validateParam, validateHeader, validateCreateWorkOrder, async function* (c) {
|
|
261
|
+
const id = c.req.valid('param').id
|
|
262
|
+
const key = c.req.valid('header')['X-Idempotency-Key']
|
|
263
|
+
const input = c.req.valid('json')
|
|
264
|
+
return Result.ok({ id, key, input })
|
|
265
|
+
})
|
|
266
|
+
)
|
|
267
|
+
```
|
|
268
|
+
|
|
242
269
|
The validator middleware runs before the Program and short-circuits with its
|
|
243
|
-
own `Response` when validation fails. `http.handler` accepts the same
|
|
244
|
-
|
|
270
|
+
own `Response` when validation fails. `http.handler` accepts the same ordered
|
|
271
|
+
validator arguments followed by the program factory and options.
|
|
245
272
|
|
|
246
273
|
Install `hono` only when this subpath is used. The main entrypoint does not
|
|
247
|
-
load the framework.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
`
|
|
251
|
-
|
|
252
|
-
|
|
274
|
+
load the framework. The default Hono failure policy redacts every non-`Response`
|
|
275
|
+
failure value to `{ error: 'Internal Server Error' }` with status 500. An
|
|
276
|
+
explicitly returned `Response` failure is intentionally passed through
|
|
277
|
+
unchanged. A custom `onFailure` policy should serialize only safe, intentional
|
|
278
|
+
domain details.
|
|
279
|
+
|
|
280
|
+
Service and Scope access share one `RuntimeContext`. The published Runtime
|
|
281
|
+
entrypoint is officially supported on Node.js and Bun, where `AsyncLocalStorage`
|
|
282
|
+
is the default context storage. The `better-effect/runtime/explicit` subpath
|
|
283
|
+
provides `ExplicitRuntimeContextStorage` as a manually managed, sequential
|
|
284
|
+
strategy only when the package entrypoint and host can load it. One instance
|
|
285
|
+
supports one non-overlapping async flow and rejects concurrent overlap. Using
|
|
286
|
+
it does not make the package generally usable in browsers, Deno, Cloudflare
|
|
287
|
+
Workers, or other non-Node hosts; separate explicit instances are not a general
|
|
288
|
+
concurrent-isolation strategy.
|
|
253
289
|
|
|
254
290
|
If a program asks that Runtime for a Service its environment does not provide, TypeScript rejects the call.
|
|
255
291
|
|
package/dist/adapters/iti.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { N as AnyServiceToken } from "../index-
|
|
2
|
-
import "../index-
|
|
3
|
-
import { a as LayerRegistration, n as LayerBackend } from "../map-layer-backend-
|
|
1
|
+
import { N as AnyServiceToken } from "../index-CULgSzUw.mjs";
|
|
2
|
+
import "../index-C7KX5rAP.mjs";
|
|
3
|
+
import { a as LayerRegistration, n as LayerBackend } from "../map-layer-backend-rNwfH0Bz.mjs";
|
|
4
4
|
//#region src/adapters/iti.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* ITI-backed Layer backend.
|
|
@@ -12,12 +12,18 @@ declare class ItiLayerBackend implements LayerBackend {
|
|
|
12
12
|
private container;
|
|
13
13
|
private readonly keys;
|
|
14
14
|
private readonly registered;
|
|
15
|
+
/**
|
|
16
|
+
* Track async gets so disposal cannot reset ITI while a provider is acquiring.
|
|
17
|
+
* ITI caches rejected acquisitions; replacing the container is the explicit
|
|
18
|
+
* retry boundary for that sticky failure behavior.
|
|
19
|
+
*/
|
|
20
|
+
private readonly pending;
|
|
15
21
|
private keyFor;
|
|
16
22
|
/** Register a Layer provider under its deterministic Service-tag key. */
|
|
17
23
|
register(registration: LayerRegistration): void;
|
|
18
24
|
/** Resolve a registered Service through the ITI container. */
|
|
19
25
|
resolve<T extends AnyServiceToken>(token: T): InstanceType<T> | PromiseLike<InstanceType<T>>;
|
|
20
|
-
/**
|
|
26
|
+
/** Reset container-owned ITI state; Scope owns Layer provider releases. */
|
|
21
27
|
disposeAll(): Promise<void>;
|
|
22
28
|
}
|
|
23
29
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iti.d.mts","names":[],"sources":["../../src/adapters/iti.ts"],"mappings":";;;;;;;;;;cAsBa,2BAA2B;UAC9B;mBAES;mBAEA;UAET;;EAgBR,SAAS,cAAc;;EAuBvB,QAAQ,UAAU,iBAAiB,OAAO,IAAI,aAAa,KAAK,YAAY,aAAa;;
|
|
1
|
+
{"version":3,"file":"iti.d.mts","names":[],"sources":["../../src/adapters/iti.ts"],"mappings":";;;;;;;;;;cAsBa,2BAA2B;UAC9B;mBAES;mBAEA;;;;;;mBAOA;UAET;;EAgBR,SAAS,cAAc;;EAuBvB,QAAQ,UAAU,iBAAiB,OAAO,IAAI,aAAa,KAAK,YAAY,aAAa;;EAiCnF,cAAc"}
|
package/dist/adapters/iti.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as ServiceTagCollisionError, c as ServiceNotFoundError, t as DuplicateServiceError } from "../errors-Dnjhzbt0.mjs";
|
|
2
|
-
import { t as assertServiceCompatibility } from "../internal-identity-DmUpBeeL.mjs";
|
|
3
2
|
import { t as isPromiseLike } from "../runtime-CDcCF5cb.mjs";
|
|
3
|
+
import { t as assertServiceCompatibility } from "../internal-identity-DmUpBeeL.mjs";
|
|
4
4
|
import { createContainer } from "iti";
|
|
5
5
|
//#region src/adapters/iti.ts
|
|
6
6
|
/**
|
|
@@ -13,6 +13,12 @@ var ItiLayerBackend = class {
|
|
|
13
13
|
container = createContainer();
|
|
14
14
|
keys = /* @__PURE__ */ new Map();
|
|
15
15
|
registered = /* @__PURE__ */ new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Track async gets so disposal cannot reset ITI while a provider is acquiring.
|
|
18
|
+
* ITI caches rejected acquisitions; replacing the container is the explicit
|
|
19
|
+
* retry boundary for that sticky failure behavior.
|
|
20
|
+
*/
|
|
21
|
+
pending = /* @__PURE__ */ new Set();
|
|
16
22
|
keyFor(token) {
|
|
17
23
|
const tag = token.serviceTag;
|
|
18
24
|
const existing = this.keys.get(tag);
|
|
@@ -42,12 +48,26 @@ var ItiLayerBackend = class {
|
|
|
42
48
|
assertServiceCompatibility(token, registered, instance);
|
|
43
49
|
return instance;
|
|
44
50
|
};
|
|
45
|
-
if (isPromiseLike(resolved))
|
|
51
|
+
if (isPromiseLike(resolved)) {
|
|
52
|
+
const pending = Promise.resolve(resolved).then(validate);
|
|
53
|
+
this.pending.add(pending);
|
|
54
|
+
pending.then(() => this.pending.delete(pending), () => this.pending.delete(pending));
|
|
55
|
+
return pending;
|
|
56
|
+
}
|
|
46
57
|
return validate(resolved);
|
|
47
58
|
}
|
|
48
|
-
/**
|
|
59
|
+
/** Reset container-owned ITI state; Scope owns Layer provider releases. */
|
|
49
60
|
async disposeAll() {
|
|
50
|
-
|
|
61
|
+
const container = this.container;
|
|
62
|
+
try {
|
|
63
|
+
await Promise.allSettled(this.pending);
|
|
64
|
+
await container.disposeAll();
|
|
65
|
+
} finally {
|
|
66
|
+
this.container = createContainer();
|
|
67
|
+
this.registered.clear();
|
|
68
|
+
this.keys.clear();
|
|
69
|
+
this.pending.clear();
|
|
70
|
+
}
|
|
51
71
|
}
|
|
52
72
|
};
|
|
53
73
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iti.mjs","names":[],"sources":["../../src/adapters/iti.ts"],"sourcesContent":["import { createContainer } from 'iti'\n\nimport {\n DuplicateServiceError,\n ServiceTagCollisionError,\n type LayerBackend,\n type LayerRegistration\n} from '../layer'\n\nimport { ServiceNotFoundError, type AnyServiceToken } from '../service'\n\nimport { assertServiceCompatibility } from '../layer/internal-identity'\nimport { isPromiseLike } from '../utils/runtime'\n\ntype LayerAcquiredValue = Awaited<ReturnType<LayerRegistration['acquire']>>\n\n/**\n * ITI-backed Layer backend.\n *\n * Install `iti` as the optional peer dependency and pass an instance to\n * `Runtime.make` when using ITI's container implementation.\n */\nexport class ItiLayerBackend implements LayerBackend {\n private container: any = createContainer()\n\n private readonly keys = new Map<string, string>()\n\n private readonly registered = new Map<string, AnyServiceToken>()\n\n private keyFor(token: AnyServiceToken): string {\n const tag = token.serviceTag\n const existing = this.keys.get(tag)\n\n if (existing) {\n return existing\n }\n\n const key = `better-effect:${tag}`\n\n this.keys.set(tag, key)\n\n return key\n }\n\n /** Register a Layer provider under its deterministic Service-tag key. */\n register(registration: LayerRegistration): void {\n const token = registration.service\n const tag = token.serviceTag\n const existing = this.registered.get(tag)\n\n if (existing === token) {\n throw new DuplicateServiceError(token)\n }\n\n if (existing) {\n throw new ServiceTagCollisionError(existing, token)\n }\n\n const key = this.keyFor(token)\n\n this.container = this.container.add({\n [key]: registration.acquire\n })\n\n this.registered.set(tag, token)\n }\n\n /** Resolve a registered Service through the ITI container. */\n resolve<T extends AnyServiceToken>(token: T): InstanceType<T> | PromiseLike<InstanceType<T>> {\n const registered = this.registered.get(token.serviceTag)\n\n if (registered === undefined) {\n throw new ServiceNotFoundError(token)\n }\n\n const key = this.keyFor(token)\n const resolved = this.container.get(key)\n\n const validate = (instance: LayerAcquiredValue): InstanceType<T> => {\n assertServiceCompatibility(token, registered, instance)\n\n // SAFETY: The registered tag and compatibility check establish the constructor-to-instance relationship after ITI erases it.\n return instance as InstanceType<T>\n }\n\n if (isPromiseLike(resolved)) {\n
|
|
1
|
+
{"version":3,"file":"iti.mjs","names":[],"sources":["../../src/adapters/iti.ts"],"sourcesContent":["import { createContainer } from 'iti'\n\nimport {\n DuplicateServiceError,\n ServiceTagCollisionError,\n type LayerBackend,\n type LayerRegistration\n} from '../layer'\n\nimport { ServiceNotFoundError, type AnyServiceToken } from '../service'\n\nimport { assertServiceCompatibility } from '../layer/internal-identity'\nimport { isPromiseLike } from '../utils/runtime'\n\ntype LayerAcquiredValue = Awaited<ReturnType<LayerRegistration['acquire']>>\n\n/**\n * ITI-backed Layer backend.\n *\n * Install `iti` as the optional peer dependency and pass an instance to\n * `Runtime.make` when using ITI's container implementation.\n */\nexport class ItiLayerBackend implements LayerBackend {\n private container: any = createContainer()\n\n private readonly keys = new Map<string, string>()\n\n private readonly registered = new Map<string, AnyServiceToken>()\n\n /**\n * Track async gets so disposal cannot reset ITI while a provider is acquiring.\n * ITI caches rejected acquisitions; replacing the container is the explicit\n * retry boundary for that sticky failure behavior.\n */\n private readonly pending = new Set<Promise<unknown>>()\n\n private keyFor(token: AnyServiceToken): string {\n const tag = token.serviceTag\n const existing = this.keys.get(tag)\n\n if (existing) {\n return existing\n }\n\n const key = `better-effect:${tag}`\n\n this.keys.set(tag, key)\n\n return key\n }\n\n /** Register a Layer provider under its deterministic Service-tag key. */\n register(registration: LayerRegistration): void {\n const token = registration.service\n const tag = token.serviceTag\n const existing = this.registered.get(tag)\n\n if (existing === token) {\n throw new DuplicateServiceError(token)\n }\n\n if (existing) {\n throw new ServiceTagCollisionError(existing, token)\n }\n\n const key = this.keyFor(token)\n\n this.container = this.container.add({\n [key]: registration.acquire\n })\n\n this.registered.set(tag, token)\n }\n\n /** Resolve a registered Service through the ITI container. */\n resolve<T extends AnyServiceToken>(token: T): InstanceType<T> | PromiseLike<InstanceType<T>> {\n const registered = this.registered.get(token.serviceTag)\n\n if (registered === undefined) {\n throw new ServiceNotFoundError(token)\n }\n\n const key = this.keyFor(token)\n const resolved = this.container.get(key)\n\n const validate = (instance: LayerAcquiredValue): InstanceType<T> => {\n assertServiceCompatibility(token, registered, instance)\n\n // SAFETY: The registered tag and compatibility check establish the constructor-to-instance relationship after ITI erases it.\n return instance as InstanceType<T>\n }\n\n if (isPromiseLike(resolved)) {\n const pending = Promise.resolve(resolved).then(validate)\n\n this.pending.add(pending)\n void pending.then(\n () => this.pending.delete(pending),\n () => this.pending.delete(pending)\n )\n\n return pending\n }\n\n return validate(resolved)\n }\n\n /** Reset container-owned ITI state; Scope owns Layer provider releases. */\n async disposeAll(): Promise<void> {\n const container = this.container\n\n try {\n await Promise.allSettled(this.pending)\n await container.disposeAll()\n } finally {\n this.container = createContainer()\n this.registered.clear()\n this.keys.clear()\n this.pending.clear()\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAsBA,IAAa,kBAAb,MAAqD;CACnD,YAAyB,gBAAgB;CAEzC,uBAAwB,IAAI,IAAoB;CAEhD,6BAA8B,IAAI,IAA6B;;;;;;CAO/D,0BAA2B,IAAI,IAAsB;CAErD,OAAe,OAAgC;EAC7C,MAAM,MAAM,MAAM;EAClB,MAAM,WAAW,KAAK,KAAK,IAAI,GAAG;EAElC,IAAI,UACF,OAAO;EAGT,MAAM,MAAM,iBAAiB;EAE7B,KAAK,KAAK,IAAI,KAAK,GAAG;EAEtB,OAAO;CACT;;CAGA,SAAS,cAAuC;EAC9C,MAAM,QAAQ,aAAa;EAC3B,MAAM,MAAM,MAAM;EAClB,MAAM,WAAW,KAAK,WAAW,IAAI,GAAG;EAExC,IAAI,aAAa,OACf,MAAM,IAAI,sBAAsB,KAAK;EAGvC,IAAI,UACF,MAAM,IAAI,yBAAyB,UAAU,KAAK;EAGpD,MAAM,MAAM,KAAK,OAAO,KAAK;EAE7B,KAAK,YAAY,KAAK,UAAU,IAAI,GACjC,MAAM,aAAa,QACtB,CAAC;EAED,KAAK,WAAW,IAAI,KAAK,KAAK;CAChC;;CAGA,QAAmC,OAA0D;EAC3F,MAAM,aAAa,KAAK,WAAW,IAAI,MAAM,UAAU;EAEvD,IAAI,eAAe,KAAA,GACjB,MAAM,IAAI,qBAAqB,KAAK;EAGtC,MAAM,MAAM,KAAK,OAAO,KAAK;EAC7B,MAAM,WAAW,KAAK,UAAU,IAAI,GAAG;EAEvC,MAAM,YAAY,aAAkD;GAClE,2BAA2B,OAAO,YAAY,QAAQ;GAGtD,OAAO;EACT;EAEA,IAAI,cAAc,QAAQ,GAAG;GAC3B,MAAM,UAAU,QAAQ,QAAQ,QAAQ,CAAC,CAAC,KAAK,QAAQ;GAEvD,KAAK,QAAQ,IAAI,OAAO;GACxB,QAAa,WACL,KAAK,QAAQ,OAAO,OAAO,SAC3B,KAAK,QAAQ,OAAO,OAAO,CACnC;GAEA,OAAO;EACT;EAEA,OAAO,SAAS,QAAQ;CAC1B;;CAGA,MAAM,aAA4B;EAChC,MAAM,YAAY,KAAK;EAEvB,IAAI;GACF,MAAM,QAAQ,WAAW,KAAK,OAAO;GACrC,MAAM,UAAU,WAAW;EAC7B,UAAU;GACR,KAAK,YAAY,gBAAgB;GACjC,KAAK,WAAW,MAAM;GACtB,KAAK,KAAK,MAAM;GAChB,KAAK,QAAQ,MAAM;EACrB;CACF;AACF"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { t as isPromiseLike } from "./runtime-CDcCF5cb.mjs";
|
|
2
|
+
//#region src/runtime/errors.ts
|
|
3
|
+
/** Thrown when no RuntimeContext is active in the selected storage. */
|
|
4
|
+
var RuntimeContextNotConfiguredError = class extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("No RuntimeContext is available in the current execution context");
|
|
7
|
+
this.name = "RuntimeContextNotConfiguredError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
/** Thrown when ExplicitRuntimeContextStorage cannot safely overlap lineages. */
|
|
11
|
+
var RuntimeContextOverlapError = class extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super("ExplicitRuntimeContextStorage does not support overlapping root or derived context runs; use NodeRuntimeContextStorage for concurrent async branches");
|
|
14
|
+
this.name = "RuntimeContextOverlapError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/runtime/context.ts
|
|
19
|
+
const unconfiguredRuntimeContextStorage = {
|
|
20
|
+
run: (_context, program) => program(),
|
|
21
|
+
current: () => {
|
|
22
|
+
throw new RuntimeContextNotConfiguredError();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const contextLineages = /* @__PURE__ */ new WeakMap();
|
|
26
|
+
/** Associate a derived context with the root context of its execution lineage. */
|
|
27
|
+
const inheritRuntimeContextLineage = (context, parent) => {
|
|
28
|
+
const lineage = contextLineages.get(parent) ?? parent;
|
|
29
|
+
contextLineages.set(context, lineage);
|
|
30
|
+
return context;
|
|
31
|
+
};
|
|
32
|
+
/** Return the root context associated with a contextual value, when known. */
|
|
33
|
+
const getRuntimeContextLineage = (context) => contextLineages.get(context);
|
|
34
|
+
/** Associate a newly-entered root context with itself. */
|
|
35
|
+
const setRuntimeContextLineage = (context) => {
|
|
36
|
+
contextLineages.set(context, context);
|
|
37
|
+
return context;
|
|
38
|
+
};
|
|
39
|
+
const hasPathPrefix = (parent, child) => child.length >= parent.length && parent.every((token, index) => child[index] === token);
|
|
40
|
+
/** Recognize contexts created by a nested Service, Scope, or Layer operation. */
|
|
41
|
+
const isDerivedRuntimeContext = (parent, child) => parent.resolver !== void 0 && child.resolver === parent.resolver && parent.resolutionPath.length > 0 && hasPathPrefix(parent.resolutionPath, child.resolutionPath) && (child.resolutionPath.length > parent.resolutionPath.length || child.scope !== parent.scope);
|
|
42
|
+
function makeRuntimeContext(resolver, scope, resolutionPath, signal, parent) {
|
|
43
|
+
const context = { resolutionPath };
|
|
44
|
+
if (resolver !== void 0) Object.assign(context, { resolver });
|
|
45
|
+
if (scope !== void 0) Object.assign(context, { scope });
|
|
46
|
+
if (signal !== void 0) Object.assign(context, { signal });
|
|
47
|
+
if (parent !== void 0) inheritRuntimeContextLineage(context, parent);
|
|
48
|
+
return context;
|
|
49
|
+
}
|
|
50
|
+
let defaultStorage = unconfiguredRuntimeContextStorage;
|
|
51
|
+
let fallbackFrame;
|
|
52
|
+
const fallbackFrames = /* @__PURE__ */ new Set();
|
|
53
|
+
const settleWithRuntimeStorage = (value, restore) => {
|
|
54
|
+
let promiseLike;
|
|
55
|
+
try {
|
|
56
|
+
promiseLike = isPromiseLike(value);
|
|
57
|
+
} catch (cause) {
|
|
58
|
+
restore();
|
|
59
|
+
throw cause;
|
|
60
|
+
}
|
|
61
|
+
if (!promiseLike) {
|
|
62
|
+
restore();
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return Promise.resolve(value).then((resolved) => {
|
|
67
|
+
restore();
|
|
68
|
+
return resolved;
|
|
69
|
+
}, (cause) => {
|
|
70
|
+
restore();
|
|
71
|
+
throw cause;
|
|
72
|
+
});
|
|
73
|
+
} catch (cause) {
|
|
74
|
+
restore();
|
|
75
|
+
throw cause;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const restoreFallbackFrame = (frame) => {
|
|
79
|
+
fallbackFrames.delete(frame);
|
|
80
|
+
if (fallbackFrame !== frame) return;
|
|
81
|
+
let parent = frame.parent;
|
|
82
|
+
while (parent !== void 0 && !fallbackFrames.has(parent)) parent = parent.parent;
|
|
83
|
+
fallbackFrame = parent;
|
|
84
|
+
};
|
|
85
|
+
const fallbackRuntimeContextFrameCarrier = {
|
|
86
|
+
run(frame, program) {
|
|
87
|
+
fallbackFrames.add(frame);
|
|
88
|
+
fallbackFrame = frame;
|
|
89
|
+
const restore = () => restoreFallbackFrame(frame);
|
|
90
|
+
try {
|
|
91
|
+
return settleWithRuntimeStorage(program(), restore);
|
|
92
|
+
} catch (cause) {
|
|
93
|
+
restore();
|
|
94
|
+
throw cause;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
current: () => fallbackFrame
|
|
98
|
+
};
|
|
99
|
+
let runtimeContextFrameCarrier = fallbackRuntimeContextFrameCarrier;
|
|
100
|
+
/** Install host async-context propagation for Runtime context frames. */
|
|
101
|
+
const setRuntimeContextFrameCarrier = (carrier) => {
|
|
102
|
+
runtimeContextFrameCarrier = carrier;
|
|
103
|
+
};
|
|
104
|
+
/** Return whether a host async-context carrier has been installed. */
|
|
105
|
+
const isRuntimeContextFrameCarrierInstalled = () => runtimeContextFrameCarrier !== fallbackRuntimeContextFrameCarrier;
|
|
106
|
+
/** Return the frame associated with the executing callback. */
|
|
107
|
+
const currentRuntimeContextFrame = () => runtimeContextFrameCarrier.current();
|
|
108
|
+
/** Install the host default used by the main Runtime entrypoint. */
|
|
109
|
+
const setDefaultRuntimeContextStorage = (storage) => {
|
|
110
|
+
defaultStorage = storage;
|
|
111
|
+
};
|
|
112
|
+
/** Return the storage currently associated with the executing callback. */
|
|
113
|
+
const activeRuntimeContextStorage = () => currentRuntimeContextFrame()?.storage ?? defaultStorage;
|
|
114
|
+
/** Return the active context, or undefined when the storage has not been entered. */
|
|
115
|
+
const getRuntimeContext = (storage = activeRuntimeContextStorage()) => {
|
|
116
|
+
const frame = currentRuntimeContextFrame();
|
|
117
|
+
if (frame?.storage === storage) return frame.context;
|
|
118
|
+
try {
|
|
119
|
+
return storage.current();
|
|
120
|
+
} catch (cause) {
|
|
121
|
+
if (cause instanceof RuntimeContextNotConfiguredError) return;
|
|
122
|
+
throw cause;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
/** Return the active context or throw the storage's standard missing-context error. */
|
|
126
|
+
const currentRuntimeContext = () => {
|
|
127
|
+
return currentRuntimeContextFrame()?.context ?? defaultStorage.current();
|
|
128
|
+
};
|
|
129
|
+
/** Keep a storage discoverable to Service and Scope compatibility bridges. */
|
|
130
|
+
const withActiveRuntimeContextStorage = (storage, context, program) => {
|
|
131
|
+
const current = currentRuntimeContextFrame();
|
|
132
|
+
if (current?.storage === storage && current.context === context) return program();
|
|
133
|
+
const frame = current === void 0 ? {
|
|
134
|
+
storage,
|
|
135
|
+
context
|
|
136
|
+
} : {
|
|
137
|
+
storage,
|
|
138
|
+
context,
|
|
139
|
+
parent: current
|
|
140
|
+
};
|
|
141
|
+
return runtimeContextFrameCarrier.run(frame, program);
|
|
142
|
+
};
|
|
143
|
+
/** Run a callback in a context while keeping the selected storage discoverable to bridges. */
|
|
144
|
+
const runRuntimeContext = (storage, context, program) => {
|
|
145
|
+
const current = getRuntimeContext(storage);
|
|
146
|
+
const contextual = current !== void 0 && isDerivedRuntimeContext(current, context) ? inheritRuntimeContextLineage(context, current) : context;
|
|
147
|
+
return storage.run(contextual, () => withActiveRuntimeContextStorage(storage, contextual, program));
|
|
148
|
+
};
|
|
149
|
+
//#endregion
|
|
150
|
+
export { getRuntimeContextLineage as a, isRuntimeContextFrameCarrierInstalled as c, setDefaultRuntimeContextStorage as d, setRuntimeContextFrameCarrier as f, RuntimeContextOverlapError as g, RuntimeContextNotConfiguredError as h, getRuntimeContext as i, makeRuntimeContext as l, withActiveRuntimeContextStorage as m, currentRuntimeContext as n, inheritRuntimeContextLineage as o, setRuntimeContextLineage as p, currentRuntimeContextFrame as r, isDerivedRuntimeContext as s, activeRuntimeContextStorage as t, runRuntimeContext as u };
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=context-BUEf1qjL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-BUEf1qjL.mjs","names":[],"sources":["../src/runtime/errors.ts","../src/runtime/context.ts"],"sourcesContent":["/** Thrown when no RuntimeContext is active in the selected storage. */\nexport class RuntimeContextNotConfiguredError extends Error {\n constructor() {\n super('No RuntimeContext is available in the current execution context')\n\n this.name = 'RuntimeContextNotConfiguredError'\n }\n}\n\n/** Thrown when ExplicitRuntimeContextStorage cannot safely overlap lineages. */\nexport class RuntimeContextOverlapError extends Error {\n constructor() {\n super(\n 'ExplicitRuntimeContextStorage does not support overlapping root or derived context runs; use NodeRuntimeContextStorage for concurrent async branches'\n )\n\n this.name = 'RuntimeContextOverlapError'\n }\n}\n","import { RuntimeContextNotConfiguredError } from './errors'\n\nimport type { Scope } from '../scope/scope'\nimport type { AnyServiceToken, ServiceResolver } from '../service'\nimport { isPromiseLike } from '../utils/runtime'\n\n/** Contextual state shared by Service, Scope and Layer resolution. */\nexport interface RuntimeContext {\n readonly resolver?: ServiceResolver\n readonly scope?: Scope\n readonly signal?: AbortSignal\n readonly resolutionPath: readonly AnyServiceToken[]\n}\n\n/** A context with both channels required by a Runtime execution. */\nexport type CompleteRuntimeContext = RuntimeContext & {\n readonly resolver: ServiceResolver\n readonly scope: Scope\n}\n\n/** Host-specific storage for the current RuntimeContext. */\nexport interface RuntimeContextStorage {\n run<A>(context: RuntimeContext, program: () => A): A\n current(): RuntimeContext\n}\n\nconst unconfiguredRuntimeContextStorage: RuntimeContextStorage = {\n run: (_context, program) => program(),\n current: () => {\n throw new RuntimeContextNotConfiguredError()\n }\n}\n\nconst contextLineages = new WeakMap<object, RuntimeContext>()\n\n/** Associate a derived context with the root context of its execution lineage. */\nexport const inheritRuntimeContextLineage = (\n context: RuntimeContext,\n parent: RuntimeContext\n): RuntimeContext => {\n const lineage = contextLineages.get(parent) ?? parent\n contextLineages.set(context, lineage)\n return context\n}\n\n/** Return the root context associated with a contextual value, when known. */\nexport const getRuntimeContextLineage = (context: RuntimeContext): RuntimeContext | undefined =>\n contextLineages.get(context)\n\n/** Associate a newly-entered root context with itself. */\nexport const setRuntimeContextLineage = (context: RuntimeContext): RuntimeContext => {\n contextLineages.set(context, context)\n return context\n}\n\nconst hasPathPrefix = (\n parent: readonly AnyServiceToken[],\n child: readonly AnyServiceToken[]\n): boolean =>\n child.length >= parent.length && parent.every((token, index) => child[index] === token)\n\n/** Recognize contexts created by a nested Service, Scope, or Layer operation. */\nexport const isDerivedRuntimeContext = (parent: RuntimeContext, child: RuntimeContext): boolean =>\n parent.resolver !== undefined &&\n child.resolver === parent.resolver &&\n parent.resolutionPath.length > 0 &&\n hasPathPrefix(parent.resolutionPath, child.resolutionPath) &&\n (child.resolutionPath.length > parent.resolutionPath.length || child.scope !== parent.scope)\n\n/** Build a context while retaining only channels that are actually available. */\nexport function makeRuntimeContext(\n resolver: ServiceResolver,\n scope: Scope,\n resolutionPath: readonly AnyServiceToken[],\n signal: AbortSignal | undefined,\n parent?: RuntimeContext\n): CompleteRuntimeContext\nexport function makeRuntimeContext(\n resolver: ServiceResolver | undefined,\n scope: Scope | undefined,\n resolutionPath: readonly AnyServiceToken[],\n signal: AbortSignal | undefined,\n parent?: RuntimeContext\n): RuntimeContext\nexport function makeRuntimeContext(\n resolver: ServiceResolver | undefined,\n scope: Scope | undefined,\n resolutionPath: readonly AnyServiceToken[],\n signal: AbortSignal | undefined,\n parent?: RuntimeContext\n): RuntimeContext {\n const context: RuntimeContext = { resolutionPath }\n\n if (resolver !== undefined) {\n Object.assign(context, { resolver })\n }\n\n if (scope !== undefined) {\n Object.assign(context, { scope })\n }\n\n if (signal !== undefined) {\n Object.assign(context, { signal })\n }\n\n if (parent !== undefined) {\n inheritRuntimeContextLineage(context, parent)\n }\n\n return context\n}\n\n/** A context frame selected for one logical Runtime execution branch. */\nexport type ActiveRuntimeContextFrame = {\n readonly storage: RuntimeContextStorage\n readonly context: RuntimeContext\n readonly parent?: ActiveRuntimeContextFrame\n}\n\n/** Host-provided propagation for Runtime context frames. */\nexport interface RuntimeContextFrameCarrier {\n run<A>(frame: ActiveRuntimeContextFrame, program: () => A): A\n current(): ActiveRuntimeContextFrame | undefined\n}\n\nlet defaultStorage = unconfiguredRuntimeContextStorage\nlet fallbackFrame: ActiveRuntimeContextFrame | undefined\nconst fallbackFrames = new Set<ActiveRuntimeContextFrame>()\n\nconst settleWithRuntimeStorage = <A>(value: A, restore: () => void): A => {\n let promiseLike: boolean\n\n try {\n promiseLike = isPromiseLike(value)\n } catch (cause) {\n restore()\n throw cause\n }\n\n if (!promiseLike) {\n restore()\n return value\n }\n\n try {\n // SAFETY: PromiseLike values are normalized only to restore the storage after settlement; the public generic retains the callback's awaited shape.\n return Promise.resolve(value).then(\n (resolved) => {\n restore()\n return resolved\n },\n (cause) => {\n restore()\n throw cause\n }\n ) as A\n } catch (cause) {\n restore()\n throw cause\n }\n}\n\nconst restoreFallbackFrame = (frame: ActiveRuntimeContextFrame): void => {\n fallbackFrames.delete(frame)\n\n if (fallbackFrame !== frame) {\n return\n }\n\n let parent = frame.parent\n\n while (parent !== undefined && !fallbackFrames.has(parent)) {\n parent = parent.parent\n }\n\n fallbackFrame = parent\n}\n\nconst fallbackRuntimeContextFrameCarrier: RuntimeContextFrameCarrier = {\n run<A>(frame: ActiveRuntimeContextFrame, program: () => A): A {\n fallbackFrames.add(frame)\n fallbackFrame = frame\n const restore = (): void => restoreFallbackFrame(frame)\n\n try {\n return settleWithRuntimeStorage(program(), restore)\n } catch (cause) {\n restore()\n throw cause\n }\n },\n\n current: () => fallbackFrame\n}\n\nlet runtimeContextFrameCarrier: RuntimeContextFrameCarrier = fallbackRuntimeContextFrameCarrier\n\n/** Install host async-context propagation for Runtime context frames. */\nexport const setRuntimeContextFrameCarrier = (carrier: RuntimeContextFrameCarrier): void => {\n runtimeContextFrameCarrier = carrier\n}\n\n/** Return whether a host async-context carrier has been installed. */\nexport const isRuntimeContextFrameCarrierInstalled = (): boolean =>\n runtimeContextFrameCarrier !== fallbackRuntimeContextFrameCarrier\n\n/** Return the frame associated with the executing callback. */\nexport const currentRuntimeContextFrame = (): ActiveRuntimeContextFrame | undefined =>\n runtimeContextFrameCarrier.current()\n\n/** Install the host default used by the main Runtime entrypoint. */\nexport const setDefaultRuntimeContextStorage = (storage: RuntimeContextStorage): void => {\n defaultStorage = storage\n}\n\n/** Return the storage currently associated with the executing callback. */\nexport const activeRuntimeContextStorage = (): RuntimeContextStorage =>\n currentRuntimeContextFrame()?.storage ?? defaultStorage\n\n/** Return the active context, or undefined when the storage has not been entered. */\nexport const getRuntimeContext = (\n storage: RuntimeContextStorage = activeRuntimeContextStorage()\n): RuntimeContext | undefined => {\n const frame = currentRuntimeContextFrame()\n\n if (frame?.storage === storage) {\n return frame.context\n }\n\n try {\n return storage.current()\n } catch (cause) {\n if (cause instanceof RuntimeContextNotConfiguredError) {\n return undefined\n }\n\n throw cause\n }\n}\n\n/** Return the active context or throw the storage's standard missing-context error. */\nexport const currentRuntimeContext = (): RuntimeContext => {\n const frame = currentRuntimeContextFrame()\n\n return frame?.context ?? defaultStorage.current()\n}\n\n/** Keep a storage discoverable to Service and Scope compatibility bridges. */\nexport const withActiveRuntimeContextStorage = <A>(\n storage: RuntimeContextStorage,\n context: RuntimeContext,\n program: () => A\n): A => {\n const current = currentRuntimeContextFrame()\n\n if (current?.storage === storage && current.context === context) {\n return program()\n }\n\n const frame: ActiveRuntimeContextFrame =\n current === undefined ? { storage, context } : { storage, context, parent: current }\n\n return runtimeContextFrameCarrier.run(frame, program)\n}\n\n/** Run a callback in a context while keeping the selected storage discoverable to bridges. */\nexport const runRuntimeContext = <A>(\n storage: RuntimeContextStorage,\n context: RuntimeContext,\n program: () => A\n): A => {\n const current = getRuntimeContext(storage)\n const contextual =\n current !== undefined && isDerivedRuntimeContext(current, context)\n ? inheritRuntimeContextLineage(context, current)\n : context\n\n return storage.run(contextual, () =>\n withActiveRuntimeContextStorage(storage, contextual, program)\n )\n}\n"],"mappings":";;;AACA,IAAa,mCAAb,cAAsD,MAAM;CAC1D,cAAc;EACZ,MAAM,iEAAiE;EAEvE,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,6BAAb,cAAgD,MAAM;CACpD,cAAc;EACZ,MACE,sJACF;EAEA,KAAK,OAAO;CACd;AACF;;;ACQA,MAAM,oCAA2D;CAC/D,MAAM,UAAU,YAAY,QAAQ;CACpC,eAAe;EACb,MAAM,IAAI,iCAAiC;CAC7C;AACF;AAEA,MAAM,kCAAkB,IAAI,QAAgC;;AAG5D,MAAa,gCACX,SACA,WACmB;CACnB,MAAM,UAAU,gBAAgB,IAAI,MAAM,KAAK;CAC/C,gBAAgB,IAAI,SAAS,OAAO;CACpC,OAAO;AACT;;AAGA,MAAa,4BAA4B,YACvC,gBAAgB,IAAI,OAAO;;AAG7B,MAAa,4BAA4B,YAA4C;CACnF,gBAAgB,IAAI,SAAS,OAAO;CACpC,OAAO;AACT;AAEA,MAAM,iBACJ,QACA,UAEA,MAAM,UAAU,OAAO,UAAU,OAAO,OAAO,OAAO,UAAU,MAAM,WAAW,KAAK;;AAGxF,MAAa,2BAA2B,QAAwB,UAC9D,OAAO,aAAa,KAAA,KACpB,MAAM,aAAa,OAAO,YAC1B,OAAO,eAAe,SAAS,KAC/B,cAAc,OAAO,gBAAgB,MAAM,cAAc,MACxD,MAAM,eAAe,SAAS,OAAO,eAAe,UAAU,MAAM,UAAU,OAAO;AAiBxF,SAAgB,mBACd,UACA,OACA,gBACA,QACA,QACgB;CAChB,MAAM,UAA0B,EAAE,eAAe;CAEjD,IAAI,aAAa,KAAA,GACf,OAAO,OAAO,SAAS,EAAE,SAAS,CAAC;CAGrC,IAAI,UAAU,KAAA,GACZ,OAAO,OAAO,SAAS,EAAE,MAAM,CAAC;CAGlC,IAAI,WAAW,KAAA,GACb,OAAO,OAAO,SAAS,EAAE,OAAO,CAAC;CAGnC,IAAI,WAAW,KAAA,GACb,6BAA6B,SAAS,MAAM;CAG9C,OAAO;AACT;AAeA,IAAI,iBAAiB;AACrB,IAAI;AACJ,MAAM,iCAAiB,IAAI,IAA+B;AAE1D,MAAM,4BAA+B,OAAU,YAA2B;CACxE,IAAI;CAEJ,IAAI;EACF,cAAc,cAAc,KAAK;CACnC,SAAS,OAAO;EACd,QAAQ;EACR,MAAM;CACR;CAEA,IAAI,CAAC,aAAa;EAChB,QAAQ;EACR,OAAO;CACT;CAEA,IAAI;EAEF,OAAO,QAAQ,QAAQ,KAAK,CAAC,CAAC,MAC3B,aAAa;GACZ,QAAQ;GACR,OAAO;EACT,IACC,UAAU;GACT,QAAQ;GACR,MAAM;EACR,CACF;CACF,SAAS,OAAO;EACd,QAAQ;EACR,MAAM;CACR;AACF;AAEA,MAAM,wBAAwB,UAA2C;CACvE,eAAe,OAAO,KAAK;CAE3B,IAAI,kBAAkB,OACpB;CAGF,IAAI,SAAS,MAAM;CAEnB,OAAO,WAAW,KAAA,KAAa,CAAC,eAAe,IAAI,MAAM,GACvD,SAAS,OAAO;CAGlB,gBAAgB;AAClB;AAEA,MAAM,qCAAiE;CACrE,IAAO,OAAkC,SAAqB;EAC5D,eAAe,IAAI,KAAK;EACxB,gBAAgB;EAChB,MAAM,gBAAsB,qBAAqB,KAAK;EAEtD,IAAI;GACF,OAAO,yBAAyB,QAAQ,GAAG,OAAO;EACpD,SAAS,OAAO;GACd,QAAQ;GACR,MAAM;EACR;CACF;CAEA,eAAe;AACjB;AAEA,IAAI,6BAAyD;;AAG7D,MAAa,iCAAiC,YAA8C;CAC1F,6BAA6B;AAC/B;;AAGA,MAAa,8CACX,+BAA+B;;AAGjC,MAAa,mCACX,2BAA2B,QAAQ;;AAGrC,MAAa,mCAAmC,YAAyC;CACvF,iBAAiB;AACnB;;AAGA,MAAa,oCACX,2BAA2B,CAAC,EAAE,WAAW;;AAG3C,MAAa,qBACX,UAAiC,4BAA4B,MAC9B;CAC/B,MAAM,QAAQ,2BAA2B;CAEzC,IAAI,OAAO,YAAY,SACrB,OAAO,MAAM;CAGf,IAAI;EACF,OAAO,QAAQ,QAAQ;CACzB,SAAS,OAAO;EACd,IAAI,iBAAiB,kCACnB;EAGF,MAAM;CACR;AACF;;AAGA,MAAa,8BAA8C;CAGzD,OAFc,2BAEH,CAAC,EAAE,WAAW,eAAe,QAAQ;AAClD;;AAGA,MAAa,mCACX,SACA,SACA,YACM;CACN,MAAM,UAAU,2BAA2B;CAE3C,IAAI,SAAS,YAAY,WAAW,QAAQ,YAAY,SACtD,OAAO,QAAQ;CAGjB,MAAM,QACJ,YAAY,KAAA,IAAY;EAAE;EAAS;CAAQ,IAAI;EAAE;EAAS;EAAS,QAAQ;CAAQ;CAErF,OAAO,2BAA2B,IAAI,OAAO,OAAO;AACtD;;AAGA,MAAa,qBACX,SACA,SACA,YACM;CACN,MAAM,UAAU,kBAAkB,OAAO;CACzC,MAAM,aACJ,YAAY,KAAA,KAAa,wBAAwB,SAAS,OAAO,IAC7D,6BAA6B,SAAS,OAAO,IAC7C;CAEN,OAAO,QAAQ,IAAI,kBACjB,gCAAgC,SAAS,YAAY,OAAO,CAC9D;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as RuntimeContextNotConfiguredError, i as getRuntimeContext, l as makeRuntimeContext, n as currentRuntimeContext, t as activeRuntimeContextStorage, u as runRuntimeContext } from "./context-BUEf1qjL.mjs";
|
|
2
2
|
import { t as isPromiseLike } from "./runtime-CDcCF5cb.mjs";
|
|
3
|
-
import { Result } from "better-result";
|
|
3
|
+
import { Err, Result } from "better-result";
|
|
4
4
|
//#region src/scope/errors.ts
|
|
5
5
|
/** Thrown when Scope context is accessed outside an active Scope execution. */
|
|
6
6
|
var ScopeRuntimeNotConfiguredError = class extends Error {
|
|
@@ -56,7 +56,7 @@ var ScopeRuntime = class {
|
|
|
56
56
|
static run(scope, program, storage = scopeStorages.get(scope) ?? activeRuntimeContextStorage()) {
|
|
57
57
|
scopeStorages.set(scope, storage);
|
|
58
58
|
const current = getRuntimeContext(storage);
|
|
59
|
-
const context = makeRuntimeContext(current?.resolver, scope, current?.resolutionPath ?? [], current?.signal);
|
|
59
|
+
const context = makeRuntimeContext(current?.resolver, scope, current?.resolutionPath ?? [], current?.signal, current);
|
|
60
60
|
return runRuntimeContext(storage, context, program);
|
|
61
61
|
}
|
|
62
62
|
/** Return the Scope active in the current execution context. */
|
|
@@ -64,8 +64,9 @@ var ScopeRuntime = class {
|
|
|
64
64
|
let context;
|
|
65
65
|
try {
|
|
66
66
|
context = currentRuntimeContext();
|
|
67
|
-
} catch {
|
|
68
|
-
throw new ScopeRuntimeNotConfiguredError();
|
|
67
|
+
} catch (cause) {
|
|
68
|
+
if (cause instanceof RuntimeContextNotConfiguredError) throw new ScopeRuntimeNotConfiguredError();
|
|
69
|
+
throw cause;
|
|
69
70
|
}
|
|
70
71
|
if (!context.scope) throw new ScopeRuntimeNotConfiguredError();
|
|
71
72
|
return context.scope;
|
|
@@ -94,10 +95,27 @@ const runScoped = async (scope, program, options) => {
|
|
|
94
95
|
programFailed = true;
|
|
95
96
|
programFailure = cause;
|
|
96
97
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
let outcome;
|
|
99
|
+
let outcomeStatus;
|
|
100
|
+
if (programFailed) {
|
|
101
|
+
outcome = {
|
|
102
|
+
status: "failure",
|
|
103
|
+
cause: programFailure
|
|
104
|
+
};
|
|
105
|
+
outcomeStatus = "failure";
|
|
106
|
+
} else try {
|
|
107
|
+
outcome = options.classify(value);
|
|
108
|
+
outcomeStatus = outcome.status;
|
|
109
|
+
} catch (cause) {
|
|
110
|
+
programFailed = true;
|
|
111
|
+
programFailure = cause;
|
|
112
|
+
outcome = {
|
|
113
|
+
status: "failure",
|
|
114
|
+
cause
|
|
115
|
+
};
|
|
116
|
+
outcomeStatus = "failure";
|
|
117
|
+
}
|
|
118
|
+
options.onOutcome?.(outcome);
|
|
101
119
|
let cleanupFailed = false;
|
|
102
120
|
let cleanupFailure;
|
|
103
121
|
try {
|
|
@@ -115,7 +133,7 @@ const runScoped = async (scope, program, options) => {
|
|
|
115
133
|
cleanupFailure = error;
|
|
116
134
|
}
|
|
117
135
|
if (programFailed) throw programFailure;
|
|
118
|
-
if (
|
|
136
|
+
if (outcomeStatus === "failure") return value;
|
|
119
137
|
if (cleanupFailed) throw cleanupFailure;
|
|
120
138
|
return value;
|
|
121
139
|
};
|
|
@@ -419,15 +437,19 @@ function programAll(programs, options = {}) {
|
|
|
419
437
|
const failures = Array.from({ length: programs.length }, () => false);
|
|
420
438
|
const causes = Array.from({ length: programs.length });
|
|
421
439
|
let nextIndex = 0;
|
|
440
|
+
let stopScheduling = false;
|
|
422
441
|
const worker = async () => {
|
|
423
|
-
while (
|
|
442
|
+
while (!stopScheduling) {
|
|
424
443
|
const index = nextIndex++;
|
|
425
444
|
if (index >= programs.length) return;
|
|
426
445
|
try {
|
|
427
|
-
|
|
446
|
+
const result = await programs[index]();
|
|
447
|
+
results[index] = result;
|
|
448
|
+
if (result instanceof Err) stopScheduling = true;
|
|
428
449
|
} catch (cause) {
|
|
429
450
|
failures[index] = true;
|
|
430
451
|
causes[index] = cause;
|
|
452
|
+
stopScheduling = true;
|
|
431
453
|
}
|
|
432
454
|
}
|
|
433
455
|
};
|
|
@@ -519,4 +541,4 @@ const Effect = {
|
|
|
519
541
|
//#endregion
|
|
520
542
|
export { ScopeRuntime as a, ScopeCloseError as c, runScoped as i, ScopeClosedError as l, Program as n, disposeResource as o, Scope as r, ResourceNotDisposableError as s, Effect as t, ScopeRuntimeNotConfiguredError as u };
|
|
521
543
|
|
|
522
|
-
//# sourceMappingURL=effect-
|
|
544
|
+
//# sourceMappingURL=effect-DAMqvegy.mjs.map
|