better-effect 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,336 +1,272 @@
1
1
  # better-effect
2
2
 
3
- Lightweight Effect-inspired primitives built around [`better-result`](https://www.npmjs.com/package/better-result).
3
+ **Effect-like dependency safety for better-result.**
4
4
 
5
- `better-effect` focuses on a small set of ideas that are useful in application code without bringing in a full effect runtime:
5
+ Type your errors with `better-result`. Typecheck the rest of your application wiring with `better-effect`.
6
6
 
7
- - **Service**contextual dependency access with `yield*`
8
- - **Layer** — declarative composition of live/test environments
9
- - **Resource** — safe acquire/use/release lifecycle
10
- - **DI adapters** — dependency resolution is delegated to an external container instead of being reimplemented by the library
11
-
12
- The goal is not to recreate Effect. The goal is to provide a small, composable layer on top of `better-result`.
13
-
14
- ## Installation
7
+ Use Services directly inside `Effect.gen`, compose implementations into application environments, and let TypeScript catch missing dependencies before your application starts while keeping Promises, `better-result`, and your DI backend.
15
8
 
16
9
  ```bash
17
10
  bun add better-effect better-result
18
11
  ```
19
12
 
20
- If you want the ITI adapter:
21
-
22
- ```bash
23
- bun add iti
24
- ```
25
-
26
- ## Service
27
-
28
- A service is a class that also acts as its own dependency token.
13
+ ## TypeScript knows what your application needs
29
14
 
30
15
  ```ts
31
16
  import { Result } from 'better-result'
32
- import { Service } from 'better-effect'
17
+ import { Effect, Layer, Runtime, Service } from 'better-effect'
33
18
 
34
- export class Database extends Service<Database>() {
35
- findUser(email: string) {
36
- return Promise.resolve({
37
- id: '1',
38
- email
39
- })
19
+ class Database extends Service<Database>() {
20
+ findUser(id: string) {
21
+ // ...
40
22
  }
41
23
  }
42
24
 
43
- export class UserRepository extends Service<UserRepository>() {
44
- findByEmail(email: string) {
45
- return Result.gen(async function* () {
25
+ class UserRepository extends Service<UserRepository>() {
26
+ findUser(id: string) {
27
+ return Effect.gen(async function* () {
46
28
  const database = yield* Database
47
29
 
48
- const user = await database.findUser(email)
49
-
50
- return Result.ok(user)
30
+ return Result.ok(await database.findUser(id))
51
31
  })
52
32
  }
53
33
  }
54
- ```
55
34
 
56
- There are no string tokens:
35
+ const UserRepositoryLive = Layer.make(UserRepository, () => new UserRepository())
57
36
 
58
- ```ts
59
- const database = yield * Database
37
+ await Runtime.make(UserRepositoryLive, backend)
38
+ // ^^^^^^^^^^^^^^^^^^
39
+ // Type error: Database is required but not provided
60
40
  ```
61
41
 
62
- The class itself is the identity used by the resolver, and the result is inferred as `Database`.
42
+ `UserRepository` used `Database`, so `Database` became part of its environment requirements.
63
43
 
64
- ### Why classes are tokens
44
+ No dependency list was written manually.
65
45
 
66
- Using constructors directly avoids duplicated identifiers such as:
46
+ Provide it and the environment becomes complete:
67
47
 
68
48
  ```ts
69
- Service<AuthService>()('authService')
70
- ```
71
-
72
- and prevents string-key collisions or typos.
49
+ const DatabaseLive = Layer.make(Database, () => new Database())
73
50
 
74
- Conceptually:
51
+ const AppLive = Layer.merge(DatabaseLive, UserRepositoryLive)
75
52
 
76
- ```text
77
- yield* AuthService
78
-
79
-
80
- ServiceRuntime
81
-
82
-
83
- ServiceResolver
84
-
85
-
86
- AuthService instance
53
+ const runtime = await Runtime.make(AppLive, backend)
87
54
  ```
88
55
 
89
- ## Layer
90
-
91
- A Layer describes which implementations form an application environment.
56
+ And the contract does not disappear after startup.
92
57
 
93
- It does **not** implement dependency resolution. That remains the responsibility of the configured backend.
58
+ A Runtime also knows which Services exist in its environment:
94
59
 
95
60
  ```ts
96
- import { Layer } from 'better-effect'
61
+ await runtime.run(() =>
62
+ Effect.gen(async function* () {
63
+ const database = yield* Database
97
64
 
98
- export const DatabaseLive = Layer.scoped(
99
- Database,
100
- async () => {
101
- const database = new Database()
102
-
103
- await database.connect()
104
-
105
- return database
106
- },
107
- (database) => database.close()
65
+ return Result.ok(database)
66
+ })
108
67
  )
109
-
110
- export const UserRepositoryLive = Layer.make(UserRepository, () => new UserRepository())
111
-
112
- export const AppLive = Layer.merge(DatabaseLive, UserRepositoryLive)
113
68
  ```
114
69
 
115
- The core Layer API intentionally stays small:
70
+ If a program asks that Runtime for a Service its environment does not provide, TypeScript rejects the call.
116
71
 
117
- ```ts
118
- Layer.make(Service, acquire)
119
- Layer.succeed(Service, instance)
120
- Layer.scoped(Service, acquire, release)
121
- Layer.merge(...layers)
122
- Layer.override(base, ...overrides)
72
+ ```text
73
+ yield* Database
74
+
75
+
76
+ program requires Database
77
+
78
+
79
+ Layer provides Database?
80
+
81
+ no ├──────────► TypeScript error
82
+
83
+ yes
84
+
85
+ Runtime can execute it
123
86
  ```
124
87
 
125
- ### Test environments
88
+ We call this **typechecked wiring**.
126
89
 
127
- Layers make implementation replacement explicit:
90
+ The Services your code uses, the implementations your Layers provide, and the programs your Runtime executes participate in the same type-level contract.
128
91
 
129
- ```ts
130
- const DatabaseTest = Layer.succeed(Database, new InMemoryDatabase())
92
+ ---
131
93
 
132
- const AppTest = Layer.override(AppLive, DatabaseTest)
133
- ```
94
+ ## Why better-effect?
134
95
 
135
- ## ITI adapter
96
+ `better-result` already gives TypeScript applications an excellent model for typed failures.
136
97
 
137
- `better-effect` does not depend on ITI in its core. ITI is just one possible backend.
98
+ But typed errors are only one part of a growing application.
138
99
 
139
- ```ts
140
- import { buildLayer } from 'better-effect'
100
+ Eventually you also need to answer:
141
101
 
142
- import { ItiLayerBackend } from 'better-effect/iti'
102
+ - What does this service depend on?
103
+ - Did the application provide every dependency?
104
+ - Can this program run in this environment?
105
+ - How do I replace implementations in tests?
106
+ - Who owns this database connection?
107
+ - When should this resource be released?
143
108
 
144
- const runtime = await buildLayer(AppLive, new ItiLayerBackend())
109
+ Those problems are often discovered through container errors, startup failures, test setup, or manual composition-root maintenance.
145
110
 
146
- try {
147
- await main()
148
- } finally {
149
- await runtime.dispose()
150
- }
151
- ```
111
+ Effect has powerful ideas for solving them.
152
112
 
153
- This keeps application code independent from the DI container.
113
+ `better-effect` explores a smaller path:
154
114
 
155
- A different backend can implement the same resolver/backend contracts without changing Services or Layers.
115
+ **keep `better-result`, Promises and normal TypeScript — borrow the architectural ideas that make dependencies and resource lifetimes easier to reason about.**
156
116
 
157
- ## Resource
117
+ ### Know your dependencies before runtime
158
118
 
159
- `Resource.acquireUseRelease()` handles local resource lifecycle while preserving typed `Result` errors.
119
+ Services can be requested directly:
160
120
 
161
121
  ```ts
162
- import { Resource } from 'better-effect'
122
+ const database = yield * Database
123
+ ```
163
124
 
164
- const result = await Resource.acquireUseRelease({
165
- name: 'transaction',
125
+ That access is also captured by the type system.
166
126
 
167
- acquire: () => database.begin(),
127
+ Layers know both what they provide and what their Services require. Incomplete environments can therefore fail during typechecking instead of application startup.
168
128
 
169
- use: (transaction) => executeCommand(transaction),
129
+ Runtime keeps that environment information and checks programs against it when they run.
170
130
 
171
- release: (transaction) => transaction.close()
172
- })
173
- ```
131
+ ### Compose application environments
174
132
 
175
- When `release` is omitted, `Resource` attempts to use the JavaScript explicit resource management protocol:
133
+ Layers describe implementations without making your application code depend on a specific DI container.
176
134
 
177
135
  ```ts
178
- Symbol.asyncDispose
179
- Symbol.dispose
136
+ const AppLive = Layer.merge(DatabaseLive, UserRepositoryLive, AuthServiceLive)
180
137
  ```
181
138
 
182
- ### Error precedence
183
-
184
- If both `use` and `release` fail, the error produced by `use` is preserved.
139
+ Testing can replace implementations explicitly:
185
140
 
186
- The precedence is:
187
-
188
- ```text
189
- 1. use failure
190
- 2. release failure
191
- 3. successful use value
141
+ ```ts
142
+ const AppTest = Layer.override(AppLive, DatabaseTest)
192
143
  ```
193
144
 
194
- Acquisition exceptions, rejected promises, and unexpected failures are normalized through `better-result`.
145
+ The environment contract remains typed after the override.
195
146
 
196
- ## Service vs Layer vs Resource
147
+ ### Own resource lifetimes
197
148
 
198
- | Primitive | Responsibility |
199
- | --------------- | ----------------------------------------------------- |
200
- | `Service` | Request a contextual dependency |
201
- | `Layer` | Describe the implementations that form an environment |
202
- | `Resource` | Manage a resource local to one operation |
203
- | DI backend | Resolve, cache and dispose service instances |
204
- | `better-result` | Typed failures and generator control flow |
149
+ Some dependencies are values.
205
150
 
206
- ## Complete example
151
+ Others own connections, sessions, files or other resources.
207
152
 
208
- The repository contains a TODO API example under:
153
+ `Layer.scoped`, `Layer.scopedGen`, `Effect.acquireRelease`, `Effect.add` and `Scope` make their lifetime explicit.
209
154
 
210
- ```text
211
- examples/todo-api
155
+ ```ts
156
+ const DatabaseLive = Layer.scoped(
157
+ Database,
158
+ () => Database.connect(),
159
+ (database) => database.close()
160
+ )
212
161
  ```
213
162
 
214
- It demonstrates:
163
+ Runtime owns the application lifetime and safely releases scoped resources when that lifetime ends.
215
164
 
216
- - Bun HTTP server
217
- - SQLite in memory with `Bun.SQL`
218
- - user login
219
- - session authentication
220
- - TODO CRUD
221
- - `Service` dependency access
222
- - Layer composition
223
- - scoped database lifecycle
224
- - `Resource.acquireUseRelease()`
225
- - ITI as the DI backend
165
+ Resources acquired during an individual execution belong to that execution instead.
226
166
 
227
- Run it from the repository root:
167
+ ### Keep your runtime choices
228
168
 
229
- ```bash
230
- bun examples/todo-api/index.ts
231
- ```
169
+ `better-effect` is not a replacement implementation of Effect.
232
170
 
233
- ## Development
171
+ It does not introduce a fiber runtime, scheduler, streams, queues or a public `Effect<A, E, R>` abstraction.
234
172
 
235
- Install dependencies:
173
+ `Effect.gen` builds on `better-result` generator composition while carrying Service requirements through the TypeScript type system.
236
174
 
237
- ```bash
238
- bun install
239
- ```
175
+ Dependency resolution stays behind a pluggable backend.
240
176
 
241
- Run tests:
177
+ Your application can keep using ordinary Promises and existing libraries.
242
178
 
243
- ```bash
244
- bun test
245
- ```
179
+ ---
246
180
 
247
- Typecheck:
181
+ ## How it compares
248
182
 
249
- ```bash
250
- bun run typecheck
251
- ```
183
+ | | better-result | better-effect | Effect |
184
+ | ----------------------------- | ------------- | ------------------- | --------------- |
185
+ | Typed success/failure | ✓ | ✓ via better-result | ✓ |
186
+ | Generator composition | ✓ | ✓ | ✓ |
187
+ | Contextual Services | — | ✓ | ✓ |
188
+ | Dependency requirements | — | ✓ | ✓ |
189
+ | Checked environments | — | ✓ | ✓ |
190
+ | Scoped resource lifetimes | — | ✓ | ✓ |
191
+ | Pluggable external DI backend | — | ✓ | different model |
192
+ | Fiber runtime | — | — | ✓ |
193
+ | Structured concurrency | — | — | ✓ |
194
+ | Streams / queues / schedules | — | — | ✓ |
195
+ | Full effect ecosystem | — | — | ✓ |
252
196
 
253
- Run the full quality gate:
197
+ ### Choose `better-result`
254
198
 
255
- ```bash
256
- bun run check
257
- ```
199
+ When typed error handling and Result composition are enough.
258
200
 
259
- The project uses:
201
+ ### Add `better-effect`
260
202
 
261
- - Bun as package manager and test runner
262
- - TypeScript
263
- - tsdown for library builds
264
- - Oxlint
265
- - Oxfmt
266
- - publint
203
+ When your Result-based application also needs contextual Services, typechecked application wiring, composable environments, or resource lifetime management.
267
204
 
268
- ## Design principles
205
+ ### Choose Effect
269
206
 
270
- ### Keep the core small
207
+ When you want a complete effect system and its runtime, concurrency model, dependency model, resource management and broader ecosystem.
271
208
 
272
- `better-effect` should not grow into a second Effect runtime.
209
+ `better-effect` is inspired by some of those ideas. It is intentionally not a reimplementation of the whole system.
273
210
 
274
- The core intentionally does not implement:
211
+ ---
275
212
 
276
- - fibers
277
- - schedules
278
- - streams
279
- - queues
280
- - a dependency graph runtime
281
- - a custom DI container
282
- - a custom Context
283
- - a custom Scope runtime
284
- - `Effect<A, E, R>`
213
+ ## Core ideas
285
214
 
286
- ### Delegate instead of rebuilding
215
+ ### Typechecked wiring
287
216
 
288
- Dependency resolution, caching and container lifecycle belong to DI backends.
217
+ **Service requirements Layer completeness Runtime validation**
289
218
 
290
- `better-effect` supplies the protocol and composition primitives.
219
+ Use a Service and its requirement follows the program.
291
220
 
292
- ### Preserve inference at public boundaries
221
+ Build an incomplete environment and TypeScript tells you what is missing.
293
222
 
294
- Type safety is part of the API.
223
+ Run a program against an incompatible Runtime and the mismatch remains visible at compile time.
295
224
 
296
- For example:
225
+ ### Composable environments
297
226
 
298
- ```ts
299
- const auth = yield * AuthService
300
- // AuthService
301
- ```
227
+ **Layer → merge → override → DI backend**
302
228
 
303
- and:
229
+ Describe application implementations independently from the container responsible for resolving them.
304
230
 
305
- ```ts
306
- const database = await ServiceRuntime.resolve(Database)
307
- // Database
308
- ```
231
+ Compose production environments and replace selected implementations for tests.
309
232
 
310
- must preserve exact instance types.
233
+ ### Scoped lifetimes
311
234
 
312
- ### Type erasure stays internal
235
+ **Scope scoped Layers → acquire/release → graceful Runtime disposal**
313
236
 
314
- Layers may store heterogeneous providers internally using erased types.
237
+ Make ownership explicit for resources that need cleanup.
315
238
 
316
- The public constructors (`Layer.make`, `Layer.succeed`, `Layer.scoped`) are responsible for preserving the relationship between a Service token and its instance type.
239
+ Application resources live with the Runtime. Execution resources live with the execution.
317
240
 
318
- ## Current scope
241
+ ### better-result underneath
319
242
 
320
- The project is intentionally small and experimental.
243
+ **Result Result.gen Effect.gen pipe**
321
244
 
322
- The initial scope is:
245
+ Keep `better-result` as the source of truth for typed successes, failures, short-circuiting
246
+ and generator control flow. `Effect.gen` delegates to `Result.gen`; it adds only the
247
+ phantom Service requirements that TypeScript needs to check the application environment.
248
+ At runtime, an `EffectResult` is still a `better-result` Result; the requirements exist
249
+ only in the type.
323
250
 
324
- ```text
325
- Service
326
- Layer
327
- Resource
328
- DI adapters
329
- better-result integration
330
- ```
251
+ For a linear workflow, `pipe` composes the same kind of program without introducing a
252
+ second Result model or a lazy Effect runtime:
331
253
 
332
- New abstractions should only be added when they solve a concrete problem without duplicating responsibilities already handled well by another library.
254
+ ```ts
255
+ import { Effect, pipe } from 'better-effect'
256
+
257
+ const program = pipe(
258
+ findUser(id),
259
+ Effect.map((user: User) => user.email),
260
+ Effect.andThen(loadPermissions),
261
+ Effect.mapError((cause: LoadUserError | PermissionError) => new ApplicationError({ cause }))
262
+ )
263
+ ```
333
264
 
334
- ## License
265
+ The combinators keep the `better-result` semantics: `Effect.map` changes the success
266
+ type, `Effect.mapError` changes the error type, and `Effect.andThen` only calls the next
267
+ step after an `Ok`. The pipeline carries the requirements of every step, so Runtime
268
+ still rejects it when its Layer does not provide every required Service.
335
269
 
336
- MIT
270
+ Use `Effect.gen` for larger workflows with several intermediate values, branches or
271
+ procedural logic. Use `pipe` for concise, linear composition; both are ways to compose
272
+ `better-result` programs while keeping dependency checking in the `better-effect` layer.
@@ -1,4 +1,4 @@
1
- import { r as LayerProvider, s as AnyServiceToken, t as LayerBackend } from "../backend-CNAls62W.mjs";
1
+ import { V as AnyServiceToken, t as LayerBackend, v as LayerProvider } from "../index-BYQKfyeJ.mjs";
2
2
  //#region src/adapters/iti.d.ts
3
3
  declare class ItiLayerBackend implements LayerBackend {
4
4
  private container;
@@ -1 +1 @@
1
- {"version":3,"file":"iti.d.mts","names":[],"sources":["../../src/adapters/iti.ts"],"mappings":";;cAMa,2BAA2B;UAC9B;mBAES;mBAEA;UAET;UAEA;EAgBR,SAAS,UAAU;EAsBnB,QAAQ,UAAU,iBAAiB,OAAO,IAAI,aAAa,KAAK,YAAY,aAAa;EAUnF,cAAc"}
1
+ {"version":3,"file":"iti.d.mts","names":[],"sources":["../../src/adapters/iti.ts"],"mappings":";;cAMa,2BAA2B;UAC9B;mBAES;mBAEA;UAET;UAEA;EAgBR,SAAS,UAAU;EAgBnB,QAAQ,UAAU,iBAAiB,OAAO,IAAI,aAAa,KAAK,YAAY,aAAa;EAUnF,cAAc"}
@@ -1,4 +1,4 @@
1
- import { n as DuplicateServiceError, o as ServiceNotFoundError } from "../errors-CnvKqBpb.mjs";
1
+ import { n as DuplicateServiceError, o as ServiceNotFoundError } from "../errors-DlHCwICc.mjs";
2
2
  import { createContainer } from "iti";
3
3
  //#region src/adapters/iti.ts
4
4
  var ItiLayerBackend = class {
@@ -18,7 +18,6 @@ var ItiLayerBackend = class {
18
18
  if (this.registered.has(token)) throw new DuplicateServiceError(token);
19
19
  const key = this.keyFor(token);
20
20
  this.container = this.container.add({ [key]: provider.acquire });
21
- if (provider.release) this.container = this.container.addDisposer({ [key]: provider.release });
22
21
  this.registered.add(token);
23
22
  }
24
23
  resolve(token) {
@@ -1 +1 @@
1
- {"version":3,"file":"iti.mjs","names":[],"sources":["../../src/adapters/iti.ts"],"sourcesContent":["import { createContainer } from 'iti'\n\nimport { DuplicateServiceError, type LayerBackend, type LayerProvider } from '../layer'\n\nimport { ServiceNotFoundError, type AnyServiceToken } from '../service'\n\nexport class ItiLayerBackend implements LayerBackend {\n private container: any = createContainer()\n\n private readonly keys = new WeakMap<AnyServiceToken, string>()\n\n private readonly registered = new WeakSet<AnyServiceToken>()\n\n private nextId = 0\n\n private keyFor(token: AnyServiceToken): string {\n const existing = this.keys.get(token)\n\n if (existing) {\n return existing\n }\n\n const name = token.name || 'Service'\n\n const key = `better-effect:${name}:${this.nextId++}`\n\n this.keys.set(token, key)\n\n return key\n }\n\n register(provider: LayerProvider): void {\n const token = provider.service\n\n if (this.registered.has(token)) {\n throw new DuplicateServiceError(token)\n }\n\n const key = this.keyFor(token)\n\n this.container = this.container.add({\n [key]: provider.acquire\n })\n\n if (provider.release) {\n this.container = this.container.addDisposer({\n [key]: provider.release\n })\n }\n\n this.registered.add(token)\n }\n\n resolve<T extends AnyServiceToken>(token: T): InstanceType<T> | PromiseLike<InstanceType<T>> {\n if (!this.registered.has(token)) {\n throw new ServiceNotFoundError(token)\n }\n\n const key = this.keyFor(token)\n\n return this.container.get(key) as InstanceType<T> | PromiseLike<InstanceType<T>>\n }\n\n async disposeAll(): Promise<void> {\n await this.container.disposeAll()\n }\n}\n"],"mappings":";;;AAMA,IAAa,kBAAb,MAAqD;CACnD,YAAyB,gBAAgB;CAEzC,uBAAwB,IAAI,QAAiC;CAE7D,6BAA8B,IAAI,QAAyB;CAE3D,SAAiB;CAEjB,OAAe,OAAgC;EAC7C,MAAM,WAAW,KAAK,KAAK,IAAI,KAAK;EAEpC,IAAI,UACF,OAAO;EAKT,MAAM,MAAM,iBAFC,MAAM,QAAQ,UAEO,GAAG,KAAK;EAE1C,KAAK,KAAK,IAAI,OAAO,GAAG;EAExB,OAAO;CACT;CAEA,SAAS,UAA+B;EACtC,MAAM,QAAQ,SAAS;EAEvB,IAAI,KAAK,WAAW,IAAI,KAAK,GAC3B,MAAM,IAAI,sBAAsB,KAAK;EAGvC,MAAM,MAAM,KAAK,OAAO,KAAK;EAE7B,KAAK,YAAY,KAAK,UAAU,IAAI,GACjC,MAAM,SAAS,QAClB,CAAC;EAED,IAAI,SAAS,SACX,KAAK,YAAY,KAAK,UAAU,YAAY,GACzC,MAAM,SAAS,QAClB,CAAC;EAGH,KAAK,WAAW,IAAI,KAAK;CAC3B;CAEA,QAAmC,OAA0D;EAC3F,IAAI,CAAC,KAAK,WAAW,IAAI,KAAK,GAC5B,MAAM,IAAI,qBAAqB,KAAK;EAGtC,MAAM,MAAM,KAAK,OAAO,KAAK;EAE7B,OAAO,KAAK,UAAU,IAAI,GAAG;CAC/B;CAEA,MAAM,aAA4B;EAChC,MAAM,KAAK,UAAU,WAAW;CAClC;AACF"}
1
+ {"version":3,"file":"iti.mjs","names":[],"sources":["../../src/adapters/iti.ts"],"sourcesContent":["import { createContainer } from 'iti'\n\nimport { DuplicateServiceError, type LayerBackend, type LayerProvider } from '../layer'\n\nimport { ServiceNotFoundError, type AnyServiceToken } from '../service'\n\nexport class ItiLayerBackend implements LayerBackend {\n private container: any = createContainer()\n\n private readonly keys = new WeakMap<AnyServiceToken, string>()\n\n private readonly registered = new WeakSet<AnyServiceToken>()\n\n private nextId = 0\n\n private keyFor(token: AnyServiceToken): string {\n const existing = this.keys.get(token)\n\n if (existing) {\n return existing\n }\n\n const name = token.name || 'Service'\n\n const key = `better-effect:${name}:${this.nextId++}`\n\n this.keys.set(token, key)\n\n return key\n }\n\n register(provider: LayerProvider): void {\n const token = provider.service\n\n if (this.registered.has(token)) {\n throw new DuplicateServiceError(token)\n }\n\n const key = this.keyFor(token)\n\n this.container = this.container.add({\n [key]: provider.acquire\n })\n\n this.registered.add(token)\n }\n\n resolve<T extends AnyServiceToken>(token: T): InstanceType<T> | PromiseLike<InstanceType<T>> {\n if (!this.registered.has(token)) {\n throw new ServiceNotFoundError(token)\n }\n\n const key = this.keyFor(token)\n\n return this.container.get(key) as InstanceType<T> | PromiseLike<InstanceType<T>>\n }\n\n async disposeAll(): Promise<void> {\n await this.container.disposeAll()\n }\n}\n"],"mappings":";;;AAMA,IAAa,kBAAb,MAAqD;CACnD,YAAyB,gBAAgB;CAEzC,uBAAwB,IAAI,QAAiC;CAE7D,6BAA8B,IAAI,QAAyB;CAE3D,SAAiB;CAEjB,OAAe,OAAgC;EAC7C,MAAM,WAAW,KAAK,KAAK,IAAI,KAAK;EAEpC,IAAI,UACF,OAAO;EAKT,MAAM,MAAM,iBAFC,MAAM,QAAQ,UAEO,GAAG,KAAK;EAE1C,KAAK,KAAK,IAAI,OAAO,GAAG;EAExB,OAAO;CACT;CAEA,SAAS,UAA+B;EACtC,MAAM,QAAQ,SAAS;EAEvB,IAAI,KAAK,WAAW,IAAI,KAAK,GAC3B,MAAM,IAAI,sBAAsB,KAAK;EAGvC,MAAM,MAAM,KAAK,OAAO,KAAK;EAE7B,KAAK,YAAY,KAAK,UAAU,IAAI,GACjC,MAAM,SAAS,QAClB,CAAC;EAED,KAAK,WAAW,IAAI,KAAK;CAC3B;CAEA,QAAmC,OAA0D;EAC3F,IAAI,CAAC,KAAK,WAAW,IAAI,KAAK,GAC5B,MAAM,IAAI,qBAAqB,KAAK;EAGtC,MAAM,MAAM,KAAK,OAAO,KAAK;EAE7B,OAAO,KAAK,UAAU,IAAI,GAAG;CAC/B;CAEA,MAAM,aAA4B;EAChC,MAAM,KAAK,UAAU,WAAW;CAClC;AACF"}
@@ -51,6 +51,10 @@ var LayerGeneratorYieldError = class extends Error {
51
51
  this.name = "LayerGeneratorYieldError";
52
52
  }
53
53
  };
54
+ /**
55
+ * @deprecated The public managed handle is `Runtime`; this error remains for
56
+ * compatibility with low-level Layer integrations.
57
+ */
54
58
  var BuiltLayerDisposedError = class extends Error {
55
59
  constructor() {
56
60
  super("Cannot run a program using a disposed Layer");
@@ -60,4 +64,4 @@ var BuiltLayerDisposedError = class extends Error {
60
64
  //#endregion
61
65
  export { LayerRegistrationError as a, LayerGeneratorYieldError as i, DuplicateServiceError as n, ServiceNotFoundError as o, LayerDisposeError as r, ServiceRuntimeNotConfiguredError as s, BuiltLayerDisposedError as t };
62
66
 
63
- //# sourceMappingURL=errors-CnvKqBpb.mjs.map
67
+ //# sourceMappingURL=errors-DlHCwICc.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors-CnvKqBpb.mjs","names":[],"sources":["../src/service/errors.ts","../src/layer/errors.ts"],"sourcesContent":["import type { AnyServiceToken } from './types'\n\nexport class ServiceRuntimeNotConfiguredError extends Error {\n constructor() {\n super('No ServiceResolver is available in the current runtime context')\n\n this.name = 'ServiceRuntimeNotConfiguredError'\n }\n}\n\nexport class ServiceNotFoundError extends Error {\n constructor(readonly service: AnyServiceToken) {\n super(`Service \"${service.name}\" was not provided`)\n\n this.name = 'ServiceNotFoundError'\n }\n}\n","import type { ServiceClass } from '../service'\n\nexport class DuplicateServiceError extends Error {\n constructor(readonly service: ServiceClass<any>) {\n super(`Duplicate service \"${service.name}\"`)\n\n this.name = 'DuplicateServiceError'\n }\n}\n\nexport class LayerRegistrationError extends Error {\n constructor(\n readonly service: ServiceClass<any> | undefined,\n readonly registrationCause: unknown,\n readonly cleanupCause?: unknown\n ) {\n super(service ? `Failed to register service \"${service.name}\"` : 'Failed to build Layer', {\n cause: registrationCause\n })\n\n this.name = 'LayerRegistrationError'\n }\n}\n\nexport class LayerDisposeError extends Error {\n constructor(readonly causes: readonly unknown[]) {\n super(`Failed to dispose Layer (${causes.length} error${causes.length === 1 ? '' : 's'})`)\n\n this.name = 'LayerDisposeError'\n }\n}\n\nexport class LayerGeneratorYieldError extends Error {\n constructor(readonly service: ServiceClass<any>) {\n super(`Layer.gen(\"${service.name}\") yielded an unsupported value`)\n\n this.name = 'LayerGeneratorYieldError'\n }\n}\n\nexport class BuiltLayerDisposedError extends Error {\n constructor() {\n super('Cannot run a program using a disposed Layer')\n\n this.name = 'BuiltLayerDisposedError'\n }\n}\n"],"mappings":";AAEA,IAAa,mCAAb,cAAsD,MAAM;CAC1D,cAAc;EACZ,MAAM,gEAAgE;EAEtE,KAAK,OAAO;CACd;AACF;AAEA,IAAa,uBAAb,cAA0C,MAAM;CACzB;CAArB,YAAY,SAAmC;EAC7C,MAAM,YAAY,QAAQ,KAAK,mBAAmB;EAD/B,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;;;ACdA,IAAa,wBAAb,cAA2C,MAAM;CAC1B;CAArB,YAAY,SAAqC;EAC/C,MAAM,sBAAsB,QAAQ,KAAK,EAAE;EADxB,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,yBAAb,cAA4C,MAAM;CAErC;CACA;CACA;CAHX,YACE,SACA,mBACA,cACA;EACA,MAAM,UAAU,+BAA+B,QAAQ,KAAK,KAAK,yBAAyB,EACxF,OAAO,kBACT,CAAC;EANQ,KAAA,UAAA;EACA,KAAA,oBAAA;EACA,KAAA,eAAA;EAMT,KAAK,OAAO;CACd;AACF;AAEA,IAAa,oBAAb,cAAuC,MAAM;CACtB;CAArB,YAAY,QAAqC;EAC/C,MAAM,4BAA4B,OAAO,OAAO,QAAQ,OAAO,WAAW,IAAI,KAAK,IAAI,EAAE;EADtE,KAAA,SAAA;EAGnB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,2BAAb,cAA8C,MAAM;CAC7B;CAArB,YAAY,SAAqC;EAC/C,MAAM,cAAc,QAAQ,KAAK,gCAAgC;EAD9C,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,0BAAb,cAA6C,MAAM;CACjD,cAAc;EACZ,MAAM,6CAA6C;EAEnD,KAAK,OAAO;CACd;AACF"}
1
+ {"version":3,"file":"errors-DlHCwICc.mjs","names":[],"sources":["../src/service/errors.ts","../src/layer/errors.ts"],"sourcesContent":["import type { AnyServiceToken } from './types'\n\nexport class ServiceRuntimeNotConfiguredError extends Error {\n constructor() {\n super('No ServiceResolver is available in the current runtime context')\n\n this.name = 'ServiceRuntimeNotConfiguredError'\n }\n}\n\nexport class ServiceNotFoundError extends Error {\n constructor(readonly service: AnyServiceToken) {\n super(`Service \"${service.name}\" was not provided`)\n\n this.name = 'ServiceNotFoundError'\n }\n}\n","import type { ServiceClass } from '../service'\n\nexport class DuplicateServiceError extends Error {\n constructor(readonly service: ServiceClass<any>) {\n super(`Duplicate service \"${service.name}\"`)\n\n this.name = 'DuplicateServiceError'\n }\n}\n\nexport class LayerRegistrationError extends Error {\n constructor(\n readonly service: ServiceClass<any> | undefined,\n readonly registrationCause: unknown,\n readonly cleanupCause?: unknown\n ) {\n super(service ? `Failed to register service \"${service.name}\"` : 'Failed to build Layer', {\n cause: registrationCause\n })\n\n this.name = 'LayerRegistrationError'\n }\n}\n\nexport class LayerDisposeError extends Error {\n constructor(readonly causes: readonly unknown[]) {\n super(`Failed to dispose Layer (${causes.length} error${causes.length === 1 ? '' : 's'})`)\n\n this.name = 'LayerDisposeError'\n }\n}\n\nexport class LayerGeneratorYieldError extends Error {\n constructor(readonly service: ServiceClass<any>) {\n super(`Layer.gen(\"${service.name}\") yielded an unsupported value`)\n\n this.name = 'LayerGeneratorYieldError'\n }\n}\n\n/**\n * @deprecated The public managed handle is `Runtime`; this error remains for\n * compatibility with low-level Layer integrations.\n */\nexport class BuiltLayerDisposedError extends Error {\n constructor() {\n super('Cannot run a program using a disposed Layer')\n\n this.name = 'BuiltLayerDisposedError'\n }\n}\n"],"mappings":";AAEA,IAAa,mCAAb,cAAsD,MAAM;CAC1D,cAAc;EACZ,MAAM,gEAAgE;EAEtE,KAAK,OAAO;CACd;AACF;AAEA,IAAa,uBAAb,cAA0C,MAAM;CACzB;CAArB,YAAY,SAAmC;EAC7C,MAAM,YAAY,QAAQ,KAAK,mBAAmB;EAD/B,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;;;ACdA,IAAa,wBAAb,cAA2C,MAAM;CAC1B;CAArB,YAAY,SAAqC;EAC/C,MAAM,sBAAsB,QAAQ,KAAK,EAAE;EADxB,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,yBAAb,cAA4C,MAAM;CAErC;CACA;CACA;CAHX,YACE,SACA,mBACA,cACA;EACA,MAAM,UAAU,+BAA+B,QAAQ,KAAK,KAAK,yBAAyB,EACxF,OAAO,kBACT,CAAC;EANQ,KAAA,UAAA;EACA,KAAA,oBAAA;EACA,KAAA,eAAA;EAMT,KAAK,OAAO;CACd;AACF;AAEA,IAAa,oBAAb,cAAuC,MAAM;CACtB;CAArB,YAAY,QAAqC;EAC/C,MAAM,4BAA4B,OAAO,OAAO,QAAQ,OAAO,WAAW,IAAI,KAAK,IAAI,EAAE;EADtE,KAAA,SAAA;EAGnB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,2BAAb,cAA8C,MAAM;CAC7B;CAArB,YAAY,SAAqC;EAC/C,MAAM,cAAc,QAAQ,KAAK,gCAAgC;EAD9C,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;;;;;AAMA,IAAa,0BAAb,cAA6C,MAAM;CACjD,cAAc;EACZ,MAAM,6CAA6C;EAEnD,KAAK,OAAO;CACd;AACF"}