better-effect 0.4.0 → 0.6.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
@@ -16,13 +16,13 @@ bun add better-effect better-result
16
16
  import { Result } from 'better-result'
17
17
  import { Effect, Layer, Runtime, Service } from 'better-effect'
18
18
 
19
- class Database extends Service<Database>() {
19
+ class Database extends Service<Database>()('Database') {
20
20
  findUser(id: string) {
21
21
  // ...
22
22
  }
23
23
  }
24
24
 
25
- class UserRepository extends Service<UserRepository>() {
25
+ class UserRepository extends Service<UserRepository>()('UserRepository') {
26
26
  findUser(id: string) {
27
27
  return Effect.gen(async function* () {
28
28
  const database = yield* Database
@@ -32,21 +32,63 @@ class UserRepository extends Service<UserRepository>() {
32
32
  }
33
33
  }
34
34
 
35
- const UserRepositoryLive = Layer.make(UserRepository, () => new UserRepository())
35
+ const UserRepositoryLive = Layer.make(UserRepository)
36
36
 
37
37
  await Runtime.make(UserRepositoryLive, backend)
38
38
  // ^^^^^^^^^^^^^^^^^^
39
39
  // Type error: Database is required but not provided
40
40
  ```
41
41
 
42
- `UserRepository` used `Database`, so `Database` became part of its environment requirements.
42
+ The explicit self type keeps `yield*` inference exact, while the non-empty
43
+ literal is the Service's stable logical identity. Services with identical
44
+ methods but different tags are different dependencies; use a namespaced tag
45
+ such as `@acme/Database` when identities must be shared across packages.
43
46
 
44
- No dependency list was written manually.
47
+ `UserRepository` used `Database`, so `Database` became part of its environment requirements:
48
+
49
+ ```ts
50
+ type FindUser = Awaited<ReturnType<UserRepository['findUser']>>
51
+ // Effect<User, never, Database>
52
+ ```
53
+
54
+ `Effect<A, E, R>` is a type-only facade over a `better-result` Result, not an Effect TS
55
+ instruction tree. Constructors remain the handles used by `yield*`, Layers and resolver backends;
56
+ the public requirement `R` is a union of tagged Service instances. No dependency list was written
57
+ manually.
58
+
59
+ Services can also describe a contract without requiring a class instance. Use the
60
+ static `of` helper to type-check a structural implementation; it returns the same
61
+ object unchanged at runtime:
62
+
63
+ ```ts
64
+ class Authorization extends Service<Authorization>()('Authorization') {
65
+ declare readonly authorize: (token: string) => Promise<boolean>
66
+ }
67
+
68
+ const authorization = Authorization.of({
69
+ authorize: async (token) => token.length > 0
70
+ })
71
+
72
+ const AuthorizationLive = Layer.succeed(Authorization, authorization)
73
+ ```
74
+
75
+ `Authorization.of(...)` does not call a constructor or make the result an
76
+ `instanceof Authorization`. For services with constructors, private fields or
77
+ other runtime invariants, use `new Authorization(...)` instead.
78
+
79
+ Service tokens themselves are always declared through `Service<Self>()(tag)`.
80
+ Every instance carries a required, declaration-only `ServiceIdentity<Tag>`; no
81
+ identity property exists at runtime. `Service.Contract<Authorization>` projects
82
+ the marker-free implementation shape accepted by `Service.of` and all Layer
83
+ provider APIs. Those boundaries return or provide the branded Service type
84
+ without modifying the implementation object. `Service.of(...)` does not create
85
+ an alternate token, so the instance contract stays tied to the constructor used
86
+ by Layers and resolver backends.
45
87
 
46
88
  Provide it and the environment becomes complete:
47
89
 
48
90
  ```ts
49
- const DatabaseLive = Layer.make(Database, () => new Database())
91
+ const DatabaseLive = Layer.make(Database)
50
92
 
51
93
  const AppLive = Layer.merge(DatabaseLive, UserRepositoryLive)
52
94
 
@@ -89,6 +131,40 @@ We call this **typechecked wiring**.
89
131
 
90
132
  The Services your code uses, the implementations your Layers provide, and the programs your Runtime executes participate in the same type-level contract.
91
133
 
134
+ A Layer's public type is `Layer<Provided, Required>`. `Provided` is the Service
135
+ instance union produced by the Layer and `Required` is only the external
136
+ requirement union left after composition. Preserve inferred Layers when possible;
137
+ use `satisfies Layer<Provided, Required>` when checking an application boundary
138
+ without erasing provider provenance.
139
+
140
+ Generic infrastructure that intentionally erases this metadata can use the
141
+ explicit `Layer.Any` sentinel, including for an empty Layer. Bare Layers,
142
+ partial-`any` shapes and concrete unions such as `Layer<A> | Layer<B>` are not
143
+ implicit unchecked boundaries.
144
+
145
+ ### Discover type helpers from their API
146
+
147
+ Public type helpers are also grouped under the runtime API they describe:
148
+
149
+ ```ts
150
+ import type { Effect, Layer, Runtime, Scope, Service } from 'better-effect'
151
+
152
+ type Program = ReturnType<UserRepository['findUser']>
153
+ type Success = Effect.Success<Program>
154
+ type Failure = Effect.Error<Program>
155
+ type Dependencies = Effect.Requirements<Program>
156
+ type Services = Layer.Provided<typeof AppLive>
157
+ type AppRuntime = Runtime.For<typeof AppLive>
158
+ type DatabaseTag = Service.Tag<Database> // 'Database'
159
+ type DatabaseToken = Service.TokenOf<Database> // Service.Token<'Database', Database>
160
+ type Outcome = Scope.Outcome
161
+ ```
162
+
163
+ These are declaration-only aliases and add nothing to the JavaScript bundle.
164
+ The associated `Layer` helpers are intentionally namespaced; use
165
+ `Layer.Provided`, `Layer.Required`, `Layer.Complete` and `Layer.Any` rather than
166
+ low-level provider metadata names.
167
+
92
168
  ---
93
169
 
94
170
  ## Why better-effect?
@@ -168,9 +244,11 @@ Resources acquired during an individual execution belong to that execution inste
168
244
 
169
245
  `better-effect` is not a replacement implementation of Effect.
170
246
 
171
- It does not introduce a fiber runtime, scheduler, streams, queues or a public `Effect<A, E, R>` abstraction.
247
+ It does not introduce a fiber runtime, scheduler, streams, queues or a lazy runtime instruction tree.
172
248
 
173
- `Effect.gen` builds on `better-result` generator composition while carrying Service requirements through the TypeScript type system.
249
+ Its public `Effect<A, E, R>` is only a type-level Result facade. `Effect.gen` builds on
250
+ `better-result` generator composition while carrying Service instance requirements through the
251
+ TypeScript type system.
174
252
 
175
253
  Dependency resolution stays behind a pluggable backend.
176
254
 
@@ -245,8 +323,9 @@ Application resources live with the Runtime. Execution resources live with the e
245
323
  Keep `better-result` as the source of truth for typed successes, failures, short-circuiting
246
324
  and generator control flow. `Effect.gen` delegates to `Result.gen`; it adds only the
247
325
  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.
326
+ At runtime, an `Effect<A, E, R>` is still a `better-result` Result; the requirements exist
327
+ only in the type. `Effect.Requirements`, `Layer.Provided`, `Layer.Required` and
328
+ `Runtime.For` expose tagged Service instance unions.
250
329
 
251
330
  For a linear workflow, `pipe` composes the same kind of program without introducing a
252
331
  second Result model or a lazy Effect runtime:
@@ -264,7 +343,9 @@ const program = pipe(
264
343
 
265
344
  The combinators keep the `better-result` semantics: `Effect.map` changes the success
266
345
  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
346
+ step after an `Ok`. Use `Effect.andThenAsync` when the next operation returns a
347
+ `Promise<Result>`; it always returns a Promise, including when the source is synchronous
348
+ or already an `Err`. The pipeline carries the requirements of every step, so Runtime
268
349
  still rejects it when its Layer does not provide every required Service.
269
350
 
270
351
  Use `Effect.gen` for larger workflows with several intermediate values, branches or
@@ -1,13 +1,21 @@
1
- import { V as AnyServiceToken, t as LayerBackend, v as LayerProvider } from "../index-BYQKfyeJ.mjs";
1
+ import { d as LayerRegistration, t as LayerBackend, z as AnyServiceToken } from "../index-DMfjhNR_.mjs";
2
2
  //#region src/adapters/iti.d.ts
3
+ /**
4
+ * ITI-backed Layer backend.
5
+ *
6
+ * Install `iti` as the optional peer dependency and pass an instance to
7
+ * `Runtime.make` when using ITI's container implementation.
8
+ */
3
9
  declare class ItiLayerBackend implements LayerBackend {
4
10
  private container;
5
11
  private readonly keys;
6
12
  private readonly registered;
7
- private nextId;
8
13
  private keyFor;
9
- register(provider: LayerProvider): void;
14
+ /** Register a Layer provider under its deterministic Service-tag key. */
15
+ register(registration: LayerRegistration): void;
16
+ /** Resolve a registered Service through the ITI container. */
10
17
  resolve<T extends AnyServiceToken>(token: T): InstanceType<T> | PromiseLike<InstanceType<T>>;
18
+ /** Dispose all ITI-managed provider instances. */
11
19
  disposeAll(): Promise<void>;
12
20
  }
13
21
  //#endregion
@@ -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;EAgBnB,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":";;;;;;;;cAsBa,2BAA2B;UAC9B;mBAES;mBAEA;UAET;;EAgBR,SAAS,cAAc;;EAuBvB,QAAQ,UAAU,iBAAiB,OAAO,IAAI,aAAa,KAAK,YAAY,aAAa;;EAyBnF,cAAc"}
@@ -1,30 +1,51 @@
1
- import { n as DuplicateServiceError, o as ServiceNotFoundError } from "../errors-DlHCwICc.mjs";
1
+ import { a as ServiceTagCollisionError, o as ServiceNotFoundError, t as DuplicateServiceError } from "../errors-GR3K_nRu.mjs";
2
+ import { t as isPromiseLike } from "../runtime-CDcCF5cb.mjs";
3
+ import { t as assertServiceCompatibility } from "../internal-identity-C6Awrc33.mjs";
2
4
  import { createContainer } from "iti";
3
5
  //#region src/adapters/iti.ts
6
+ /**
7
+ * ITI-backed Layer backend.
8
+ *
9
+ * Install `iti` as the optional peer dependency and pass an instance to
10
+ * `Runtime.make` when using ITI's container implementation.
11
+ */
4
12
  var ItiLayerBackend = class {
5
13
  container = createContainer();
6
- keys = /* @__PURE__ */ new WeakMap();
7
- registered = /* @__PURE__ */ new WeakSet();
8
- nextId = 0;
14
+ keys = /* @__PURE__ */ new Map();
15
+ registered = /* @__PURE__ */ new Map();
9
16
  keyFor(token) {
10
- const existing = this.keys.get(token);
17
+ const tag = token.serviceTag;
18
+ const existing = this.keys.get(tag);
11
19
  if (existing) return existing;
12
- const key = `better-effect:${token.name || "Service"}:${this.nextId++}`;
13
- this.keys.set(token, key);
20
+ const key = `better-effect:${tag}`;
21
+ this.keys.set(tag, key);
14
22
  return key;
15
23
  }
16
- register(provider) {
17
- const token = provider.service;
18
- if (this.registered.has(token)) throw new DuplicateServiceError(token);
24
+ /** Register a Layer provider under its deterministic Service-tag key. */
25
+ register(registration) {
26
+ const token = registration.service;
27
+ const tag = token.serviceTag;
28
+ const existing = this.registered.get(tag);
29
+ if (existing === token) throw new DuplicateServiceError(token);
30
+ if (existing) throw new ServiceTagCollisionError(existing, token);
19
31
  const key = this.keyFor(token);
20
- this.container = this.container.add({ [key]: provider.acquire });
21
- this.registered.add(token);
32
+ this.container = this.container.add({ [key]: registration.acquire });
33
+ this.registered.set(tag, token);
22
34
  }
35
+ /** Resolve a registered Service through the ITI container. */
23
36
  resolve(token) {
24
- if (!this.registered.has(token)) throw new ServiceNotFoundError(token);
37
+ const registered = this.registered.get(token.serviceTag);
38
+ if (registered === void 0) throw new ServiceNotFoundError(token);
25
39
  const key = this.keyFor(token);
26
- return this.container.get(key);
40
+ const resolved = this.container.get(key);
41
+ const validate = (instance) => {
42
+ assertServiceCompatibility(token, registered, instance);
43
+ return instance;
44
+ };
45
+ if (isPromiseLike(resolved)) return Promise.resolve(resolved).then(validate);
46
+ return validate(resolved);
27
47
  }
48
+ /** Dispose all ITI-managed provider instances. */
28
49
  async disposeAll() {
29
50
  await this.container.disposeAll();
30
51
  }
@@ -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 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"}
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 return Promise.resolve(resolved).then(validate)\n }\n\n return validate(resolved)\n }\n\n /** Dispose all ITI-managed provider instances. */\n async disposeAll(): Promise<void> {\n await this.container.disposeAll()\n }\n}\n"],"mappings":";;;;;;;;;;;AAsBA,IAAa,kBAAb,MAAqD;CACnD,YAAyB,gBAAgB;CAEzC,uBAAwB,IAAI,IAAoB;CAEhD,6BAA8B,IAAI,IAA6B;CAE/D,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,GACxB,OAAO,QAAQ,QAAQ,QAAQ,CAAC,CAAC,KAAK,QAAQ;EAGhD,OAAO,SAAS,QAAQ;CAC1B;;CAGA,MAAM,aAA4B;EAChC,MAAM,KAAK,UAAU,WAAW;CAClC;AACF"}
@@ -0,0 +1,74 @@
1
+ //#region src/service/errors.ts
2
+ /** Thrown when a Service is accessed without an active runtime resolver. */
3
+ var ServiceRuntimeNotConfiguredError = class extends Error {
4
+ constructor() {
5
+ super("No ServiceResolver is available in the current runtime context");
6
+ this.name = "ServiceRuntimeNotConfiguredError";
7
+ }
8
+ };
9
+ /** Thrown when a runtime has no provider for the requested Service tag. */
10
+ var ServiceNotFoundError = class extends Error {
11
+ service;
12
+ constructor(service) {
13
+ super(`Service "${service.serviceTag}" was not provided`);
14
+ this.service = service;
15
+ this.name = "ServiceNotFoundError";
16
+ }
17
+ };
18
+ //#endregion
19
+ //#region src/layer/errors.ts
20
+ /** Thrown when a Layer registers the same Service tag more than once. */
21
+ var DuplicateServiceError = class extends Error {
22
+ service;
23
+ constructor(service) {
24
+ super(`Duplicate service tag "${service.serviceTag}"`);
25
+ this.service = service;
26
+ this.name = "DuplicateServiceError";
27
+ }
28
+ };
29
+ /** Thrown when one Service tag is associated with incompatible constructors. */
30
+ var ServiceTagCollisionError = class extends Error {
31
+ existing;
32
+ incoming;
33
+ constructor(existing, incoming) {
34
+ super(`Service tag "${incoming.serviceTag}" is already associated with "${existing.name}" and cannot be associated with "${incoming.name}"`);
35
+ this.existing = existing;
36
+ this.incoming = incoming;
37
+ this.name = "ServiceTagCollisionError";
38
+ }
39
+ };
40
+ /** Thrown when a backend fails while registering a Layer provider. */
41
+ var LayerRegistrationError = class extends Error {
42
+ service;
43
+ registrationCause;
44
+ cleanupCause;
45
+ constructor(service, registrationCause, cleanupCause) {
46
+ super(service ? `Failed to register service "${service.serviceTag}"` : "Failed to build Layer", { cause: registrationCause });
47
+ this.service = service;
48
+ this.registrationCause = registrationCause;
49
+ this.cleanupCause = cleanupCause;
50
+ this.name = "LayerRegistrationError";
51
+ }
52
+ };
53
+ /** Thrown when one or more Layer-owned resources fail during disposal. */
54
+ var LayerDisposeError = class extends Error {
55
+ causes;
56
+ constructor(causes) {
57
+ super(`Failed to dispose Layer (${causes.length} error${causes.length === 1 ? "" : "s"})`);
58
+ this.causes = causes;
59
+ this.name = "LayerDisposeError";
60
+ }
61
+ };
62
+ /** Thrown when a Layer generator yields a value other than a Service requirement. */
63
+ var LayerGeneratorYieldError = class extends Error {
64
+ service;
65
+ constructor(service) {
66
+ super(`Layer.gen("${service.serviceTag}") yielded an unsupported value`);
67
+ this.service = service;
68
+ this.name = "LayerGeneratorYieldError";
69
+ }
70
+ };
71
+ //#endregion
72
+ export { ServiceTagCollisionError as a, LayerRegistrationError as i, LayerDisposeError as n, ServiceNotFoundError as o, LayerGeneratorYieldError as r, ServiceRuntimeNotConfiguredError as s, DuplicateServiceError as t };
73
+
74
+ //# sourceMappingURL=errors-GR3K_nRu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-GR3K_nRu.mjs","names":[],"sources":["../src/service/errors.ts","../src/layer/errors.ts"],"sourcesContent":["import type { AnyServiceToken } from './types'\n\n/** Thrown when a Service is accessed without an active runtime resolver. */\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\n/** Thrown when a runtime has no provider for the requested Service tag. */\nexport class ServiceNotFoundError extends Error {\n constructor(readonly service: AnyServiceToken) {\n super(`Service \"${service.serviceTag}\" was not provided`)\n\n this.name = 'ServiceNotFoundError'\n }\n}\n","import type { AnyServiceToken, ServiceClass } from '../service'\nimport type { ScopeOutcome } from '../scope'\n\ntype LayerCause = Extract<ScopeOutcome, { readonly status: 'failure' }>['cause']\n\n/** Thrown when a Layer registers the same Service tag more than once. */\nexport class DuplicateServiceError extends Error {\n constructor(readonly service: ServiceClass<any>) {\n super(`Duplicate service tag \"${service.serviceTag}\"`)\n\n this.name = 'DuplicateServiceError'\n }\n}\n\n/** Thrown when one Service tag is associated with incompatible constructors. */\nexport class ServiceTagCollisionError extends Error {\n constructor(\n readonly existing: AnyServiceToken,\n readonly incoming: AnyServiceToken\n ) {\n super(\n `Service tag \"${incoming.serviceTag}\" is already associated with \"${existing.name}\" ` +\n `and cannot be associated with \"${incoming.name}\"`\n )\n\n this.name = 'ServiceTagCollisionError'\n }\n}\n\n/** Thrown when a backend fails while registering a Layer provider. */\nexport class LayerRegistrationError extends Error {\n constructor(\n readonly service: ServiceClass<any> | undefined,\n readonly registrationCause: LayerCause,\n readonly cleanupCause?: LayerCause\n ) {\n super(\n service ? `Failed to register service \"${service.serviceTag}\"` : 'Failed to build Layer',\n {\n cause: registrationCause\n }\n )\n\n this.name = 'LayerRegistrationError'\n }\n}\n\n/** Thrown when one or more Layer-owned resources fail during disposal. */\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\n/** Thrown when a Layer generator yields a value other than a Service requirement. */\nexport class LayerGeneratorYieldError extends Error {\n constructor(readonly service: ServiceClass<any>) {\n super(`Layer.gen(\"${service.serviceTag}\") yielded an unsupported value`)\n\n this.name = 'LayerGeneratorYieldError'\n }\n}\n"],"mappings":";;AAGA,IAAa,mCAAb,cAAsD,MAAM;CAC1D,cAAc;EACZ,MAAM,gEAAgE;EAEtE,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,uBAAb,cAA0C,MAAM;CACzB;CAArB,YAAY,SAAmC;EAC7C,MAAM,YAAY,QAAQ,WAAW,mBAAmB;EADrC,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;;;;ACZA,IAAa,wBAAb,cAA2C,MAAM;CAC1B;CAArB,YAAY,SAAqC;EAC/C,MAAM,0BAA0B,QAAQ,WAAW,EAAE;EADlC,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,2BAAb,cAA8C,MAAM;CAEvC;CACA;CAFX,YACE,UACA,UACA;EACA,MACE,gBAAgB,SAAS,WAAW,gCAAgC,SAAS,KAAK,mCAC9C,SAAS,KAAK,EACpD;EANS,KAAA,WAAA;EACA,KAAA,WAAA;EAOT,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,yBAAb,cAA4C,MAAM;CAErC;CACA;CACA;CAHX,YACE,SACA,mBACA,cACA;EACA,MACE,UAAU,+BAA+B,QAAQ,WAAW,KAAK,yBACjE,EACE,OAAO,kBACT,CACF;EATS,KAAA,UAAA;EACA,KAAA,oBAAA;EACA,KAAA,eAAA;EAST,KAAK,OAAO;CACd;AACF;;AAGA,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;;AAGA,IAAa,2BAAb,cAA8C,MAAM;CAC7B;CAArB,YAAY,SAAqC;EAC/C,MAAM,cAAc,QAAQ,WAAW,gCAAgC;EADpD,KAAA,UAAA;EAGnB,KAAK,OAAO;CACd;AACF"}