@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 +24 -0
- package/README.md +68 -85
- package/dist/MethodProof.d.ts +1 -4
- package/dist/MethodProof.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/MethodProof.ts +1 -7
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
184
|
-
|
|
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
|
|
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
|
|
202
|
-
|
|
|
203
|
-
| `@shivaedev/service/defineService.ts`
|
|
204
|
-
| `@shivaedev/service/genericMethod.ts`
|
|
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
|
|
210
|
-
|
|
|
211
|
-
| `id`
|
|
212
|
-
| `requires`
|
|
213
|
-
| `initialize`
|
|
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
|
|
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.
|
package/dist/MethodProof.d.ts
CHANGED
|
@@ -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> ?
|
|
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,
|
|
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.
|
|
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.
|
|
47
|
-
"@shivaedev/quality": "0.
|
|
48
|
-
"@shivaedev/test": "0.
|
|
49
|
-
"@shivaedev/test-story": "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.
|
|
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.
|
|
56
|
+
"effect": "4.0.6"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=24"
|
package/src/MethodProof.ts
CHANGED
|
@@ -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
|
-
?
|
|
43
|
-
? TMethod
|
|
44
|
-
: GenericMethodWithDeclaredRequirementsIsUnsupported
|
|
38
|
+
? TMethod
|
|
45
39
|
: TMethod extends AnyMethod
|
|
46
40
|
? HasDistinctCallSignatures<TMethod> extends true
|
|
47
41
|
? GenericOrStructurallyOverloadedMethodsAreUnsupported
|