@shivaedev/service 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0 - 2026-10-30
4
+
5
+ ### Added
6
+
7
+ - Jobs services share one scoped pg-boss client through the Effect environment. Registration, worker and producer Layers use the same connection and pool settings.
8
+ - Service definitions accept marked generic methods alongside declared dependencies. Generic signatures retain their caller requirements unchanged; initialization can capture declared dependencies as private state.
9
+
10
+ ### Breaking
11
+
12
+ - Move connection, pool, client factory, cache key and stop options from each `Jobs.layer` call into one `pgBossLayer` from `@shivaedev/jobs/server/service.ts`. Supply `connectionString` as `Redacted<string>` and provide that Layer to the merged jobs services. Keep only `jobs` and `onError` in `Jobs.layer`.
13
+ - Call `jobs.health()` instead of yielding `jobs.health`. Custom jobs service implementations must expose health as a method. Admin's built-in jobs handlers call the method automatically. Jobs services passed to webhook routes and enqueue helpers must also implement the new method shape.
14
+
15
+ ## 0.5.1 - 2026-10-30
16
+
17
+ ### Changed
18
+
19
+ - Require Effect 4.0.6 and align the Effect companion package peers and generated starter catalog to the same exact release. Install the 4.0.6 Effect stack together.
20
+
21
+ ### Fixed
22
+
23
+ - Register hosted RPC cache-control handling through Effect 4.0.6's request-scoped pre-response API so responses keep `private, no-store`.
24
+ - Accept native RPC's `application/x-ndjson` media type while preserving `application/ndjson` callers at the transport guard.
25
+ - Keep subscriptions open after their HTTP request body completes; closing the socket still cancels them.
26
+
3
27
  ## 0.5.0 - 2026-10-27
4
28
 
5
29
  ### Breaking
package/README.md CHANGED
@@ -8,14 +8,12 @@ A service should explain what it needs and what callers can do with it. When eve
8
8
 
9
9
  ```ts
10
10
  const Greetings = defineService({
11
- id: "app/Greetings",
12
- requires: [Prefix],
13
- initialize: Effect.succeed({ punctuation: "!" }),
14
- methods: (state) => ({
15
- greet: Effect.fn("Greetings.greet")((name: string) =>
16
- Effect.map(Prefix, (prefix) => `${prefix}${name}${state.punctuation}`),
17
- ),
18
- }),
11
+ id: "app/Greetings",
12
+ requires: [Prefix],
13
+ initialize: Effect.succeed({ punctuation: "!" }),
14
+ methods: (state) => ({
15
+ greet: Effect.fn("Greetings.greet")((name: string) => Effect.map(Prefix, (prefix) => `${prefix}${name}${state.punctuation}`)),
16
+ }),
19
17
  });
20
18
  ```
21
19
 
@@ -34,7 +32,6 @@ A **declared dependency** is a service tag in `requires`. The Layer supplies tho
34
32
  **Caller scope** is different from initialization scope. The Layer owns initialization resources: their finalizers run once when its scope closes or its owner is interrupted, including when initialization is still running. A method that acquires a scoped resource keeps `Scope.Scope` in its public requirement type; its caller supplies the scope and releases the resource when that scope closes, even while the service stays live. Interrupting a method call in `Effect.scoped` interrupts the call and releases its resources without ending the service's lifetime.
35
33
 
36
34
  The work has three parts:
37
-
38
35
  1. Once at the application boundary, compose service Layers with their dependencies.
39
36
  2. Once per service, define its dependency list, private state and methods.
40
37
  3. In application code, yield the service and call its methods.
@@ -48,23 +45,19 @@ import { defineService } from "@shivaedev/service/defineService.ts";
48
45
  class Prefix extends Context.Service<Prefix, string>()("app/Prefix") {}
49
46
 
50
47
  const Greetings = defineService({
51
- id: "app/Greetings",
52
- requires: [Prefix],
53
- initialize: Effect.succeed({ punctuation: "!" }),
54
- methods: (state) => ({
55
- greet: Effect.fn("Greetings.greet")((name: string) =>
56
- Effect.map(Prefix, (prefix) => `${prefix}${name}${state.punctuation}`),
57
- ),
58
- }),
48
+ id: "app/Greetings",
49
+ requires: [Prefix],
50
+ initialize: Effect.succeed({ punctuation: "!" }),
51
+ methods: (state) => ({
52
+ greet: Effect.fn("Greetings.greet")((name: string) => Effect.map(Prefix, (prefix) => `${prefix}${name}${state.punctuation}`)),
53
+ }),
59
54
  });
