@shivaedev/effect-trpc 0.2.0 → 0.3.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 +9 -0
- package/README.md +19 -7
- package/dist/adapter.d.ts +15 -3
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/context-bridge.d.ts +4 -1
- package/dist/internal/context-bridge.d.ts.map +1 -1
- package/dist/internal/context-bridge.js +8 -1
- package/dist/internal/context-bridge.js.map +1 -1
- package/dist/internal/procedure-types.d.ts +2 -1
- package/dist/internal/procedure-types.d.ts.map +1 -1
- package/dist/internal/runtime.d.ts +5 -2
- package/dist/internal/runtime.d.ts.map +1 -1
- package/dist/internal/runtime.js +48 -16
- package/dist/internal/runtime.js.map +1 -1
- package/dist/internal/subscription-handler.d.ts +14 -0
- package/dist/internal/subscription-handler.d.ts.map +1 -0
- package/dist/internal/subscription-handler.js +18 -0
- package/dist/internal/subscription-handler.js.map +1 -0
- package/dist/procedure.d.ts +10 -3
- package/dist/procedure.d.ts.map +1 -1
- package/dist/procedure.js +16 -3
- package/dist/procedure.js.map +1 -1
- package/dist/request-signal.d.ts +4 -0
- package/dist/request-signal.d.ts.map +1 -0
- package/dist/request-signal.js +4 -0
- package/dist/request-signal.js.map +1 -0
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapter.ts +29 -4
- package/src/index.ts +3 -0
- package/src/internal/context-bridge.ts +14 -1
- package/src/internal/procedure-types.ts +9 -1
- package/src/internal/runtime.ts +72 -38
- package/src/internal/subscription-handler.ts +61 -0
- package/src/procedure.ts +58 -0
- package/src/request-signal.ts +7 -0
- package/src/types.ts +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.0 - 2026-08-03
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add Effect Stream subscriptions with request-scoped Layers, transport
|
|
10
|
+
cancellation, finalizers, tracing, and stream instrumentation.
|
|
11
|
+
- Accept a shared application runtime so tRPC calls and other promise-based
|
|
12
|
+
adapters use the same ambient Effect services.
|
|
13
|
+
|
|
5
14
|
## 0.2.0 - 2026-08-03
|
|
6
15
|
|
|
7
16
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@shivaedev/effect-trpc`
|
|
2
2
|
|
|
3
|
-
Effect-native query and
|
|
3
|
+
Effect-native query, mutation, and subscription procedures for tRPC, with an optional Vitest
|
|
4
4
|
harness for calling routers as Effects.
|
|
5
5
|
|
|
6
6
|
This package currently targets exact early-access versions of Effect v4 and
|
|
@@ -55,9 +55,21 @@ uses the schema's encoded type at the caller and decoded type in the generator;
|
|
|
55
55
|
output uses the schema's encoded type in the generator and decoded type at the
|
|
56
56
|
caller.
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
Subscriptions return an Effect Stream. The request Layer remains open for the
|
|
59
|
+
stream's lifetime, transport cancellation interrupts the stream, and scoped
|
|
60
|
+
finalizers run when it ends:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const updates = procedure.subscription(function* () {
|
|
64
|
+
const movies = yield* Movies
|
|
65
|
+
return movies.updates
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`RequestSignal` exposes tRPC's transport signal when application code needs to
|
|
70
|
+
combine it with another disconnect signal. Build middleware, metadata, and
|
|
71
|
+
other tRPC configuration on the ordinary tRPC procedure builder before passing
|
|
72
|
+
it to `adapter.procedure`.
|
|
61
73
|
|
|
62
74
|
## Request services
|
|
63
75
|
|
|
@@ -96,9 +108,9 @@ const adapter = makeEffectTRPC({
|
|
|
96
108
|
})
|
|
97
109
|
```
|
|
98
110
|
|
|
99
|
-
Each procedure runs in a span named after its tRPC path. `instrument`
|
|
100
|
-
application-specific Effect logging, metrics, or
|
|
101
|
-
procedure definitions.
|
|
111
|
+
Each procedure runs in a span named after its tRPC path. `instrument` and
|
|
112
|
+
`instrumentStream` can add application-specific Effect logging, metrics, or
|
|
113
|
+
tracing without changing procedure definitions.
|
|
102
114
|
|
|
103
115
|
## Vitest
|
|
104
116
|
|
package/dist/adapter.d.ts
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import type { inferProcedureBuilderResolverOptions, TRPCProcedureBuilder } from "@trpc/server";
|
|
2
|
-
import type { Context,
|
|
2
|
+
import type { Context, Effect, Exit } from "effect";
|
|
3
3
|
import { EffectProcedureBuilder } from "./procedure.js";
|
|
4
4
|
import type { EffectProcedureRequestServices } from "./request-services.js";
|
|
5
|
-
import type { EffectTRPCErrorMapper, EffectTRPCInstrument } from "./types.js";
|
|
5
|
+
import type { EffectTRPCErrorMapper, EffectTRPCInstrument, EffectTRPCStreamInstrument } from "./types.js";
|
|
6
6
|
export interface MakeEffectTRPCOptions<Requirements, RuntimeError> {
|
|
7
7
|
readonly instrument?: EffectTRPCInstrument;
|
|
8
|
+
readonly instrumentStream?: EffectTRPCStreamInstrument;
|
|
8
9
|
readonly mapError?: EffectTRPCErrorMapper;
|
|
9
|
-
readonly runtime:
|
|
10
|
+
readonly runtime: EffectTRPCRuntime<Requirements, RuntimeError>;
|
|
11
|
+
}
|
|
12
|
+
export interface EffectTRPCRuntime<Requirements, RuntimeError> {
|
|
13
|
+
readonly contextEffect: Effect.Effect<Context.Context<Requirements>, RuntimeError>;
|
|
14
|
+
readonly currentServices?: () => Context.Context<never> | undefined;
|
|
15
|
+
readonly runPromise: <Value, Error>(effect: Effect.Effect<Value, Error, Requirements>, options?: {
|
|
16
|
+
readonly signal?: AbortSignal;
|
|
17
|
+
}) => Promise<Value>;
|
|
18
|
+
readonly runPromiseExit: <Value, Error>(effect: Effect.Effect<Value, Error, Requirements>, options?: {
|
|
19
|
+
readonly signal?: AbortSignal;
|
|
20
|
+
}) => Promise<Exit.Exit<Value, Error | RuntimeError>>;
|
|
21
|
+
readonly runWithServices?: <Services, Value>(services: Context.Context<Services>, evaluate: () => Value) => Value;
|
|
10
22
|
}
|
|
11
23
|
export interface EffectTRPCAdapter<Requirements> {
|
|
12
24
|
readonly procedure: <Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut, ProvidedServices, LayerError>(builder: TRPCProcedureBuilder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut, false>, requestServices: EffectProcedureRequestServices<inferProcedureBuilderResolverOptions<TRPCProcedureBuilder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut, false>>["ctx"], ProvidedServices, LayerError>) => EffectProcedureBuilder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut, ProvidedServices, LayerError, Requirements>;
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oCAAoC,EACpC,oBAAoB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
CHANGED
|
@@ -2,7 +2,7 @@ import { makeContextBridge } from "./internal/context-bridge.js";
|
|
|
2
2
|
import { makeRuntimeBridge } from "./internal/runtime.js";
|
|
3
3
|
import { EffectProcedureBuilder } from "./procedure.js";
|
|
4
4
|
export const makeEffectTRPC = (options) => {
|
|
5
|
-
const contextBridge = makeContextBridge();
|
|
5
|
+
const contextBridge = makeContextBridge(options.runtime);
|
|
6
6
|
const runtime = makeRuntimeBridge(options.runtime, contextBridge, options);
|
|
7
7
|
return {
|
|
8
8
|
procedure: (builder, requestServices) => new EffectProcedureBuilder(builder, requestServices, runtime),
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA2FxD,MAAM,CAAC,MAAM,cAAc,GAAG,CAC7B,OAA0D,EACxB,EAAE;IACpC,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;IAE3E,OAAO;QACN,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,CACvC,IAAI,sBAAsB,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAU;QACvE,eAAe,EAAE,aAAa,CAAC,GAAG;KAClC,CAAC;AACH,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { type EffectTRPCAdapter, type MakeEffectTRPCOptions, makeEffectTRPC, } from "./adapter.js";
|
|
1
|
+
export { type EffectTRPCAdapter, type EffectTRPCRuntime, type MakeEffectTRPCOptions, makeEffectTRPC, } from "./adapter.js";
|
|
2
2
|
export { badRequest, conflict, fail, forbidden, internalServerError, notFound, preconditionFailed, unauthorized, } from "./errors.js";
|
|
3
3
|
export type { EffectProcedureBuilder } from "./procedure.js";
|
|
4
4
|
export { type EffectProcedureRequestServices, extendRequestServices, makeRequestServices, } from "./request-services.js";
|
|
5
|
-
export
|
|
5
|
+
export { RequestSignal } from "./request-signal.js";
|
|
6
|
+
export type { EffectTRPCErrorContext, EffectTRPCErrorMapper, EffectTRPCInstrument, EffectTRPCStreamInstrument, ProcedureInfo, ProcedureKind, } from "./types.js";
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,kBAAkB,EAClB,YAAY,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACN,KAAK,8BAA8B,EACnC,qBAAqB,EACrB,mBAAmB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACX,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,aAAa,GACb,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,kBAAkB,EAClB,YAAY,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACN,KAAK,8BAA8B,EACnC,qBAAqB,EACrB,mBAAmB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EACX,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACb,aAAa,GACb,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { makeEffectTRPC, } from "./adapter.js";
|
|
2
2
|
export { badRequest, conflict, fail, forbidden, internalServerError, notFound, preconditionFailed, unauthorized, } from "./errors.js";
|
|
3
3
|
export { extendRequestServices, makeRequestServices, } from "./request-services.js";
|
|
4
|
+
export { RequestSignal } from "./request-signal.js";
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,kBAAkB,EAClB,YAAY,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAEN,qBAAqB,EACrB,mBAAmB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -3,5 +3,8 @@ export interface ContextBridge {
|
|
|
3
3
|
readonly current: () => Context.Context<never> | undefined;
|
|
4
4
|
readonly run: <Services, Value>(services: Context.Context<Services>, evaluate: () => Value) => Value;
|
|
5
5
|
}
|
|
6
|
-
export declare const makeContextBridge: (
|
|
6
|
+
export declare const makeContextBridge: (shared?: {
|
|
7
|
+
readonly currentServices?: ContextBridge["current"];
|
|
8
|
+
readonly runWithServices?: ContextBridge["run"];
|
|
9
|
+
}) => ContextBridge;
|
|
7
10
|
//# sourceMappingURL=context-bridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-bridge.d.ts","sourceRoot":"","sources":["../../src/internal/context-bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,EAC7B,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EACnC,QAAQ,EAAE,MAAM,KAAK,KACjB,KAAK,CAAC;CACX;AAED,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"context-bridge.d.ts","sourceRoot":"","sources":["../../src/internal/context-bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,EAC7B,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EACnC,QAAQ,EAAE,MAAM,KAAK,KACjB,KAAK,CAAC;CACX;AAED,eAAO,MAAM,iBAAiB,GAAI,SAAS;IAC1C,QAAQ,CAAC,eAAe,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACpD,QAAQ,CAAC,eAAe,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CAChD,KAAG,aAkBH,CAAC"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
export const makeContextBridge = () => {
|
|
2
|
+
export const makeContextBridge = (shared) => {
|
|
3
|
+
if (shared?.currentServices !== undefined &&
|
|
4
|
+
shared.runWithServices !== undefined) {
|
|
5
|
+
return {
|
|
6
|
+
current: shared.currentServices,
|
|
7
|
+
run: shared.runWithServices,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
3
10
|
const storage = new AsyncLocalStorage();
|
|
4
11
|
return {
|
|
5
12
|
current: () => storage.getStore(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-bridge.js","sourceRoot":"","sources":["../../src/internal/context-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAWrD,MAAM,CAAC,MAAM,iBAAiB,GAAG,
|
|
1
|
+
{"version":3,"file":"context-bridge.js","sourceRoot":"","sources":["../../src/internal/context-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAWrD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAGjC,EAAiB,EAAE;IACnB,IACC,MAAM,EAAE,eAAe,KAAK,SAAS;QACrC,MAAM,CAAC,eAAe,KAAK,SAAS,EACnC,CAAC;QACF,OAAO;YACN,OAAO,EAAE,MAAM,CAAC,eAAe;YAC/B,GAAG,EAAE,MAAM,CAAC,eAAe;SAC3B,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAA0B,CAAC;IAEhE,OAAO;QACN,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE;QACjC,GAAG,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAC3B,OAAO,CAAC,GAAG,CAAC,QAAkC,EAAE,QAAQ,CAAC;KAC1D,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { inferProcedureBuilderResolverOptions, TRPCProcedureBuilder, TRPCUnsetMarker } from "@trpc/server";
|
|
2
|
-
import type { Effect } from "effect";
|
|
2
|
+
import type { Effect, Stream } from "effect";
|
|
3
3
|
export type AnyProcedureBuilder = TRPCProcedureBuilder<any, any, any, any, any, any, any, false>;
|
|
4
4
|
export type DefaultValue<Value, Fallback> = Value extends TRPCUnsetMarker ? Fallback : Value;
|
|
5
5
|
export type IntersectIfDefined<Value, With> = Value extends TRPCUnsetMarker ? With : With extends TRPCUnsetMarker ? Value : Value & With;
|
|
6
6
|
export type ResolverContext<Builder extends AnyProcedureBuilder> = inferProcedureBuilderResolverOptions<Builder>["ctx"];
|
|
7
7
|
export type ProcedureEffect<Requirements> = Effect.Effect<any, any, Requirements>;
|
|
8
8
|
export type EffectProcedureResolver<Input, Requirements, Output> = (input: Input) => Generator<ProcedureEffect<Requirements>, Output, never>;
|
|
9
|
+
export type EffectSubscriptionResolver<Input, Requirements, Output> = (input: Input) => Generator<ProcedureEffect<Requirements>, Stream.Stream<Output, unknown, Requirements>, never>;
|
|
9
10
|
//# sourceMappingURL=procedure-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procedure-types.d.ts","sourceRoot":"","sources":["../../src/internal/procedure-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oCAAoC,EACpC,oBAAoB,EACpB,eAAe,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"procedure-types.d.ts","sourceRoot":"","sources":["../../src/internal/procedure-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oCAAoC,EACpC,oBAAoB,EACpB,eAAe,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE7C,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,CAErD,GAAG,EAEH,GAAG,EAEH,GAAG,EAEH,GAAG,EAEH,GAAG,EAEH,GAAG,EAEH,GAAG,EACH,KAAK,CACL,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,KAAK,EAAE,QAAQ,IAAI,KAAK,SAAS,eAAe,GACtE,QAAQ,GACR,KAAK,CAAC;AAET,MAAM,MAAM,kBAAkB,CAAC,KAAK,EAAE,IAAI,IAAI,KAAK,SAAS,eAAe,GACxE,IAAI,GACJ,IAAI,SAAS,eAAe,GAC3B,KAAK,GACL,KAAK,GAAG,IAAI,CAAC;AAEjB,MAAM,MAAM,eAAe,CAAC,OAAO,SAAS,mBAAmB,IAC9D,oCAAoC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;AAEtD,MAAM,MAAM,eAAe,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,CAExD,GAAG,EAEH,GAAG,EACH,YAAY,CACZ,CAAC;AAEF,MAAM,MAAM,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CAClE,KAAK,EAAE,KAAK,KACR,SAAS,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAE7D,MAAM,MAAM,0BAA0B,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CACrE,KAAK,EAAE,KAAK,KACR,SAAS,CACb,eAAe,CAAC,YAAY,CAAC,EAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,EAC5C,KAAK,CACL,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Effect,
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import type { EffectTRPCRuntime } from "../adapter.js";
|
|
2
3
|
import type { EffectTRPCErrorMapper, EffectTRPCInstrument, ProcedureInfo } from "../types.js";
|
|
3
4
|
import type { ContextBridge } from "./context-bridge.js";
|
|
4
5
|
interface RunEffectOptions {
|
|
@@ -8,9 +9,11 @@ interface RunEffectOptions {
|
|
|
8
9
|
export interface RuntimeBridge<Requirements> {
|
|
9
10
|
readonly instrument: EffectTRPCInstrument;
|
|
10
11
|
readonly runEffect: <Value>(effect: Effect.Effect<Value, unknown, Requirements>, options: RunEffectOptions) => Promise<Value>;
|
|
12
|
+
readonly runStream: <Value>(stream: Stream.Stream<Value, unknown, Requirements>, options: RunEffectOptions) => Promise<AsyncIterable<Value>>;
|
|
11
13
|
}
|
|
12
|
-
export declare const makeRuntimeBridge: <Requirements, RuntimeError>(runtime:
|
|
14
|
+
export declare const makeRuntimeBridge: <Requirements, RuntimeError>(runtime: EffectTRPCRuntime<Requirements, RuntimeError>, contextBridge: ContextBridge, options: {
|
|
13
15
|
readonly instrument?: EffectTRPCInstrument;
|
|
16
|
+
readonly instrumentStream?: import("../types.js").EffectTRPCStreamInstrument;
|
|
14
17
|
readonly mapError?: EffectTRPCErrorMapper;
|
|
15
18
|
}) => RuntimeBridge<Requirements>;
|
|
16
19
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/internal/runtime.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/internal/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,MAAM,EAAwB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EACX,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,UAAU,gBAAgB;IACzB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa,CAAC,YAAY;IAC1C,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EACzB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,EACnD,OAAO,EAAE,gBAAgB,KACrB,OAAO,CAAC,KAAK,CAAC,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EACzB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,EACnD,OAAO,EAAE,gBAAgB,KACrB,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;CACnC;AAkED,eAAO,MAAM,iBAAiB,GAAI,YAAY,EAAE,YAAY,EAC3D,SAAS,iBAAiB,CAAC,YAAY,EAAE,YAAY,CAAC,EACtD,eAAe,aAAa,EAC5B,SAAS;IACR,QAAQ,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,aAAa,EAAE,0BAA0B,CAAC;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAC1C,KACC,aAAa,CAAC,YAAY,CAmE3B,CAAC"}
|
package/dist/internal/runtime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TRPCError } from "@trpc/server";
|
|
2
|
-
import { Cause, Context, Effect, Exit, Option, Result, } from "effect";
|
|
2
|
+
import { Cause, Context, Effect, Exit, Option, Result, Stream } from "effect";
|
|
3
3
|
const internalError = (cause) => new TRPCError({
|
|
4
4
|
cause,
|
|
5
5
|
code: "INTERNAL_SERVER_ERROR",
|
|
@@ -16,10 +16,56 @@ const mapError = (error, origin, procedure, consumerMapper) => {
|
|
|
16
16
|
return internalError(mapperDefect);
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
+
const mapCause = (cause, procedure, consumerMapper) => {
|
|
20
|
+
if (Cause.hasInterruptsOnly(cause)) {
|
|
21
|
+
return new TRPCError({
|
|
22
|
+
code: "CLIENT_CLOSED_REQUEST",
|
|
23
|
+
message: "Request cancelled",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const failure = Cause.findErrorOption(cause);
|
|
27
|
+
if (Option.isSome(failure)) {
|
|
28
|
+
return mapError(failure.value, "failure", procedure, consumerMapper);
|
|
29
|
+
}
|
|
30
|
+
const defect = Cause.findDefect(cause);
|
|
31
|
+
if (Result.isSuccess(defect)) {
|
|
32
|
+
return mapError(defect.success, "defect", procedure, consumerMapper);
|
|
33
|
+
}
|
|
34
|
+
return internalError();
|
|
35
|
+
};
|
|
36
|
+
const interruptOn = (signal) => {
|
|
37
|
+
if (signal === undefined)
|
|
38
|
+
return Effect.never;
|
|
39
|
+
return Effect.callback((resume) => {
|
|
40
|
+
if (signal.aborted) {
|
|
41
|
+
resume(Effect.void);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const abort = () => resume(Effect.void);
|
|
45
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
46
|
+
return Effect.sync(() => signal.removeEventListener("abort", abort));
|
|
47
|
+
});
|
|
48
|
+
};
|
|
19
49
|
export const makeRuntimeBridge = (runtime, contextBridge, options) => ({
|
|
20
50
|
instrument: (effect, procedure) => Effect.suspend(() => options.instrument === undefined
|
|
21
51
|
? effect
|
|
22
52
|
: options.instrument(effect, procedure)),
|
|
53
|
+
runStream: async (stream, runOptions) => {
|
|
54
|
+
const instrumented = Stream.suspend(() => options.instrumentStream === undefined
|
|
55
|
+
? stream
|
|
56
|
+
: options.instrumentStream(stream, runOptions.procedure)).pipe(Stream.withSpan(runOptions.procedure.path, {
|
|
57
|
+
attributes: {
|
|
58
|
+
"rpc.method": runOptions.procedure.path,
|
|
59
|
+
"rpc.system": "trpc",
|
|
60
|
+
"trpc.type": runOptions.procedure.type,
|
|
61
|
+
},
|
|
62
|
+
captureStackTrace: runOptions.procedure.captureStackTrace,
|
|
63
|
+
}), Stream.interruptWhen(interruptOn(runOptions.signal)), Stream.catchCause((cause) => Stream.fail(mapCause(cause, runOptions.procedure, options.mapError))));
|
|
64
|
+
const context = await runtime.runPromise(Effect.context());
|
|
65
|
+
const ambient = contextBridge.current();
|
|
66
|
+
const provided = ambient === undefined ? context : Context.merge(context, ambient);
|
|
67
|
+
return Stream.toAsyncIterableWith(instrumented, provided);
|
|
68
|
+
},
|
|
23
69
|
runEffect: async (effect, runOptions) => {
|
|
24
70
|
const traced = effect.pipe(Effect.withSpan(runOptions.procedure.path, {
|
|
25
71
|
attributes: {
|
|
@@ -40,21 +86,7 @@ export const makeRuntimeBridge = (runtime, contextBridge, options) => ({
|
|
|
40
86
|
if (Exit.isSuccess(exit)) {
|
|
41
87
|
return exit.value;
|
|
42
88
|
}
|
|
43
|
-
|
|
44
|
-
throw new TRPCError({
|
|
45
|
-
code: "CLIENT_CLOSED_REQUEST",
|
|
46
|
-
message: "Request cancelled",
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
const failure = Cause.findErrorOption(exit.cause);
|
|
50
|
-
if (Option.isSome(failure)) {
|
|
51
|
-
throw mapError(failure.value, "failure", runOptions.procedure, options.mapError);
|
|
52
|
-
}
|
|
53
|
-
const defect = Cause.findDefect(exit.cause);
|
|
54
|
-
if (Result.isSuccess(defect)) {
|
|
55
|
-
throw mapError(defect.success, "defect", runOptions.procedure, options.mapError);
|
|
56
|
-
}
|
|
57
|
-
throw internalError();
|
|
89
|
+
throw mapCause(exit.cause, runOptions.procedure, options.mapError);
|
|
58
90
|
},
|
|
59
91
|
});
|
|
60
92
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/internal/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/internal/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import type { EffectProcedureRequestServices } from "../request-services.js";
|
|
3
|
+
import type { ProcedureInfo } from "../types.js";
|
|
4
|
+
import type { EffectSubscriptionResolver } from "./procedure-types.js";
|
|
5
|
+
import type { RuntimeBridge } from "./runtime.js";
|
|
6
|
+
interface SubscriptionInvocation<Context, Input> {
|
|
7
|
+
readonly ctx: Context;
|
|
8
|
+
readonly input: Input;
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly signal?: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
export declare const makeSubscriptionHandler: <RuntimeRequirements, Context, Input, ProvidedServices, LayerError, Output>(runtime: RuntimeBridge<RuntimeRequirements>, resolver: EffectSubscriptionResolver<Input, ProvidedServices | NoInfer<RuntimeRequirements>, Output>, requestServices: EffectProcedureRequestServices<Context, ProvidedServices, LayerError>, procedure: Omit<ProcedureInfo, "path">, outputSchema?: Schema.ConstraintDecoder<unknown>) => (invocation: SubscriptionInvocation<Context, Input>) => Promise<AsyncIterable<Output>>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=subscription-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-handler.d.ts","sourceRoot":"","sources":["../../src/internal/subscription-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAU,MAAM,QAAQ,CAAC;AACvD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AAE7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,UAAU,sBAAsB,CAAC,OAAO,EAAE,KAAK;IAC9C,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,eAAO,MAAM,uBAAuB,GACnC,mBAAmB,EACnB,OAAO,EACP,KAAK,EACL,gBAAgB,EAChB,UAAU,EACV,MAAM,EAEN,SAAS,aAAa,CAAC,mBAAmB,CAAC,EAC3C,UAAU,0BAA0B,CACnC,KAAK,EACL,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC,EAC/C,MAAM,CACN,EACD,iBAAiB,8BAA8B,CAC9C,OAAO,EACP,gBAAgB,EAChB,UAAU,CACV,EACD,WAAW,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,EACtC,eAAe,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAIlC,YAAY,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,mCAsBhE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Effect, Layer, Schema, Stream } from "effect";
|
|
2
|
+
import { RequestSignal } from "../request-signal.js";
|
|
3
|
+
export const makeSubscriptionHandler = (runtime, resolver, requestServices, procedure, outputSchema) => {
|
|
4
|
+
const tracedResolver = Effect.fnUntraced(resolver);
|
|
5
|
+
return async (invocation) => {
|
|
6
|
+
const info = { ...procedure, path: invocation.path };
|
|
7
|
+
const requestLayer = Layer.merge(requestServices.layer(invocation.ctx), Layer.succeed(RequestSignal, invocation.signal));
|
|
8
|
+
let stream = Stream.unwrap(Effect.suspend(() => runtime.instrument(tracedResolver(invocation.input), info))).pipe(Stream.provide(requestLayer));
|
|
9
|
+
if (outputSchema !== undefined) {
|
|
10
|
+
stream = Stream.mapEffect(stream, (value) => Schema.decodeUnknownEffect(outputSchema)(value));
|
|
11
|
+
}
|
|
12
|
+
return await runtime.runStream(stream, {
|
|
13
|
+
procedure: info,
|
|
14
|
+
...(invocation.signal === undefined ? {} : { signal: invocation.signal }),
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=subscription-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-handler.js","sourceRoot":"","sources":["../../src/internal/subscription-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAYrD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAQtC,OAA2C,EAC3C,QAIC,EACD,eAIC,EACD,SAAsC,EACtC,YAAgD,EAC/C,EAAE;IACH,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEnD,OAAO,KAAK,EAAE,UAAkD,EAAE,EAAE;QACnE,MAAM,IAAI,GAAG,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC;QACrD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAC/B,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EACrC,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,CAC/C,CAAC;QACF,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CACzB,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CACnB,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAC1D,CACD,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;QACrC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAC3C,MAAM,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAC9B,CAAC;QACpB,CAAC;QAED,OAAO,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE;YACtC,SAAS,EAAE,IAAI;YACf,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;SACzE,CAAC,CAAC;IACJ,CAAC,CAAC;AACH,CAAC,CAAC"}
|
package/dist/procedure.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { TRPCMutationProcedure, TRPCProcedureBuilder, TRPCQueryProcedure } from "@trpc/server";
|
|
1
|
+
import type { TRPCMutationProcedure, TRPCProcedureBuilder, TRPCQueryProcedure, TRPCSubscriptionProcedure } from "@trpc/server";
|
|
2
2
|
import { Schema } from "effect";
|
|
3
|
-
import type { DefaultValue, EffectProcedureResolver, IntersectIfDefined, ResolverContext } from "./internal/procedure-types.js";
|
|
3
|
+
import type { DefaultValue, EffectProcedureResolver, EffectSubscriptionResolver, IntersectIfDefined, ResolverContext } from "./internal/procedure-types.js";
|
|
4
4
|
import type { RuntimeBridge } from "./internal/runtime.js";
|
|
5
5
|
import type { EffectProcedureRequestServices } from "./request-services.js";
|
|
6
6
|
type Builder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut> = TRPCProcedureBuilder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut, false>;
|
|
@@ -8,7 +8,9 @@ export declare class EffectProcedureBuilder<Context, Meta, ContextOverrides, Inp
|
|
|
8
8
|
private readonly builder;
|
|
9
9
|
private readonly requestServices;
|
|
10
10
|
private readonly runtime;
|
|
11
|
-
|
|
11
|
+
private readonly subscriptionBuilder;
|
|
12
|
+
private readonly subscriptionOutput?;
|
|
13
|
+
constructor(builder: Builder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut>, requestServices: EffectProcedureRequestServices<ResolverContext<Builder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut>>, ProvidedServices, LayerError>, runtime: RuntimeBridge<RuntimeRequirements>, subscriptionBuilder?: Builder<Context, Meta, ContextOverrides, InputIn, InputOut, OutputIn, OutputOut>, subscriptionOutput?: Schema.ConstraintDecoder<unknown> | undefined);
|
|
12
14
|
input<SchemaValue extends Schema.ConstraintDecoder<unknown>>(schema: SchemaValue): EffectProcedureBuilder<Context, Meta, ContextOverrides, IntersectIfDefined<InputIn, SchemaValue["Encoded"]>, IntersectIfDefined<InputOut, SchemaValue["Type"]>, OutputIn, OutputOut, ProvidedServices, LayerError, RuntimeRequirements>;
|
|
13
15
|
output<SchemaValue extends Schema.ConstraintDecoder<unknown>>(schema: SchemaValue): EffectProcedureBuilder<Context, Meta, ContextOverrides, InputIn, InputOut, IntersectIfDefined<OutputIn, SchemaValue["Encoded"]>, IntersectIfDefined<OutputOut, SchemaValue["Type"]>, ProvidedServices, LayerError, RuntimeRequirements>;
|
|
14
16
|
query<Output>(resolver: EffectProcedureResolver<DefaultValue<InputOut, undefined>, ProvidedServices | NoInfer<RuntimeRequirements>, DefaultValue<OutputIn, Output>>): TRPCQueryProcedure<{
|
|
@@ -21,6 +23,11 @@ export declare class EffectProcedureBuilder<Context, Meta, ContextOverrides, Inp
|
|
|
21
23
|
output: DefaultValue<OutputOut, Output>;
|
|
22
24
|
meta: Meta;
|
|
23
25
|
}>;
|
|
26
|
+
subscription<Output>(resolver: EffectSubscriptionResolver<DefaultValue<InputOut, undefined>, ProvidedServices | NoInfer<RuntimeRequirements>, DefaultValue<OutputIn, Output>>): TRPCSubscriptionProcedure<{
|
|
27
|
+
input: DefaultValue<InputIn, void>;
|
|
28
|
+
output: AsyncIterable<DefaultValue<OutputOut, Output>, void, unknown>;
|
|
29
|
+
meta: Meta;
|
|
30
|
+
}>;
|
|
24
31
|
private dispatch;
|
|
25
32
|
}
|
|
26
33
|
export {};
|
package/dist/procedure.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procedure.d.ts","sourceRoot":"","sources":["../src/procedure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EACX,YAAY,EACZ,uBAAuB,EACvB,kBAAkB,EAClB,eAAe,EACf,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"procedure.d.ts","sourceRoot":"","sources":["../src/procedure.ts"],"names":[],"mappings":"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"}
|
package/dist/procedure.js
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
import { makeProcedureHandler } from "./internal/procedure-handler.js";
|
|
3
3
|
import { captureStackTrace } from "./internal/stack-trace.js";
|
|
4
|
+
import { makeSubscriptionHandler } from "./internal/subscription-handler.js";
|
|
4
5
|
export class EffectProcedureBuilder {
|
|
5
6
|
builder;
|
|
6
7
|
requestServices;
|
|
7
8
|
runtime;
|
|
8
|
-
|
|
9
|
+
subscriptionBuilder;
|
|
10
|
+
subscriptionOutput;
|
|
11
|
+
constructor(builder, requestServices, runtime, subscriptionBuilder = builder, subscriptionOutput) {
|
|
9
12
|
this.builder = builder;
|
|
10
13
|
this.requestServices = requestServices;
|
|
11
14
|
this.runtime = runtime;
|
|
15
|
+
this.subscriptionBuilder = subscriptionBuilder;
|
|
16
|
+
this.subscriptionOutput = subscriptionOutput;
|
|
12
17
|
}
|
|
13
18
|
input(schema) {
|
|
14
19
|
const next = this.builder.input(Schema.toStandardSchemaV1(schema));
|
|
15
|
-
|
|
20
|
+
const subscriptionNext = this.subscriptionBuilder.input(Schema.toStandardSchemaV1(schema));
|
|
21
|
+
return new EffectProcedureBuilder(next, this.requestServices, this.runtime, subscriptionNext, this.subscriptionOutput);
|
|
16
22
|
}
|
|
17
23
|
output(schema) {
|
|
18
24
|
const next = this.builder.output(Schema.toStandardSchemaV1(schema));
|
|
19
|
-
return new EffectProcedureBuilder(next, this.requestServices, this.runtime);
|
|
25
|
+
return new EffectProcedureBuilder(next, this.requestServices, this.runtime, this.subscriptionBuilder, schema);
|
|
20
26
|
}
|
|
21
27
|
query(resolver) {
|
|
22
28
|
return this.dispatch("query", resolver);
|
|
@@ -24,6 +30,13 @@ export class EffectProcedureBuilder {
|
|
|
24
30
|
mutation(resolver) {
|
|
25
31
|
return this.dispatch("mutation", resolver);
|
|
26
32
|
}
|
|
33
|
+
subscription(resolver) {
|
|
34
|
+
const handler = makeSubscriptionHandler(this.runtime, resolver, this.requestServices, {
|
|
35
|
+
captureStackTrace: captureStackTrace(),
|
|
36
|
+
type: "subscription",
|
|
37
|
+
}, this.subscriptionOutput);
|
|
38
|
+
return this.subscriptionBuilder.subscription(handler);
|
|
39
|
+
}
|
|
27
40
|
dispatch(type, resolver) {
|
|
28
41
|
const handler = makeProcedureHandler(this.runtime, resolver, this.requestServices, { captureStackTrace: captureStackTrace(), type });
|
|
29
42
|
return type === "query"
|
package/dist/procedure.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procedure.js","sourceRoot":"","sources":["../src/procedure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"procedure.js","sourceRoot":"","sources":["../src/procedure.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AASvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAsB7E,MAAM,OAAO,sBAAsB;IAahB;IASA;IAeA;IACA;IACA;IA3BlB,YACkB,OAQhB,EACgB,eAchB,EACgB,OAA2C,EAC3C,sBAAsB,OAAO,EAC7B,kBAAsD;QA1BtD,YAAO,GAAP,OAAO,CAQvB;QACgB,oBAAe,GAAf,eAAe,CAc/B;QACgB,YAAO,GAAP,OAAO,CAAoC;QAC3C,wBAAmB,GAAnB,mBAAmB,CAAU;QAC7B,uBAAkB,GAAlB,kBAAkB,CAAoC;IACrE,CAAC;IAEJ,KAAK,CACJ,MAAmB;QAanB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAU,CAAC,CAAC;QAC5E,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CACtD,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAU,CAC1C,CAAC;QACF,OAAO,IAAI,sBAAsB,CAChC,IAQC,EACD,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,OAAO,EACZ,gBAQC,EACD,IAAI,CAAC,kBAAkB,CACvB,CAAC;IACH,CAAC;IAED,MAAM,CACL,MAAmB;QAanB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;QACpE,OAAO,IAAI,sBAAsB,CAChC,IAQC,EACD,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,mBAQJ,EACD,MAAM,CACN,CAAC;IACH,CAAC;IAED,KAAK,CACJ,QAIC;QAMD,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAIpC,CAAC;IACJ,CAAC;IAED,QAAQ,CACP,QAIC;QAMD,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAIvC,CAAC;IACJ,CAAC;IAED,YAAY,CACX,QAIC;QAMD,MAAM,OAAO,GAAG,uBAAuB,CACtC,IAAI,CAAC,OAAO,EACZ,QAAQ,EACR,IAAI,CAAC,eAAe,EACpB;YACC,iBAAiB,EAAE,iBAAiB,EAAE;YACtC,IAAI,EAAE,cAAc;SACpB,EACD,IAAI,CAAC,kBAAkB,CACd,CAAC;QACX,OAAO,IAAI,CAAC,mBAAmB,CAAC,YAAY,CAC3C,OAAO,CAKN,CAAC;IACJ,CAAC;IAEO,QAAQ,CACf,IAA0B,EAC1B,QAIC;QAED,MAAM,OAAO,GAAG,oBAAoB,CACnC,IAAI,CAAC,OAAO,EACZ,QAAQ,EACR,IAAI,CAAC,eAAe,EACpB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,CACvC,CAAC;QACX,OAAO,IAAI,KAAK,OAAO;YACtB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;YAC7B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-signal.d.ts","sourceRoot":"","sources":["../src/request-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,wEAAwE;AACxE,eAAO,MAAM,aAAa,4CAGzB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
/** The transport cancellation signal for the current tRPC procedure. */
|
|
3
|
+
export const RequestSignal = Context.Reference("@shivaedev/effect-trpc/RequestSignal", { defaultValue: () => undefined });
|
|
4
|
+
//# sourceMappingURL=request-signal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-signal.js","sourceRoot":"","sources":["../src/request-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,wEAAwE;AACxE,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,CAC7C,sCAAsC,EACtC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CACjC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TRPCError } from "@trpc/server";
|
|
2
|
-
import type { Effect } from "effect";
|
|
3
|
-
export type ProcedureKind = "mutation" | "query";
|
|
2
|
+
import type { Effect, Stream } from "effect";
|
|
3
|
+
export type ProcedureKind = "mutation" | "query" | "subscription";
|
|
4
4
|
export interface ProcedureInfo {
|
|
5
5
|
readonly captureStackTrace: () => string | undefined;
|
|
6
6
|
readonly path: string;
|
|
@@ -11,4 +11,5 @@ export interface EffectTRPCErrorContext extends ProcedureInfo {
|
|
|
11
11
|
}
|
|
12
12
|
export type EffectTRPCErrorMapper = (error: unknown, context: EffectTRPCErrorContext) => TRPCError | undefined;
|
|
13
13
|
export type EffectTRPCInstrument = <A, E, R>(effect: Effect.Effect<A, E, R>, procedure: ProcedureInfo) => Effect.Effect<A, E, R>;
|
|
14
|
+
export type EffectTRPCStreamInstrument = <A, E, R>(stream: Stream.Stream<A, E, R>, procedure: ProcedureInfo) => Stream.Stream<A, E, R>;
|
|
14
15
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE7C,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;AAElE,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC5D,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,MAAM,qBAAqB,GAAG,CACnC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,sBAAsB,KAC3B,SAAS,GAAG,SAAS,CAAC;AAE3B,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,SAAS,EAAE,aAAa,KACpB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAE5B,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAChD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,SAAS,EAAE,aAAa,KACpB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
package/src/adapter.ts
CHANGED
|
@@ -2,17 +2,42 @@ import type {
|
|
|
2
2
|
inferProcedureBuilderResolverOptions,
|
|
3
3
|
TRPCProcedureBuilder,
|
|
4
4
|
} from "@trpc/server";
|
|
5
|
-
import type { Context,
|
|
5
|
+
import type { Context, Effect, Exit } from "effect";
|
|
6
6
|
import { makeContextBridge } from "./internal/context-bridge.js";
|
|
7
7
|
import { makeRuntimeBridge } from "./internal/runtime.js";
|
|
8
8
|
import { EffectProcedureBuilder } from "./procedure.js";
|
|
9
9
|
import type { EffectProcedureRequestServices } from "./request-services.js";
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
EffectTRPCErrorMapper,
|
|
12
|
+
EffectTRPCInstrument,
|
|
13
|
+
EffectTRPCStreamInstrument,
|
|
14
|
+
} from "./types.js";
|
|
11
15
|
|
|
12
16
|
export interface MakeEffectTRPCOptions<Requirements, RuntimeError> {
|
|
13
17
|
readonly instrument?: EffectTRPCInstrument;
|
|
18
|
+
readonly instrumentStream?: EffectTRPCStreamInstrument;
|
|
14
19
|
readonly mapError?: EffectTRPCErrorMapper;
|
|
15
|
-
readonly runtime:
|
|
20
|
+
readonly runtime: EffectTRPCRuntime<Requirements, RuntimeError>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface EffectTRPCRuntime<Requirements, RuntimeError> {
|
|
24
|
+
readonly contextEffect: Effect.Effect<
|
|
25
|
+
Context.Context<Requirements>,
|
|
26
|
+
RuntimeError
|
|
27
|
+
>;
|
|
28
|
+
readonly currentServices?: () => Context.Context<never> | undefined;
|
|
29
|
+
readonly runPromise: <Value, Error>(
|
|
30
|
+
effect: Effect.Effect<Value, Error, Requirements>,
|
|
31
|
+
options?: { readonly signal?: AbortSignal },
|
|
32
|
+
) => Promise<Value>;
|
|
33
|
+
readonly runPromiseExit: <Value, Error>(
|
|
34
|
+
effect: Effect.Effect<Value, Error, Requirements>,
|
|
35
|
+
options?: { readonly signal?: AbortSignal },
|
|
36
|
+
) => Promise<Exit.Exit<Value, Error | RuntimeError>>;
|
|
37
|
+
readonly runWithServices?: <Services, Value>(
|
|
38
|
+
services: Context.Context<Services>,
|
|
39
|
+
evaluate: () => Value,
|
|
40
|
+
) => Value;
|
|
16
41
|
}
|
|
17
42
|
|
|
18
43
|
export interface EffectTRPCAdapter<Requirements> {
|
|
@@ -74,7 +99,7 @@ export interface EffectTRPCAdapter<Requirements> {
|
|
|
74
99
|
export const makeEffectTRPC = <Requirements, RuntimeError = never>(
|
|
75
100
|
options: MakeEffectTRPCOptions<Requirements, RuntimeError>,
|
|
76
101
|
): EffectTRPCAdapter<Requirements> => {
|
|
77
|
-
const contextBridge = makeContextBridge();
|
|
102
|
+
const contextBridge = makeContextBridge(options.runtime);
|
|
78
103
|
const runtime = makeRuntimeBridge(options.runtime, contextBridge, options);
|
|
79
104
|
|
|
80
105
|
return {
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export {
|
|
2
2
|
type EffectTRPCAdapter,
|
|
3
|
+
type EffectTRPCRuntime,
|
|
3
4
|
type MakeEffectTRPCOptions,
|
|
4
5
|
makeEffectTRPC,
|
|
5
6
|
} from "./adapter.js";
|
|
@@ -19,10 +20,12 @@ export {
|
|
|
19
20
|
extendRequestServices,
|
|
20
21
|
makeRequestServices,
|
|
21
22
|
} from "./request-services.js";
|
|
23
|
+
export { RequestSignal } from "./request-signal.js";
|
|
22
24
|
export type {
|
|
23
25
|
EffectTRPCErrorContext,
|
|
24
26
|
EffectTRPCErrorMapper,
|
|
25
27
|
EffectTRPCInstrument,
|
|
28
|
+
EffectTRPCStreamInstrument,
|
|
26
29
|
ProcedureInfo,
|
|
27
30
|
ProcedureKind,
|
|
28
31
|
} from "./types.js";
|
|
@@ -9,7 +9,20 @@ export interface ContextBridge {
|
|
|
9
9
|
) => Value;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export const makeContextBridge = (
|
|
12
|
+
export const makeContextBridge = (shared?: {
|
|
13
|
+
readonly currentServices?: ContextBridge["current"];
|
|
14
|
+
readonly runWithServices?: ContextBridge["run"];
|
|
15
|
+
}): ContextBridge => {
|
|
16
|
+
if (
|
|
17
|
+
shared?.currentServices !== undefined &&
|
|
18
|
+
shared.runWithServices !== undefined
|
|
19
|
+
) {
|
|
20
|
+
return {
|
|
21
|
+
current: shared.currentServices,
|
|
22
|
+
run: shared.runWithServices,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
13
26
|
const storage = new AsyncLocalStorage<Context.Context<never>>();
|
|
14
27
|
|
|
15
28
|
return {
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
TRPCProcedureBuilder,
|
|
4
4
|
TRPCUnsetMarker,
|
|
5
5
|
} from "@trpc/server";
|
|
6
|
-
import type { Effect } from "effect";
|
|
6
|
+
import type { Effect, Stream } from "effect";
|
|
7
7
|
|
|
8
8
|
export type AnyProcedureBuilder = TRPCProcedureBuilder<
|
|
9
9
|
// biome-ignore lint/suspicious/noExplicitAny: tRPC phantom slot extraction
|
|
@@ -47,3 +47,11 @@ export type ProcedureEffect<Requirements> = Effect.Effect<
|
|
|
47
47
|
export type EffectProcedureResolver<Input, Requirements, Output> = (
|
|
48
48
|
input: Input,
|
|
49
49
|
) => Generator<ProcedureEffect<Requirements>, Output, never>;
|
|
50
|
+
|
|
51
|
+
export type EffectSubscriptionResolver<Input, Requirements, Output> = (
|
|
52
|
+
input: Input,
|
|
53
|
+
) => Generator<
|
|
54
|
+
ProcedureEffect<Requirements>,
|
|
55
|
+
Stream.Stream<Output, unknown, Requirements>,
|
|
56
|
+
never
|
|
57
|
+
>;
|
package/src/internal/runtime.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { TRPCError } from "@trpc/server";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
Context,
|
|
5
|
-
Effect,
|
|
6
|
-
Exit,
|
|
7
|
-
type ManagedRuntime,
|
|
8
|
-
Option,
|
|
9
|
-
Result,
|
|
10
|
-
} from "effect";
|
|
2
|
+
import { Cause, Context, Effect, Exit, Option, Result, Stream } from "effect";
|
|
3
|
+
import type { EffectTRPCRuntime } from "../adapter.js";
|
|
11
4
|
import type {
|
|
12
5
|
EffectTRPCErrorMapper,
|
|
13
6
|
EffectTRPCInstrument,
|
|
@@ -26,6 +19,10 @@ export interface RuntimeBridge<Requirements> {
|
|
|
26
19
|
effect: Effect.Effect<Value, unknown, Requirements>,
|
|
27
20
|
options: RunEffectOptions,
|
|
28
21
|
) => Promise<Value>;
|
|
22
|
+
readonly runStream: <Value>(
|
|
23
|
+
stream: Stream.Stream<Value, unknown, Requirements>,
|
|
24
|
+
options: RunEffectOptions,
|
|
25
|
+
) => Promise<AsyncIterable<Value>>;
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
const internalError = (cause?: unknown): TRPCError =>
|
|
@@ -54,11 +51,50 @@ const mapError = (
|
|
|
54
51
|
}
|
|
55
52
|
};
|
|
56
53
|
|
|
54
|
+
const mapCause = (
|
|
55
|
+
cause: Cause.Cause<unknown>,
|
|
56
|
+
procedure: ProcedureInfo,
|
|
57
|
+
consumerMapper: EffectTRPCErrorMapper | undefined,
|
|
58
|
+
): TRPCError => {
|
|
59
|
+
if (Cause.hasInterruptsOnly(cause)) {
|
|
60
|
+
return new TRPCError({
|
|
61
|
+
code: "CLIENT_CLOSED_REQUEST",
|
|
62
|
+
message: "Request cancelled",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const failure = Cause.findErrorOption(cause);
|
|
67
|
+
if (Option.isSome(failure)) {
|
|
68
|
+
return mapError(failure.value, "failure", procedure, consumerMapper);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const defect = Cause.findDefect(cause);
|
|
72
|
+
if (Result.isSuccess(defect)) {
|
|
73
|
+
return mapError(defect.success, "defect", procedure, consumerMapper);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return internalError();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const interruptOn = (signal: AbortSignal | undefined): Effect.Effect<void> => {
|
|
80
|
+
if (signal === undefined) return Effect.never;
|
|
81
|
+
return Effect.callback<void>((resume) => {
|
|
82
|
+
if (signal.aborted) {
|
|
83
|
+
resume(Effect.void);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const abort = () => resume(Effect.void);
|
|
87
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
88
|
+
return Effect.sync(() => signal.removeEventListener("abort", abort));
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
57
92
|
export const makeRuntimeBridge = <Requirements, RuntimeError>(
|
|
58
|
-
runtime:
|
|
93
|
+
runtime: EffectTRPCRuntime<Requirements, RuntimeError>,
|
|
59
94
|
contextBridge: ContextBridge,
|
|
60
95
|
options: {
|
|
61
96
|
readonly instrument?: EffectTRPCInstrument;
|
|
97
|
+
readonly instrumentStream?: import("../types.js").EffectTRPCStreamInstrument;
|
|
62
98
|
readonly mapError?: EffectTRPCErrorMapper;
|
|
63
99
|
},
|
|
64
100
|
): RuntimeBridge<Requirements> => ({
|
|
@@ -68,6 +104,31 @@ export const makeRuntimeBridge = <Requirements, RuntimeError>(
|
|
|
68
104
|
? effect
|
|
69
105
|
: options.instrument(effect, procedure),
|
|
70
106
|
),
|
|
107
|
+
runStream: async (stream, runOptions) => {
|
|
108
|
+
const instrumented = Stream.suspend(() =>
|
|
109
|
+
options.instrumentStream === undefined
|
|
110
|
+
? stream
|
|
111
|
+
: options.instrumentStream(stream, runOptions.procedure),
|
|
112
|
+
).pipe(
|
|
113
|
+
Stream.withSpan(runOptions.procedure.path, {
|
|
114
|
+
attributes: {
|
|
115
|
+
"rpc.method": runOptions.procedure.path,
|
|
116
|
+
"rpc.system": "trpc",
|
|
117
|
+
"trpc.type": runOptions.procedure.type,
|
|
118
|
+
},
|
|
119
|
+
captureStackTrace: runOptions.procedure.captureStackTrace,
|
|
120
|
+
}),
|
|
121
|
+
Stream.interruptWhen(interruptOn(runOptions.signal)),
|
|
122
|
+
Stream.catchCause((cause) =>
|
|
123
|
+
Stream.fail(mapCause(cause, runOptions.procedure, options.mapError)),
|
|
124
|
+
),
|
|
125
|
+
);
|
|
126
|
+
const context = await runtime.runPromise(Effect.context<Requirements>());
|
|
127
|
+
const ambient = contextBridge.current();
|
|
128
|
+
const provided =
|
|
129
|
+
ambient === undefined ? context : Context.merge(context, ambient);
|
|
130
|
+
return Stream.toAsyncIterableWith(instrumented, provided);
|
|
131
|
+
},
|
|
71
132
|
runEffect: async (effect, runOptions) => {
|
|
72
133
|
const traced = effect.pipe(
|
|
73
134
|
Effect.withSpan(
|
|
@@ -101,33 +162,6 @@ export const makeRuntimeBridge = <Requirements, RuntimeError>(
|
|
|
101
162
|
if (Exit.isSuccess(exit)) {
|
|
102
163
|
return exit.value;
|
|
103
164
|
}
|
|
104
|
-
|
|
105
|
-
throw new TRPCError({
|
|
106
|
-
code: "CLIENT_CLOSED_REQUEST",
|
|
107
|
-
message: "Request cancelled",
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const failure = Cause.findErrorOption(exit.cause);
|
|
112
|
-
if (Option.isSome(failure)) {
|
|
113
|
-
throw mapError(
|
|
114
|
-
failure.value,
|
|
115
|
-
"failure",
|
|
116
|
-
runOptions.procedure,
|
|
117
|
-
options.mapError,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const defect = Cause.findDefect(exit.cause);
|
|
122
|
-
if (Result.isSuccess(defect)) {
|
|
123
|
-
throw mapError(
|
|
124
|
-
defect.success,
|
|
125
|
-
"defect",
|
|
126
|
-
runOptions.procedure,
|
|
127
|
-
options.mapError,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
throw internalError();
|
|
165
|
+
throw mapCause(exit.cause, runOptions.procedure, options.mapError);
|
|
132
166
|
},
|
|
133
167
|
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Effect, Layer, Schema, Stream } from "effect";
|
|
2
|
+
import type { EffectProcedureRequestServices } from "../request-services.js";
|
|
3
|
+
import { RequestSignal } from "../request-signal.js";
|
|
4
|
+
import type { ProcedureInfo } from "../types.js";
|
|
5
|
+
import type { EffectSubscriptionResolver } from "./procedure-types.js";
|
|
6
|
+
import type { RuntimeBridge } from "./runtime.js";
|
|
7
|
+
|
|
8
|
+
interface SubscriptionInvocation<Context, Input> {
|
|
9
|
+
readonly ctx: Context;
|
|
10
|
+
readonly input: Input;
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly signal?: AbortSignal;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const makeSubscriptionHandler = <
|
|
16
|
+
RuntimeRequirements,
|
|
17
|
+
Context,
|
|
18
|
+
Input,
|
|
19
|
+
ProvidedServices,
|
|
20
|
+
LayerError,
|
|
21
|
+
Output,
|
|
22
|
+
>(
|
|
23
|
+
runtime: RuntimeBridge<RuntimeRequirements>,
|
|
24
|
+
resolver: EffectSubscriptionResolver<
|
|
25
|
+
Input,
|
|
26
|
+
ProvidedServices | NoInfer<RuntimeRequirements>,
|
|
27
|
+
Output
|
|
28
|
+
>,
|
|
29
|
+
requestServices: EffectProcedureRequestServices<
|
|
30
|
+
Context,
|
|
31
|
+
ProvidedServices,
|
|
32
|
+
LayerError
|
|
33
|
+
>,
|
|
34
|
+
procedure: Omit<ProcedureInfo, "path">,
|
|
35
|
+
outputSchema?: Schema.ConstraintDecoder<unknown>,
|
|
36
|
+
) => {
|
|
37
|
+
const tracedResolver = Effect.fnUntraced(resolver);
|
|
38
|
+
|
|
39
|
+
return async (invocation: SubscriptionInvocation<Context, Input>) => {
|
|
40
|
+
const info = { ...procedure, path: invocation.path };
|
|
41
|
+
const requestLayer = Layer.merge(
|
|
42
|
+
requestServices.layer(invocation.ctx),
|
|
43
|
+
Layer.succeed(RequestSignal, invocation.signal),
|
|
44
|
+
);
|
|
45
|
+
let stream = Stream.unwrap(
|
|
46
|
+
Effect.suspend(() =>
|
|
47
|
+
runtime.instrument(tracedResolver(invocation.input), info),
|
|
48
|
+
),
|
|
49
|
+
).pipe(Stream.provide(requestLayer));
|
|
50
|
+
if (outputSchema !== undefined) {
|
|
51
|
+
stream = Stream.mapEffect(stream, (value) =>
|
|
52
|
+
Schema.decodeUnknownEffect(outputSchema)(value),
|
|
53
|
+
) as typeof stream;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return await runtime.runStream(stream, {
|
|
57
|
+
procedure: info,
|
|
58
|
+
...(invocation.signal === undefined ? {} : { signal: invocation.signal }),
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
};
|
package/src/procedure.ts
CHANGED
|
@@ -2,17 +2,20 @@ import type {
|
|
|
2
2
|
TRPCMutationProcedure,
|
|
3
3
|
TRPCProcedureBuilder,
|
|
4
4
|
TRPCQueryProcedure,
|
|
5
|
+
TRPCSubscriptionProcedure,
|
|
5
6
|
} from "@trpc/server";
|
|
6
7
|
import { Schema } from "effect";
|
|
7
8
|
import { makeProcedureHandler } from "./internal/procedure-handler.js";
|
|
8
9
|
import type {
|
|
9
10
|
DefaultValue,
|
|
10
11
|
EffectProcedureResolver,
|
|
12
|
+
EffectSubscriptionResolver,
|
|
11
13
|
IntersectIfDefined,
|
|
12
14
|
ResolverContext,
|
|
13
15
|
} from "./internal/procedure-types.js";
|
|
14
16
|
import type { RuntimeBridge } from "./internal/runtime.js";
|
|
15
17
|
import { captureStackTrace } from "./internal/stack-trace.js";
|
|
18
|
+
import { makeSubscriptionHandler } from "./internal/subscription-handler.js";
|
|
16
19
|
import type { EffectProcedureRequestServices } from "./request-services.js";
|
|
17
20
|
|
|
18
21
|
type Builder<
|
|
@@ -72,6 +75,8 @@ export class EffectProcedureBuilder<
|
|
|
72
75
|
LayerError
|
|
73
76
|
>,
|
|
74
77
|
private readonly runtime: RuntimeBridge<RuntimeRequirements>,
|
|
78
|
+
private readonly subscriptionBuilder = builder,
|
|
79
|
+
private readonly subscriptionOutput?: Schema.ConstraintDecoder<unknown>,
|
|
75
80
|
) {}
|
|
76
81
|
|
|
77
82
|
input<SchemaValue extends Schema.ConstraintDecoder<unknown>>(
|
|
@@ -89,6 +94,9 @@ export class EffectProcedureBuilder<
|
|
|
89
94
|
RuntimeRequirements
|
|
90
95
|
> {
|
|
91
96
|
const next = this.builder.input(Schema.toStandardSchemaV1(schema) as never);
|
|
97
|
+
const subscriptionNext = this.subscriptionBuilder.input(
|
|
98
|
+
Schema.toStandardSchemaV1(schema) as never,
|
|
99
|
+
);
|
|
92
100
|
return new EffectProcedureBuilder(
|
|
93
101
|
next as unknown as Builder<
|
|
94
102
|
Context,
|
|
@@ -101,6 +109,16 @@ export class EffectProcedureBuilder<
|
|
|
101
109
|
>,
|
|
102
110
|
this.requestServices,
|
|
103
111
|
this.runtime,
|
|
112
|
+
subscriptionNext as unknown as Builder<
|
|
113
|
+
Context,
|
|
114
|
+
Meta,
|
|
115
|
+
ContextOverrides,
|
|
116
|
+
IntersectIfDefined<InputIn, SchemaValue["Encoded"]>,
|
|
117
|
+
IntersectIfDefined<InputOut, SchemaValue["Type"]>,
|
|
118
|
+
OutputIn,
|
|
119
|
+
OutputOut
|
|
120
|
+
>,
|
|
121
|
+
this.subscriptionOutput,
|
|
104
122
|
);
|
|
105
123
|
}
|
|
106
124
|
|
|
@@ -131,6 +149,16 @@ export class EffectProcedureBuilder<
|
|
|
131
149
|
>,
|
|
132
150
|
this.requestServices,
|
|
133
151
|
this.runtime,
|
|
152
|
+
this.subscriptionBuilder as unknown as Builder<
|
|
153
|
+
Context,
|
|
154
|
+
Meta,
|
|
155
|
+
ContextOverrides,
|
|
156
|
+
InputIn,
|
|
157
|
+
InputOut,
|
|
158
|
+
IntersectIfDefined<OutputIn, SchemaValue["Encoded"]>,
|
|
159
|
+
IntersectIfDefined<OutputOut, SchemaValue["Type"]>
|
|
160
|
+
>,
|
|
161
|
+
schema,
|
|
134
162
|
);
|
|
135
163
|
}
|
|
136
164
|
|
|
@@ -170,6 +198,36 @@ export class EffectProcedureBuilder<
|
|
|
170
198
|
}>;
|
|
171
199
|
}
|
|
172
200
|
|
|
201
|
+
subscription<Output>(
|
|
202
|
+
resolver: EffectSubscriptionResolver<
|
|
203
|
+
DefaultValue<InputOut, undefined>,
|
|
204
|
+
ProvidedServices | NoInfer<RuntimeRequirements>,
|
|
205
|
+
DefaultValue<OutputIn, Output>
|
|
206
|
+
>,
|
|
207
|
+
): TRPCSubscriptionProcedure<{
|
|
208
|
+
input: DefaultValue<InputIn, void>;
|
|
209
|
+
output: AsyncIterable<DefaultValue<OutputOut, Output>, void, unknown>;
|
|
210
|
+
meta: Meta;
|
|
211
|
+
}> {
|
|
212
|
+
const handler = makeSubscriptionHandler(
|
|
213
|
+
this.runtime,
|
|
214
|
+
resolver,
|
|
215
|
+
this.requestServices,
|
|
216
|
+
{
|
|
217
|
+
captureStackTrace: captureStackTrace(),
|
|
218
|
+
type: "subscription",
|
|
219
|
+
},
|
|
220
|
+
this.subscriptionOutput,
|
|
221
|
+
) as never;
|
|
222
|
+
return this.subscriptionBuilder.subscription(
|
|
223
|
+
handler,
|
|
224
|
+
) as TRPCSubscriptionProcedure<{
|
|
225
|
+
input: DefaultValue<InputIn, void>;
|
|
226
|
+
output: AsyncIterable<DefaultValue<OutputOut, Output>, void, unknown>;
|
|
227
|
+
meta: Meta;
|
|
228
|
+
}>;
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
private dispatch<Output>(
|
|
174
232
|
type: "mutation" | "query",
|
|
175
233
|
resolver: EffectProcedureResolver<
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
|
|
3
|
+
/** The transport cancellation signal for the current tRPC procedure. */
|
|
4
|
+
export const RequestSignal = Context.Reference<AbortSignal | undefined>(
|
|
5
|
+
"@shivaedev/effect-trpc/RequestSignal",
|
|
6
|
+
{ defaultValue: () => undefined },
|
|
7
|
+
);
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TRPCError } from "@trpc/server";
|
|
2
|
-
import type { Effect } from "effect";
|
|
2
|
+
import type { Effect, Stream } from "effect";
|
|
3
3
|
|
|
4
|
-
export type ProcedureKind = "mutation" | "query";
|
|
4
|
+
export type ProcedureKind = "mutation" | "query" | "subscription";
|
|
5
5
|
|
|
6
6
|
export interface ProcedureInfo {
|
|
7
7
|
readonly captureStackTrace: () => string | undefined;
|
|
@@ -22,3 +22,8 @@ export type EffectTRPCInstrument = <A, E, R>(
|
|
|
22
22
|
effect: Effect.Effect<A, E, R>,
|
|
23
23
|
procedure: ProcedureInfo,
|
|
24
24
|
) => Effect.Effect<A, E, R>;
|
|
25
|
+
|
|
26
|
+
export type EffectTRPCStreamInstrument = <A, E, R>(
|
|
27
|
+
stream: Stream.Stream<A, E, R>,
|
|
28
|
+
procedure: ProcedureInfo,
|
|
29
|
+
) => Stream.Stream<A, E, R>;
|