@shivaedev/service 0.8.1 → 0.9.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 +12 -0
- package/README.md +3 -1
- package/dist/MethodProof.d.ts +1 -1
- package/dist/MethodProof.d.ts.map +1 -1
- package/dist/adapters/requirementLayer.d.ts +12 -0
- package/dist/adapters/requirementLayer.d.ts.map +1 -0
- package/dist/adapters/requirementLayer.js +13 -0
- package/dist/adapters/requirementLayer.js.map +1 -0
- package/dist/defineService.d.ts +1 -1
- package/dist/defineService.d.ts.map +1 -1
- package/dist/defineService.js +3 -10
- package/dist/defineService.js.map +1 -1
- package/dist/genericMethod.d.ts +8 -11
- package/dist/genericMethod.d.ts.map +1 -1
- package/dist/genericMethod.js.map +1 -1
- package/package.json +3 -4
- package/src/MethodProof.ts +5 -1
- package/src/adapters/requirementLayer.ts +24 -0
- package/src/defineService.ts +5 -14
- package/src/genericMethod.ts +9 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.0 - 2026-11-08
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Expose `requirementLayer` at `@shivaedev/service/adapters/requirementLayer.ts` for binding declared requirements in the service Layer.
|
|
8
|
+
|
|
9
|
+
## 0.8.2 - 2026-11-07
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Preserve schema result types and decoding service requirements through generic service methods.
|
|
14
|
+
|
|
3
15
|
## 0.8.1 - 2026-11-07
|
|
4
16
|
|
|
5
17
|
### Changed
|
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ A **service definition** has four parts: an identity, the services it requires,
|
|
|
46
46
|
|
|
47
47
|
An **operation** is an `Effect.fn("Service.operation")` export in its own file, in the service's folder beside its `service.ts`. It reads every dependency with `yield*`: repositories, `SqlClient`, HTTP clients, config, other services and the caller. A dependency never arrives as a parameter, a closure capture or a bundle, and the acting user's id is never an argument. A target id, such as the account an administrator acts on, is an ordinary argument.
|
|
48
48
|
|
|
49
|
-
A **declared dependency** is a service tag in `requires`. The Layer supplies those services to initialization and binds them to each operation, and the public operation's type no longer requires them. If a caller provides a different value for a declared dependency around a call, the operation still uses the value supplied when the Layer was built.
|
|
49
|
+
A **declared dependency** is a service tag in `requires`. The Layer supplies those services to initialization and binds them to each operation, and the public operation's type no longer requires them. The requirement binder lives in `src/adapters/requirementLayer.ts`; it captures the Layer's declared services once and provides them to initialization and operations. If a caller provides a different value for a declared dependency around a call, the operation still uses the value supplied when the Layer was built.
|
|
50
50
|
|
|
51
51
|
The **lifetime** of a service is its Layer's. Each build of the Layer runs `initialize` once, and every call on that build shares its state. Where the Layer is registered decides the lifetime: built once by the host, the service is global; built for each request, it is per request and may require the caller, such as `SessionUser` or `Subject`, which the host provides for that request; built with `Layer.fresh` or for a single use, it is fresh each time. A service that requires the caller cannot be built globally, because nothing global provides the caller.
|
|
52
52
|
|
|
@@ -266,6 +266,8 @@ Import the module that defines the name:
|
|
|
266
266
|
| `@shivaedev/service/genericMethod.ts` | `genericMethod(method)` | Preserve a generic Effect-returning function and its caller requirements. |
|
|
267
267
|
| `@shivaedev/service/ServiceRequirements.ts` | `ServiceRequirements<Requirements, Success, Failure = never, CallerScope = never>` | Annotate an `Effect.fn` generator with declared dependencies and optional caller scope. |
|
|
268
268
|
|
|
269
|
+
The public `defineService` entry stays at `@shivaedev/service/defineService.ts`. Its context-capturing requirement binder lives in `@shivaedev/service/adapters/requirementLayer.ts`.
|
|
270
|
+
|
|
269
271
|
The definition's fields are:
|
|
270
272
|
|
|
271
273
|
| Field | Meaning |
|
package/dist/MethodProof.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ interface ServiceMembersMustBeMethods {
|
|
|
17
17
|
type OrdinaryMethodProof<TName extends PropertyKey, TMethod, TRequirements extends RequirementRecord> = [
|
|
18
18
|
Exclude<MethodRequirements<TMethod>, RequirementsOf<TRequirements> | Scope.Scope>
|
|
19
19
|
] extends [never] ? TMethod : MethodHasUndeclaredServiceRequirements<TName, Exclude<MethodRequirements<TMethod>, RequirementsOf<TRequirements> | Scope.Scope>>;
|
|
20
|
-
type SupportedMethod<TName extends PropertyKey, 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<TName, TMethod, TRequirements> : GenericOrStructurallyOverloadedMethodsAreUnsupported : GenericOrStructurallyOverloadedMethodsAreUnsupported : ServiceMembersMustBeMethods;
|
|
20
|
+
type SupportedMethod<TName extends PropertyKey, TMethod, TRequirements extends RequirementRecord> = TMethod extends GenericMethodDescriptor<AnyMethod> ? TMethod extends GenericMethodDescriptor<infer TGenericMethod> ? [HasDistinctCallSignatures<TGenericMethod>] extends [true] ? GenericOrStructurallyOverloadedMethodsAreUnsupported : TMethod : TMethod : TMethod extends AnyMethod ? HasDistinctCallSignatures<TMethod> extends true ? GenericOrStructurallyOverloadedMethodsAreUnsupported : TMethod extends (...arguments_: infer TArguments) => infer TResult ? ((...arguments_: TArguments) => TResult) extends TMethod ? OrdinaryMethodProof<TName, TMethod, TRequirements> : GenericOrStructurallyOverloadedMethodsAreUnsupported : GenericOrStructurallyOverloadedMethodsAreUnsupported : ServiceMembersMustBeMethods;
|
|
21
21
|
export type MethodProof<TMethods extends MethodInventory, TRequirements extends RequirementRecord> = {
|
|
22
22
|
readonly [TName in keyof TMethods]: SupportedMethod<TName, TMethods[TName], TRequirements>;
|
|
23
23
|
};
|
|
@@ -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,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEjF,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,CAAC,KAAK,SAAS,WAAW,EAAE,QAAQ;IACnF,QAAQ,CAAC,uBAAuB,EAAE,qEAAqE,CAAC;IACxG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC;CACnC;AAED,UAAU,2BAA2B;IACpC,QAAQ,CAAC,uBAAuB,EAAE,iCAAiC,CAAC;CACpE;AAED,KAAK,mBAAmB,CAAC,KAAK,SAAS,WAAW,EAAE,OAAO,EAAE,aAAa,SAAS,iBAAiB,IAAI;IACvG,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,KAAK,EAAE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAEpI,KAAK,eAAe,CAAC,KAAK,SAAS,WAAW,EAAE,OAAO,EAAE,aAAa,SAAS,iBAAiB,IAC/F,OAAO,SAAS,uBAAuB,CAAC,SAAS,CAAC,GAC/C,OAAO,
|
|
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,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEjF,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,CAAC,KAAK,SAAS,WAAW,EAAE,QAAQ;IACnF,QAAQ,CAAC,uBAAuB,EAAE,qEAAqE,CAAC;IACxG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC;CACnC;AAED,UAAU,2BAA2B;IACpC,QAAQ,CAAC,uBAAuB,EAAE,iCAAiC,CAAC;CACpE;AAED,KAAK,mBAAmB,CAAC,KAAK,SAAS,WAAW,EAAE,OAAO,EAAE,aAAa,SAAS,iBAAiB,IAAI;IACvG,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,KAAK,EAAE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAEpI,KAAK,eAAe,CAAC,KAAK,SAAS,WAAW,EAAE,OAAO,EAAE,aAAa,SAAS,iBAAiB,IAC/F,OAAO,SAAS,uBAAuB,CAAC,SAAS,CAAC,GAC/C,OAAO,SAAS,uBAAuB,CAAC,MAAM,cAAc,CAAC,GAC5D,CAAC,yBAAyB,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GACzD,oDAAoD,GACpD,OAAO,GACR,OAAO,GACR,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,KAAK,EAAE,OAAO,EAAE,aAAa,CAAC,GAClD,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,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAC1F,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import type { MethodRecord, RuntimeMethodInventory } from "#MethodProof.ts";
|
|
3
|
+
import type { RequirementRecord } from "#ServiceRequirements.ts";
|
|
4
|
+
interface RuntimeDefinition<TState> {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly initialize: Effect.Effect<TState, unknown, unknown>;
|
|
7
|
+
readonly methods: (state: TState) => RuntimeMethodInventory;
|
|
8
|
+
readonly requires: RequirementRecord;
|
|
9
|
+
}
|
|
10
|
+
export declare function requirementLayer<TState>(service: Context.Service<string, MethodRecord>, definition: RuntimeDefinition<TState>): Layer.Layer<string, unknown, string>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=requirementLayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirementLayer.d.ts","sourceRoot":"","sources":["../../src/adapters/requirementLayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAe,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,UAAU,iBAAiB,CAAC,MAAM;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7D,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,sBAAsB,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;CACrC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,UAAU,EAAE,iBAAiB,CAAC,MAAM,CAAC,wCAY7H"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Record } from "effect";
|
|
2
|
+
export function requirementLayer(service, definition) {
|
|
3
|
+
return Layer.effect(service)(Effect.gen(function* () {
|
|
4
|
+
const ambient = yield* Effect.context();
|
|
5
|
+
const declared = Context.pick(...definition.requires)(ambient);
|
|
6
|
+
const state = yield* Effect.provide(definition.initialize, declared);
|
|
7
|
+
return Record.map(definition.methods(state), (entry) => {
|
|
8
|
+
const method = typeof entry === "function" ? entry : entry.method;
|
|
9
|
+
return (...arguments_) => Effect.provide(method(...arguments_), declared);
|
|
10
|
+
});
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=requirementLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirementLayer.js","sourceRoot":"","sources":["../../src/adapters/requirementLayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAWxD,MAAM,UAAU,gBAAgB,CAAS,OAA8C,EAAE,UAAqC;IAC7H,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAC3B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAU,CAAC;QAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACrE,OAAO,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAkB,EAAE,EAAE;YACnE,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;YAClE,OAAO,CAAC,GAAG,UAA4B,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC7F,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;AACH,CAAC"}
|
package/dist/defineService.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Effect, Layer } from "effect";
|
|
1
|
+
import { Context, type Effect, type Layer } from "effect";
|
|
2
2
|
import type { GenericMethodDescriptor } from "#genericMethod.ts";
|
|
3
3
|
import type { InitializerProof } from "#InitializerProof.ts";
|
|
4
4
|
import type { MethodInventory, MethodProof } from "#MethodProof.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineService.d.ts","sourceRoot":"","sources":["../src/defineService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"defineService.d.ts","sourceRoot":"","sources":["../src/defineService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAwC,MAAM,iBAAiB,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEjF,KAAK,WAAW,CAAC,OAAO,EAAE,aAAa,IAAI,OAAO,SAAS,CAC1D,GAAG,UAAU,EAAE,MAAM,UAAU,KAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,QAAQ,EAAE,MAAM,QAAQ,EAAE,MAAM,SAAS,CAAC,GAChE,CAAC,GAAG,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,GACnG,KAAK,CAAC;AAET,KAAK,YAAY,CAAC,MAAM,EAAE,aAAa,IAAI,MAAM,SAAS,uBAAuB,CAAC,MAAM,OAAO,CAAC,GAAG,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEhJ,KAAK,YAAY,CAAC,QAAQ,SAAS,eAAe,EAAE,aAAa,SAAS,iBAAiB,IAAI,QAAQ,CAAC;KACtG,KAAK,IAAI,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;CACvF,CAAC,CAAC;AAEH,UAAU,iBAAiB,CAC1B,WAAW,SAAS,MAAM,EAC1B,aAAa,SAAS,iBAAiB,EACvC,YAAY,SAAS,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAC7D,QAAQ,SAAS,eAAe;IAEhC,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,YAAY,GAAG,gBAAgB,CAAC,YAAY,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;IAClG,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC;IACpH,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;CACnE;AASD,KAAK,cAAc,CAAC,WAAW,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG;IACzH,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;CAClE,CAAC;AAEF,wBAAgB,aAAa,CAC5B,KAAK,CAAC,WAAW,SAAS,MAAM,EAChC,KAAK,CAAC,aAAa,SAAS,iBAAiB,EAC7C,KAAK,CAAC,YAAY,SAAS,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EACnE,KAAK,CAAC,QAAQ,SAAS,eAAe,EAEtC,UAAU,EAAE,iBAAiB,CAAC,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,CAAC,GAC/E,cAAc,CAAC,WAAW,EAAE,YAAY,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC"}
|
package/dist/defineService.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import { Context
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import { requirementLayer } from "#adapters/requirementLayer.ts";
|
|
2
3
|
export function defineService(definition) {
|
|
3
4
|
const service = Context.Service(definition.id);
|
|
4
|
-
const layer =
|
|
5
|
-
const ambient = yield* Effect.context();
|
|
6
|
-
const declared = Context.pick(...definition.requires)(ambient);
|
|
7
|
-
const state = yield* Effect.provide(definition.initialize, declared);
|
|
8
|
-
return Record.map(definition.methods(state), (entry) => {
|
|
9
|
-
const method = typeof entry === "function" ? entry : entry.method;
|
|
10
|
-
return (...arguments_) => Effect.provide(method(...arguments_), declared);
|
|
11
|
-
});
|
|
12
|
-
}));
|
|
5
|
+
const layer = requirementLayer(service, definition);
|
|
13
6
|
return Object.assign(service, { layer });
|
|
14
7
|
}
|
|
15
8
|
//# sourceMappingURL=defineService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineService.js","sourceRoot":"","sources":["../src/defineService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"defineService.js","sourceRoot":"","sources":["../src/defineService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA2B,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAkDjE,MAAM,UAAU,aAAa,CAAS,UAAqC;IAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAuB,UAAU,CAAC,EAAE,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAC1C,CAAC"}
|
package/dist/genericMethod.d.ts
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import type { Effect } from "effect";
|
|
2
2
|
export type AnyMethod = (...arguments_: readonly never[]) => Effect.Effect<unknown, unknown, unknown>;
|
|
3
|
-
export interface GenericMethodDescriptor<TMethod extends AnyMethod> {
|
|
4
|
-
readonly _tag: "GenericMethod";
|
|
5
|
-
readonly method: TMethod;
|
|
6
|
-
}
|
|
7
|
-
type Same<TLeft, TRight> = (<TValue>() => TValue extends TLeft ? 1 : 2) extends <TValue>() => (TValue extends TRight ? 1 : 2) ? true : false;
|
|
8
3
|
export type HasDistinctCallSignatures<TMethod> = TMethod extends {
|
|
9
|
-
(...arguments_: infer TFirstArguments):
|
|
10
|
-
(...arguments_: infer TLastArguments):
|
|
11
|
-
} ?
|
|
4
|
+
(...arguments_: infer TFirstArguments): unknown;
|
|
5
|
+
(...arguments_: infer TLastArguments): unknown;
|
|
6
|
+
} ? [TFirstArguments] extends [TLastArguments] ? [TLastArguments] extends [TFirstArguments] ? false : true : true : false;
|
|
12
7
|
export interface GenericOrStructurallyOverloadedMethodsAreUnsupported {
|
|
13
8
|
readonly _serviceDefinitionError: "generic and structurally overloaded methods are unsupported";
|
|
14
9
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
export interface GenericMethodDescriptor<TMethod extends AnyMethod> {
|
|
11
|
+
readonly _tag: "GenericMethod";
|
|
12
|
+
readonly method: TMethod;
|
|
13
|
+
}
|
|
14
|
+
export declare function genericMethod<TMethod extends AnyMethod>(method: TMethod): GenericMethodDescriptor<TMethod>;
|
|
18
15
|
//# sourceMappingURL=genericMethod.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genericMethod.d.ts","sourceRoot":"","sources":["../src/genericMethod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,UAAU,EAAE,SAAS,KAAK,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEtG,MAAM,
|
|
1
|
+
{"version":3,"file":"genericMethod.d.ts","sourceRoot":"","sources":["../src/genericMethod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,UAAU,EAAE,SAAS,KAAK,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEtG,MAAM,MAAM,yBAAyB,CAAC,OAAO,IAAI,OAAO,SAAS;IAChE,CAAC,GAAG,UAAU,EAAE,MAAM,eAAe,GAAG,OAAO,CAAC;IAChD,CAAC,GAAG,UAAU,EAAE,MAAM,cAAc,GAAG,OAAO,CAAC;CAC/C,GACE,CAAC,eAAe,CAAC,SAAS,CAAC,cAAc,CAAC,GACzC,CAAC,cAAc,CAAC,SAAS,CAAC,eAAe,CAAC,GACzC,KAAK,GACL,IAAI,GACL,IAAI,GACL,KAAK,CAAC;AAET,MAAM,WAAW,oDAAoD;IACpE,QAAQ,CAAC,uBAAuB,EAAE,6DAA6D,CAAC;CAChG;AAED,MAAM,WAAW,uBAAuB,CAAC,OAAO,SAAS,SAAS;IACjE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,aAAa,CAAC,OAAO,SAAS,SAAS,EAAE,MAAM,EAAE,OAAO,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genericMethod.js","sourceRoot":"","sources":["../src/genericMethod.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"genericMethod.js","sourceRoot":"","sources":["../src/genericMethod.ts"],"names":[],"mappings":"AAyBA,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC9C,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;AAC1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/service",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Declared Effect services with scoped initialization and bound dependencies",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect"
|
|
@@ -44,9 +44,8 @@
|
|
|
44
44
|
],
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@effect/vitest": "4.1.1",
|
|
47
|
-
"@shivaedev/quality": "0.
|
|
48
|
-
"@shivaedev/test": "0.
|
|
49
|
-
"@shivaedev/test-story": "0.45.2",
|
|
47
|
+
"@shivaedev/quality": "0.74.3",
|
|
48
|
+
"@shivaedev/test-story": "0.45.6",
|
|
50
49
|
"@types/node": "24.19.2",
|
|
51
50
|
"effect": "4.1.1",
|
|
52
51
|
"typescript": "7.0.2",
|
package/src/MethodProof.ts
CHANGED
|
@@ -37,7 +37,11 @@ type OrdinaryMethodProof<TName extends PropertyKey, TMethod, TRequirements exten
|
|
|
37
37
|
|
|
38
38
|
type SupportedMethod<TName extends PropertyKey, TMethod, TRequirements extends RequirementRecord> =
|
|
39
39
|
TMethod extends GenericMethodDescriptor<AnyMethod>
|
|
40
|
-
? TMethod
|
|
40
|
+
? TMethod extends GenericMethodDescriptor<infer TGenericMethod>
|
|
41
|
+
? [HasDistinctCallSignatures<TGenericMethod>] extends [true]
|
|
42
|
+
? GenericOrStructurallyOverloadedMethodsAreUnsupported
|
|
43
|
+
: TMethod
|
|
44
|
+
: TMethod
|
|
41
45
|
: TMethod extends AnyMethod
|
|
42
46
|
? HasDistinctCallSignatures<TMethod> extends true
|
|
43
47
|
? GenericOrStructurallyOverloadedMethodsAreUnsupported
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Record } from "effect";
|
|
2
|
+
import type { MethodEntry, MethodRecord, RuntimeMethodInventory } from "#MethodProof.ts";
|
|
3
|
+
import type { RequirementRecord } from "#ServiceRequirements.ts";
|
|
4
|
+
|
|
5
|
+
interface RuntimeDefinition<TState> {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly initialize: Effect.Effect<TState, unknown, unknown>;
|
|
8
|
+
readonly methods: (state: TState) => RuntimeMethodInventory;
|
|
9
|
+
readonly requires: RequirementRecord;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function requirementLayer<TState>(service: Context.Service<string, MethodRecord>, definition: RuntimeDefinition<TState>) {
|
|
13
|
+
return Layer.effect(service)(
|
|
14
|
+
Effect.gen(function* () {
|
|
15
|
+
const ambient = yield* Effect.context<string>();
|
|
16
|
+
const declared = Context.pick(...definition.requires)(ambient);
|
|
17
|
+
const state = yield* Effect.provide(definition.initialize, declared);
|
|
18
|
+
return Record.map(definition.methods(state), (entry: MethodEntry) => {
|
|
19
|
+
const method = typeof entry === "function" ? entry : entry.method;
|
|
20
|
+
return (...arguments_: readonly never[]) => Effect.provide(method(...arguments_), declared);
|
|
21
|
+
});
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
24
|
+
}
|
package/src/defineService.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Context, Effect, Layer
|
|
2
|
-
import
|
|
1
|
+
import { Context, type Effect, type Layer } from "effect";
|
|
2
|
+
import { requirementLayer } from "#adapters/requirementLayer.ts";
|
|
3
|
+
import type { GenericMethodDescriptor } from "#genericMethod.ts";
|
|
3
4
|
import type { InitializerProof } from "#InitializerProof.ts";
|
|
4
|
-
import type {
|
|
5
|
+
import type { MethodInventory, MethodProof, MethodRecord, RuntimeMethodInventory } from "#MethodProof.ts";
|
|
5
6
|
import type { RequirementProof } from "#RequirementProof.ts";
|
|
6
7
|
import type { RequirementRecord, RequirementsOf } from "#ServiceRequirements.ts";
|
|
7
8
|
|
|
@@ -50,16 +51,6 @@ export function defineService<
|
|
|
50
51
|
): DefinedService<TIdentifier, ServiceShape<TMethods, TRequirements>, Effect.Error<TInitializer>, RequirementsOf<TRequirements>>;
|
|
51
52
|
export function defineService<TState>(definition: RuntimeDefinition<TState>): unknown {
|
|
52
53
|
const service = Context.Service<string, MethodRecord>(definition.id);
|
|
53
|
-
const layer =
|
|
54
|
-
Effect.gen(function* () {
|
|
55
|
-
const ambient = yield* Effect.context<string>();
|
|
56
|
-
const declared = Context.pick(...definition.requires)(ambient);
|
|
57
|
-
const state = yield* Effect.provide(definition.initialize, declared);
|
|
58
|
-
return Record.map(definition.methods(state), (entry: MethodEntry) => {
|
|
59
|
-
const method: AnyMethod = typeof entry === "function" ? entry : entry.method;
|
|
60
|
-
return (...arguments_: readonly never[]) => Effect.provide(method(...arguments_), declared);
|
|
61
|
-
});
|
|
62
|
-
}),
|
|
63
|
-
);
|
|
54
|
+
const layer = requirementLayer(service, definition);
|
|
64
55
|
return Object.assign(service, { layer });
|
|
65
56
|
}
|
package/src/genericMethod.ts
CHANGED
|
@@ -2,19 +2,12 @@ import type { Effect } from "effect";
|
|
|
2
2
|
|
|
3
3
|
export type AnyMethod = (...arguments_: readonly never[]) => Effect.Effect<unknown, unknown, unknown>;
|
|
4
4
|
|
|
5
|
-
export interface GenericMethodDescriptor<TMethod extends AnyMethod> {
|
|
6
|
-
readonly _tag: "GenericMethod";
|
|
7
|
-
readonly method: TMethod;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type Same<TLeft, TRight> = (<TValue>() => TValue extends TLeft ? 1 : 2) extends <TValue>() => TValue extends TRight ? 1 : 2 ? true : false;
|
|
11
|
-
|
|
12
5
|
export type HasDistinctCallSignatures<TMethod> = TMethod extends {
|
|
13
|
-
(...arguments_: infer TFirstArguments):
|
|
14
|
-
(...arguments_: infer TLastArguments):
|
|
6
|
+
(...arguments_: infer TFirstArguments): unknown;
|
|
7
|
+
(...arguments_: infer TLastArguments): unknown;
|
|
15
8
|
}
|
|
16
|
-
?
|
|
17
|
-
?
|
|
9
|
+
? [TFirstArguments] extends [TLastArguments]
|
|
10
|
+
? [TLastArguments] extends [TFirstArguments]
|
|
18
11
|
? false
|
|
19
12
|
: true
|
|
20
13
|
: true
|
|
@@ -24,10 +17,12 @@ export interface GenericOrStructurallyOverloadedMethodsAreUnsupported {
|
|
|
24
17
|
readonly _serviceDefinitionError: "generic and structurally overloaded methods are unsupported";
|
|
25
18
|
}
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
export interface GenericMethodDescriptor<TMethod extends AnyMethod> {
|
|
21
|
+
readonly _tag: "GenericMethod";
|
|
22
|
+
readonly method: TMethod;
|
|
23
|
+
}
|
|
29
24
|
|
|
30
|
-
export function genericMethod<TMethod extends AnyMethod>(method: TMethod):
|
|
25
|
+
export function genericMethod<TMethod extends AnyMethod>(method: TMethod): GenericMethodDescriptor<TMethod>;
|
|
31
26
|
export function genericMethod(method: AnyMethod): unknown {
|
|
32
27
|
return { _tag: "GenericMethod", method };
|
|
33
28
|
}
|