60
55
 
61
- const live = Greetings.layer.pipe(
62
- Layer.provide(Layer.succeed(Prefix, "Hello ")),
63
- );
56
+ const live = Greetings.layer.pipe(Layer.provide(Layer.succeed(Prefix, "Hello ")));
64
57
 
65
58
  const greeting = Effect.gen(function* () {
66
- const greetings = yield* Greetings;
67
- return yield* greetings.greet("Ada");
59
+ const greetings = yield* Greetings;
60
+ return yield* greetings.greet("Ada");
68
61
  }).pipe(Effect.provide(live));
69
62
  ```
70
63
 
@@ -83,28 +76,30 @@ import { Context, Effect, type Scope } from "effect";
83
76
  import { defineService } from "@shivaedev/service/defineService.ts";
84
77
  import type { ServiceRequirements } from "@shivaedev/service/ServiceRequirements.ts";
85
78
 
86
- class Declared extends Context.Service<Declared, { readonly identity: object }>()(
87
- "app/Declared",
88
- ) {}
79
+ class Declared extends Context.Service<Declared, { readonly identity: object }>()("app/Declared") {}
89
80
 
90
81
  const requirements = [Declared] as const;
91
82
 
92
- type Requirements<Success, Failure = never, CallerScope extends Scope.Scope = never> =
93
- ServiceRequirements<typeof requirements, Success, Failure, CallerScope>;
83
+ type Requirements<Success, Failure = never, CallerScope extends Scope.Scope = never> = ServiceRequirements<
84
+ typeof requirements,
85
+ Success,
86
+ Failure,
87
+ CallerScope
88
+ >;
94
89
 
95
90
  const Identity = defineService({
96
- id: "app/Identity",
97
- requires: requirements,
98
- initialize: Effect.fn("Identity.initialize")(function* (): Requirements<{
99
- readonly identity: object;
100
- }> {
101
- return { identity: (yield* Declared).identity };
102
- })(),
103
- methods: (state) => ({
104
- sameIdentity: Effect.fn("Identity.sameIdentity")(function* (): Requirements<boolean> {
105
- return (yield* Declared).identity === state.identity;
106
- }),
107
- }),
91
+ id: "app/Identity",
92
+ requires: requirements,
93
+ initialize: Effect.fn("Identity.initialize")(function* (): Requirements<{
94
+ readonly identity: object;
95
+ }> {
96
+ return { identity: (yield* Declared).identity };
97
+ })(),
98
+ methods: (state) => ({
99
+ sameIdentity: Effect.fn("Identity.sameIdentity")(function* (): Requirements<boolean> {
100
+ return (yield* Declared).identity === state.identity;
101
+ }),
102
+ }),
108
103
  });
109
104
  ```
110
105
 
@@ -117,24 +112,19 @@ import { Effect, Ref } from "effect";
117
112
  import { defineService } from "@shivaedev/service/defineService.ts";
118
113
 
119
114
  const Resources = defineService({
120
- id: "app/Resources",
121
- requires: [],
122
- initialize: Ref.make(0),
123
- methods: (released) => ({
124
- open: Effect.fn("Resources.open")(() =>
125
- Effect.acquireRelease(
126
- Effect.succeed("resource"),
127
- () => Ref.update(released, (count) => count + 1),
128
- ),
129
- ),
130
- released: Effect.fn("Resources.released")(() => Ref.get(released)),
131
- }),
115
+ id: "app/Resources",
116
+ requires: [],
117
+ initialize: Ref.make(0),
118
+ methods: (released) => ({
119
+ open: Effect.fn("Resources.open")(() => Effect.acquireRelease(Effect.succeed("resource"), () => Ref.update(released, (count) => count + 1))),
120
+ released: Effect.fn("Resources.released")(() => Ref.get(released)),
121
+ }),
132
122
  });
133
123
 
134
124
  const useResource = Effect.gen(function* () {
135
- const resources = yield* Resources;
136
- yield* Effect.scoped(resources.open());
137
- return yield* resources.released();
125
+ const resources = yield* Resources;
126
+ yield* Effect.scoped(resources.open());
127
+ return yield* resources.released();
138
128
  }).pipe(Effect.provide(Resources.layer));
139
129
  ```
140
130
 
@@ -146,7 +136,7 @@ A native Layer can provide the method interface directly:
146
136
 
147
137
  ```ts
148
138
  const testGreetings = Layer.succeed(Greetings, {
149
- greet: Effect.fn("TestGreetings.greet")((name: string) => Effect.succeed(name)),
139
+ greet: Effect.fn("TestGreetings.greet")((name: string) => Effect.succeed(name)),
150
140
  });
151
141
  ```
152
142
 
@@ -154,43 +144,37 @@ The replacement provides the public method interface, rather than private initia
154
144
 
155
145
  ### Preserve a generic method's signature
156
146
 
157
- Ordinary methods have one concrete signature. For a service with an empty `requires` list, `genericMethod` marks a generic function so its success, failure and caller requirements remain related at each call:
147
+ Ordinary methods have one concrete signature. `genericMethod` marks a generic function so its success, failure and caller requirements remain related at each call:
158
148
 
159
149
  ```ts
160
150
  import { Context, Effect } from "effect";
161
151
  import { defineService } from "@shivaedev/service/defineService.ts";
162
152
  import { genericMethod } from "@shivaedev/service/genericMethod.ts";
163
153
 
164
- class Caller extends Context.Service<Caller, { readonly value: number }>()(
165
- "app/Caller",
166
- ) {}
154
+ class Caller extends Context.Service<Caller, { readonly value: number }>()("app/Caller") {}
167
155
 
168
156
  const preserve = Effect.fn("Generic.preserve")(
169
- <Success, Failure, Requirements>(
170
- effect: Effect.Effect<Success, Failure, Requirements>,
171
- ): Effect.Effect<{ readonly value: Success }, Failure, Requirements> =>
172
- Effect.map(effect, (value) => ({ value })),
157
+ <Success, Failure, Requirements>(
158
+ effect: Effect.Effect<Success, Failure, Requirements>,
159
+ ): Effect.Effect<{ readonly value: Success }, Failure, Requirements> => Effect.map(effect, (value) => ({ value })),
173
160
  );
174
161
 
175
162
  const Generic = defineService({
176
- id: "app/Generic",
177
- requires: [],
178
- initialize: Effect.void,
179
- methods: () => ({ preserve: genericMethod(preserve) }),
163
+ id: "app/Generic",
164
+ requires: [],
165
+ initialize: Effect.void,
166
+ methods: () => ({ preserve: genericMethod(preserve) }),
180
167
  });
181
168
 
182
169
  const preserved = Effect.gen(function* () {
183
- const service = yield* Generic;
184
- return yield* service.preserve(Effect.map(Caller, ({ value }) => value));
185
- }).pipe(
186
- Effect.provide(Generic.layer),
187
- Effect.provideService(Caller, { value: 42 }),
188
- );
170
+ const service = yield* Generic;
171
+ return yield* service.preserve(Effect.map(Caller, ({ value }) => value));
172
+ }).pipe(Effect.provide(Generic.layer), Effect.provideService(Caller, { value: 42 }));
189
173
  ```
190
174
 
191
175
  The wrapped Effect still requires `Caller`, which the caller supplies separately. The generic service's Layer has no declared dependencies. The emitted declarations preserve the generic success and failure types as well as caller requirements.
192
176
 
193
- Marked generic methods require a service with no declared dependencies. The compiler rejects an unmarked generic that correlates its input and returned Effect, and a structurally distinct two-signature overload; it may not reject other generic or overloaded signatures. Use ordinary methods with concrete signatures when the service binds dependencies.
177
+ Marked generic methods also work with declared initializer dependencies. Their signatures keep all caller requirements unchanged; unlike ordinary methods, they do not subtract declared dependencies from the public signature. The compiler rejects an unmarked generic that correlates its input and returned Effect, and a structurally distinct two-signature overload; it may not reject other generic or overloaded signatures. Use initialization state to close over bound dependencies in generic methods.
194
178
 
195
179
  Dependency binding wraps the method's outer returned Effect. A Stream returned as its value retains its own service requirements; provide them when running the Stream.
196
180
 
@@ -198,28 +182,27 @@ Dependency binding wraps the method's outer returned Effect. A Stream returned a
198
182
 
199
183
  Import the module that defines the name:
200
184
 
201
- | Module | Name | Use |
202
- | --- | --- | --- |
203
- | `@shivaedev/service/defineService.ts` | `defineService(definition)` | Create a native service with its `.layer`. |
204
- | `@shivaedev/service/genericMethod.ts` | `genericMethod(method)` | Mark a generic Effect-returning function in a service with no declared dependencies. |
185
+ | Module | Name | Use |
186
+ | ------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
187
+ | `@shivaedev/service/defineService.ts` | `defineService(definition)` | Create a native service with its `.layer`. |
188
+ | `@shivaedev/service/genericMethod.ts` | `genericMethod(method)` | Preserve a generic Effect-returning function and its caller requirements. |
205
189
  | `@shivaedev/service/ServiceRequirements.ts` | `ServiceRequirements<Requirements, Success, Failure = never, CallerScope = never>` | Annotate an `Effect.fn` generator with declared dependencies and optional caller scope. |
206
190
 
207
191
  The definition's fields are:
208
192
 
209
- | Field | Meaning |
210
- | --- | --- |
211
- | `id` | The Context service identity, also retained in the Layer's output type. |
212
- | `requires` | A readonly list of service tags available to initialization and ordinary methods. |
213
- | `initialize` | The Effect producing private state; its failure type becomes the Layer's failure type. |
193
+ | Field | Meaning |
194
+ | ---------------- | --------------------------------------------------------------------------------------------------------------------------- |
195
+ | `id` | The Context service identity, also retained in the Layer's output type. |
196
+ | `requires` | A readonly list of service tags available to initialization and ordinary methods. |
197
+ | `initialize` | The Effect producing private state; its failure type becomes the Layer's failure type. |
214
198
  | `methods(state)` | A function returning the public method record, with declared dependencies removed from ordinary methods' requirement types. |
215
199
 
216
200
  ### Install and limits
217
201
 
218
202
  ```sh
219
- pnpm add @shivaedev/service effect@4.0.5
203
+ pnpm add @shivaedev/service effect
220
204
  ```
221
205
 
222
206
  `effect` is a peer dependency, and the package needs Node.js 24 or later.
223
-
224
207
  - Keep request identity at the request boundary when it changes per call. Pass it as a method argument rather than binding it into a service intended to live across requests.
225
208
  - Choose service Layer lifetimes at the application's composition boundary; keep initialization resource ownership separate from a method caller's scope.
@@ -5,9 +5,6 @@ export type MethodEntry = AnyMethod | GenericMethodDescriptor<AnyMethod>;
5
5
  export type MethodRecord = Readonly<Record<string, AnyMethod>>;
6
6
  export type MethodInventory = Readonly<Record<string, unknown>>;
7
7
  export type RuntimeMethodInventory = Readonly<Record<string, MethodEntry>>;
8
- interface GenericMethodWithDeclaredRequirementsIsUnsupported {
9
- readonly _serviceDefinitionError: "generic methods cannot subtract declared service requirements";
10
- }
11
8
  type MethodRequirements<TMethod> = TMethod extends (...arguments_: readonly never[]) => Effect.Effect<unknown, unknown, infer TRequirements> ? TRequirements : never;
12
9
  interface MethodHasUndeclaredServiceRequirements {
13
10
  readonly _serviceDefinitionError: "method has service requirements absent from the service declaration";
@@ -18,7 +15,7 @@ interface ServiceMembersMustBeMethods {
18
15
  type OrdinaryMethodProof<TMethod, TRequirements extends RequirementRecord> = [
19
16
  Exclude<MethodRequirements<TMethod>, RequirementsOf<TRequirements> | Scope.Scope>
20
17
  ] extends [never] ? TMethod : MethodHasUndeclaredServiceRequirements;
21
- type SupportedMethod<TMethod, TRequirements extends RequirementRecord> = TMethod extends GenericMethodDescriptor<AnyMethod> ? TRequirements extends readonly [] ? TMethod : GenericMethodWithDeclaredRequirementsIsUnsupported : TMethod extends AnyMethod ? HasDistinctCallSignatures<TMethod> extends true ? GenericOrStructurallyOverloadedMethodsAreUnsupported : TMethod extends (...arguments_: infer TArguments) => infer TResult ? ((...arguments_: TArguments) => TResult) extends TMethod ? OrdinaryMethodProof<TMethod, TRequirements> : GenericOrStructurallyOverloadedMethodsAreUnsupported : GenericOrStructurallyOverloadedMethodsAreUnsupported : ServiceMembersMustBeMethods;
18
+ type SupportedMethod<TMethod, TRequirements extends RequirementRecord> = TMethod extends GenericMethodDescriptor<AnyMethod> ? TMethod : TMethod extends AnyMethod ? HasDistinctCallSignatures<TMethod> extends true ? GenericOrStructurallyOverloadedMethodsAreUnsupported : TMethod extends (...arguments_: infer TArguments) => infer TResult ? ((...arguments_: TArguments) => TResult) extends TMethod ? OrdinaryMethodProof<TMethod, TRequirements> : GenericOrStructurallyOverloadedMethodsAreUnsupported : GenericOrStructurallyOverloadedMethodsAreUnsupported : ServiceMembersMustBeMethods;
22
19
  export type MethodProof<TMethods extends MethodInventory, TRequirements extends RequirementRecord> = {
23
20
  readonly [TName in keyof TMethods]: SupportedMethod<TMethods[TName], TRequirements>;
24
21
  };
@@ -1 +1 @@
1
- {"version":3,"file":"MethodProof.d.ts","sourceRoot":"","sources":["../src/MethodProof.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EACX,SAAS,EACT,uBAAuB,EACvB,oDAAoD,EACpD,yBAAyB,EACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAElF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;AAEzE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhE,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAE3E,UAAU,kDAAkD;IAC3D,QAAQ,CAAC,uBAAuB,EAAE,+DAA+D,CAAC;CAClG;AAED,KAAK,kBAAkB,CAAC,OAAO,IAAI,OAAO,SAAS,CAAC,GAAG,UAAU,EAAE,SAAS,KAAK,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC,GACzI,aAAa,GACb,KAAK,CAAC;AAET,UAAU,sCAAsC;IAC/C,QAAQ,CAAC,uBAAuB,EAAE,qEAAqE,CAAC;CACxG;AAED,UAAU,2BAA2B;IACpC,QAAQ,CAAC,uBAAuB,EAAE,iCAAiC,CAAC;CACpE;AAED,KAAK,mBAAmB,CAAC,OAAO,EAAE,aAAa,SAAS,iBAAiB,IAAI;IAC5E,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;CACjF,SAAS,CAAC,KAAK,CAAC,GACd,OAAO,GACP,sCAAsC,CAAC;AAE1C,KAAK,eAAe,CAAC,OAAO,EAAE,aAAa,SAAS,iBAAiB,IACpE,OAAO,SAAS,uBAAuB,CAAC,SAAS,CAAC,GAC/C,aAAa,SAAS,SAAS,EAAE,GAChC,OAAO,GACP,kDAAkD,GACnD,OAAO,SAAS,SAAS,GACxB,yBAAyB,CAAC,OAAO,CAAC,SAAS,IAAI,GAC9C,oDAAoD,GACpD,OAAO,SAAS,CAAC,GAAG,UAAU,EAAE,MAAM,UAAU,KAAK,MAAM,OAAO,GACjE,CAAC,CAAC,GAAG,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,OAAO,GACvD,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,GAC3C,oDAAoD,GACrD,oDAAoD,GACtD,2BAA2B,CAAC;AAEjC,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,eAAe,EAAE,aAAa,SAAS,iBAAiB,IAAI;IACpG,QAAQ,EAAE,KAAK,IAAI,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CACnF,CAAC"}
1
+ {"version":3,"file":"MethodProof.d.ts","sourceRoot":"","sources":["../src/MethodProof.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EACX,SAAS,EACT,uBAAuB,EACvB,oDAAoD,EACpD,yBAAyB,EACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAElF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;AAEzE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhE,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAE3E,KAAK,kBAAkB,CAAC,OAAO,IAAI,OAAO,SAAS,CAAC,GAAG,UAAU,EAAE,SAAS,KAAK,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC,GACzI,aAAa,GACb,KAAK,CAAC;AAET,UAAU,sCAAsC;IAC/C,QAAQ,CAAC,uBAAuB,EAAE,qEAAqE,CAAC;CACxG;AAED,UAAU,2BAA2B;IACpC,QAAQ,CAAC,uBAAuB,EAAE,iCAAiC,CAAC;CACpE;AAED,KAAK,mBAAmB,CAAC,OAAO,EAAE,aAAa,SAAS,iBAAiB,IAAI;IAC5E,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;CACjF,SAAS,CAAC,KAAK,CAAC,GACd,OAAO,GACP,sCAAsC,CAAC;AAE1C,KAAK,eAAe,CAAC,OAAO,EAAE,aAAa,SAAS,iBAAiB,IACpE,OAAO,SAAS,uBAAuB,CAAC,SAAS,CAAC,GAC/C,OAAO,GACP,OAAO,SAAS,SAAS,GACxB,yBAAyB,CAAC,OAAO,CAAC,SAAS,IAAI,GAC9C,oDAAoD,GACpD,OAAO,SAAS,CAAC,GAAG,UAAU,EAAE,MAAM,UAAU,KAAK,MAAM,OAAO,GACjE,CAAC,CAAC,GAAG,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,OAAO,GACvD,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,GAC3C,oDAAoD,GACrD,oDAAoD,GACtD,2BAA2B,CAAC;AAEjC,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,eAAe,EAAE,aAAa,SAAS,iBAAiB,IAAI;IACpG,QAAQ,EAAE,KAAK,IAAI,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CACnF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/service",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Declared Effect services with scoped initialization and bound dependencies",
5
5
  "keywords": [
6
6
  "effect"
@@ -43,17 +43,17 @@
43
43
  "README.md"
44
44
  ],
45
45
  "devDependencies": {
46
- "@effect/vitest": "4.0.5",
47
- "@shivaedev/quality": "0.42.0",
48
- "@shivaedev/test": "0.10.0",
49
- "@shivaedev/test-story": "0.21.0",
46
+ "@effect/vitest": "4.0.6",
47
+ "@shivaedev/quality": "0.46.0",
48
+ "@shivaedev/test": "0.11.0",
49
+ "@shivaedev/test-story": "0.25.0",
50
50
  "@types/node": "24.19.2",
51
- "effect": "4.0.5",
51
+ "effect": "4.0.6",
52
52
  "typescript": "7.0.2",
53
53
  "vitest": "5.0.5"
54
54
  },
55
55
  "peerDependencies": {
56
- "effect": "4.0.5"
56
+ "effect": "4.0.6"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=24"
@@ -15,10 +15,6 @@ export type MethodInventory = Readonly<Record<string, unknown>>;
15
15
 
16
16
  export type RuntimeMethodInventory = Readonly<Record<string, MethodEntry>>;
17
17
 
18
- interface GenericMethodWithDeclaredRequirementsIsUnsupported {
19
- readonly _serviceDefinitionError: "generic methods cannot subtract declared service requirements";
20
- }
21
-
22
18
  type MethodRequirements<TMethod> = TMethod extends (...arguments_: readonly never[]) => Effect.Effect<unknown, unknown, infer TRequirements>
23
19
  ? TRequirements
24
20
  : never;
@@ -39,9 +35,7 @@ type OrdinaryMethodProof<TMethod, TRequirements extends RequirementRecord> = [
39
35
 
40
36
  type SupportedMethod<TMethod, TRequirements extends RequirementRecord> =
41
37
  TMethod extends GenericMethodDescriptor<AnyMethod>
42
- ? TRequirements extends readonly []
43
- ? TMethod
44
- : GenericMethodWithDeclaredRequirementsIsUnsupported
38
+ ? TMethod
45
39
  : TMethod extends AnyMethod
46
40
  ? HasDistinctCallSignatures<TMethod> extends true
47
41
  ? GenericOrStructurallyOverloadedMethodsAreUnsupported