Socket
Socket
Sign inDemoInstall

@effect/rpc

Package Overview
Dependencies
Maintainers
3
Versions
262
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@effect/rpc - npm Package Compare versions

Comparing version 0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49 to 0.0.0-snapshot-e0f0eba005ab024d629f3728d81590db23057c74

dist/cjs/internal/rpc.js

18

dist/cjs/index.js

@@ -6,17 +6,11 @@ "use strict";

});
exports.Server = exports.SchemaC = exports.Schema = exports.Router = exports.Resolver = exports.Error = exports.Client = void 0;
var _Client = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Client.js"));
exports.Client = _Client;
var _Error = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Error.js"));
exports.Error = _Error;
exports.Rpc = exports.Router = exports.ResolverNoStream = exports.Resolver = void 0;
var _Resolver = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Resolver.js"));
exports.Resolver = _Resolver;
var _ResolverNoStream = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./ResolverNoStream.js"));
exports.ResolverNoStream = _ResolverNoStream;
var _Router = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Router.js"));
exports.Router = _Router;
var _Schema = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Schema.js"));
exports.Schema = _Schema;
var _SchemaC = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./SchemaC.js"));
exports.SchemaC = _SchemaC;
var _Server = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Server.js"));
exports.Server = _Server;
var _Rpc = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Rpc.js"));
exports.Rpc = _Rpc;
function _getRequireWildcardCache(e) {

@@ -41,3 +35,3 @@ if ("function" != typeof WeakMap) return null;

a = Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) {
for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;

@@ -44,0 +38,0 @@ i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];

@@ -6,4 +6,16 @@ "use strict";

});
exports.makeWithSchema = exports.makeSingleWithSchema = exports.makeSingle = exports.make = void 0;
var internal = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./internal/resolver.js"));
exports.toClient = exports.make = exports.annotateHeadersEffect = exports.annotateHeaders = void 0;
var Headers = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/platform/Http/Headers"));
var Schema = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Schema"));
var Serializable = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Serializable"));
var Arr = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array"));
var Cause = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Cause"));
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect"));
var Exit = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Exit"));
var _Function = /*#__PURE__*/require("effect/Function");
var Request = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Request"));
var RequestResolver = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/RequestResolver"));
var Stream = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Stream"));
var _rpc = /*#__PURE__*/require("./internal/rpc.js");
var Rpc = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Rpc.js"));
function _getRequireWildcardCache(e) {

@@ -28,3 +40,3 @@ if ("function" != typeof WeakMap) return null;

a = Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) {
for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;

@@ -36,21 +48,81 @@ i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];

/**
* @category constructors
* @since 1.0.0
*/
const make = exports.make = internal.make;
/**
* @since 1.0.0
* @category constructors
*/
const make = handler => () => {
const getDecode = (0, _rpc.withRequestTag)(req => Schema.decodeUnknown(Serializable.exitSchema(req)));
const getDecodeChunk = (0, _rpc.withRequestTag)(req => Schema.decodeUnknown(Schema.Chunk(Serializable.exitSchema(req))));
return RequestResolver.makeBatched(requests => {
const [effectRequests, streamRequests] = Arr.partition(requests, _ => _rpc.StreamRequestTypeId in _.request);
const processEffects = (0, _Function.pipe)(Effect.forEach(effectRequests, _ => Effect.map(Serializable.serialize(_.request), request => ({
..._,
request
}))), Effect.flatMap(payload => Stream.runForEach(Stream.filter(handler(payload), _ => Arr.isArray(_) && _.length === 2), ([index, response]) => {
const request = effectRequests[index];
return Effect.matchCauseEffect(Effect.orDie(getDecode(request.request)(response)), {
onFailure: cause => Request.failCause(request, cause),
onSuccess: exit => Request.complete(request, exit)
});
})), Effect.orDie, Effect.catchAllCause(cause => Effect.forEach(effectRequests, request => Request.failCause(request, cause), {
discard: true
})));
const processStreams = (0, _Function.pipe)(Effect.forEach(streamRequests, request => {
const decode = getDecodeChunk(request.request);
const stream = (0, _Function.pipe)(Serializable.serialize(request.request), Effect.map(_ => ({
...request,
request: _
})), Effect.map(payload => (0, _Function.pipe)(handler([payload]), Stream.mapEffect(_ => Effect.orDie(decode(_[1]))), Stream.flattenChunks, Stream.flatMap(Exit.match({
onFailure: cause => Cause.isEmptyType(cause) ? Stream.empty : Stream.failCause(cause),
onSuccess: Stream.succeed
})))), Effect.orDie, Stream.unwrap);
return Request.succeed(request, stream);
}, {
discard: true
}), Effect.catchAllCause(cause => Effect.forEach(streamRequests, request => Request.failCause(request, cause), {
discard: true
})));
return Effect.zipRight(processStreams, processEffects);
});
};
/**
* @since 1.0.0
* @category combinators
*/
const makeWithSchema = exports.makeWithSchema = internal.makeWithSchema;
exports.make = make;
const annotateHeaders = exports.annotateHeaders = /*#__PURE__*/(0, _Function.dual)(2, (self, headers) => {
const resolved = Headers.fromInput(headers);
return RequestResolver.makeWithEntry(requests => {
requests.forEach(entries => entries.forEach(entry => {
;
entry.request.headers = Headers.merge(entry.request.headers, resolved);
}));
return self.runAll(requests);
});
});
/**
* @category constructors
* @since 1.0.0
* @category combinators
*/
const makeSingle = exports.makeSingle = internal.makeSingle;
const annotateHeadersEffect = exports.annotateHeadersEffect = /*#__PURE__*/(0, _Function.dual)(2, (self, headers) => RequestResolver.makeWithEntry(requests => headers.pipe(Effect.map(Headers.fromInput), Effect.orDie, Effect.matchCauseEffect({
onFailure: cause => Effect.forEach(requests.flat(), entry => Request.failCause(entry.request, cause), {
discard: true
}),
onSuccess: resolved => {
requests.forEach(entries => entries.forEach(entry => {
;
entry.request.headers = Headers.merge(entry.request.headers, resolved);
}));
return self.runAll(requests);
}
}))));
/**
* @category constructors
* @since 1.0.0
* @category combinators
*/
const makeSingleWithSchema = exports.makeSingleWithSchema = internal.makeSingleWithSchema;
const toClient = (resolver, options) => request => Rpc.call(request, resolver, options);
exports.toClient = toClient;
//# sourceMappingURL=Resolver.js.map

@@ -6,4 +6,18 @@ "use strict";

});
exports.provideServiceSync = exports.provideServiceEffect = exports.provideService = exports.make = void 0;
var internal = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./internal/router.js"));
exports.toHandlerUndecoded = exports.toHandlerRaw = exports.toHandlerEffect = exports.toHandler = exports.provideServiceEffect = exports.provideService = exports.make = exports.isRouter = exports.TypeId = void 0;
var Schema = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Schema"));
var Serializable = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Serializable"));
var Cause = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Cause"));
var Channel = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Channel"));
var Chunk = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Chunk"));
var Context = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Context"));
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect"));
var Exit = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Exit"));
var _Function = /*#__PURE__*/require("effect/Function");
var _Pipeable = /*#__PURE__*/require("effect/Pipeable");
var Predicate = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Predicate"));
var Queue = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Queue"));
var Stream = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Stream"));
var _rpc = /*#__PURE__*/require("./internal/rpc.js");
var Rpc = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Rpc.js"));
function _getRequireWildcardCache(e) {

@@ -28,3 +42,3 @@ if ("function" != typeof WeakMap) return null;

a = Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) {
for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;

@@ -36,21 +50,199 @@ i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];

/**
* @category router constructors
* @since 1.0.0
* @category type ids
*/
const make = exports.make = internal.make;
const TypeId = exports.TypeId = /*#__PURE__*/Symbol.for("@effect/rpc/Router");
/**
* @category router combinators
* @since 1.0.0
* @category refinements
*/
const provideService = exports.provideService = internal.provideService;
const isRouter = u => Predicate.hasProperty(u, TypeId);
exports.isRouter = isRouter;
const fromSet = rpcs => ({
[TypeId]: TypeId,
rpcs,
pipe() {
return (0, _Pipeable.pipeArguments)(this, arguments);
}
});
/**
* @category router combinators
* @since 1.0.0
* @category constructors
*/
const provideServiceEffect = exports.provideServiceEffect = internal.provideServiceEffect;
const make = (...rpcs) => {
const rpcSet = new Set();
rpcs.forEach(rpc => {
if (isRouter(rpc)) {
rpc.rpcs.forEach(rpc => rpcSet.add(rpc));
} else {
rpcSet.add(rpc);
}
});
return fromSet(rpcSet);
};
/**
* @category router combinators
* @since 1.0.0
* @category context
*/
const provideServiceSync = exports.provideServiceSync = internal.provideServiceSync;
exports.make = make;
const provideServiceEffect = exports.provideServiceEffect = /*#__PURE__*/(0, _Function.dual)(3, (self, tag, effect) => fromSet(new Set([...self.rpcs].map(Rpc.provideServiceEffect(tag, effect)))));
/**
* @since 1.0.0
* @category context
*/
const provideService = exports.provideService = /*#__PURE__*/(0, _Function.dual)(3, (self, tag, service) => fromSet(new Set([...self.rpcs].map(Rpc.provideService(tag, service)))));
const EOF = /*#__PURE__*/Symbol.for("@effect/rpc/Router/EOF");
const channelFromQueue = queue => {
const loop = Channel.flatMap(Queue.takeBetween(queue, 1, Number.MAX_SAFE_INTEGER), chunk => {
if (Chunk.unsafeLast(chunk) === EOF) {
return Channel.write(Chunk.dropRight(chunk, 1));
}
return Channel.zipRight(Channel.write(chunk), loop);
});
return loop;
};
const emptyExit = /*#__PURE__*/Schema.encodeSync(Schema.Exit({
failure: Schema.Never,
success: Schema.Never
}))( /*#__PURE__*/Exit.failCause(Cause.empty));
/**
* @since 1.0.0
* @category combinators
*/
const toHandler = (router, options) => {
const spanPrefix = options?.spanPrefix ?? "Rpc.router ";
const schema = Schema.Union(...[...router.rpcs].map(rpc => Schema.transform(rpc.schema, Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)), {
decode: request => [request, rpc],
encode: ([request]) => request
})));
const schemaArray = Schema.Array(Rpc.RequestSchema(schema));
const decode = Schema.decodeUnknown(schemaArray);
const getEncode = (0, _rpc.withRequestTag)(req => Schema.encode(Serializable.exitSchema(req)));
const getEncodeChunk = (0, _rpc.withRequestTag)(req => Schema.encode(Schema.Chunk(Serializable.exitSchema(req))));
return u => (0, _Function.pipe)(decode(u), Effect.zip(Queue.unbounded()), Effect.tap(([requests, queue]) => (0, _Function.pipe)(Effect.forEach(requests, (req, index) => {
const [request, rpc] = req.request;
if (rpc._tag === "Effect") {
const encode = getEncode(request);
return (0, _Function.pipe)(Effect.exit(rpc.handler(request)), Effect.flatMap(encode), Effect.orDie, Effect.matchCauseEffect({
onSuccess: response => Queue.offer(queue, [index, response]),
onFailure: cause => Effect.flatMap(encode(Exit.failCause(cause)), response => Queue.offer(queue, [index, response]))
}), Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}
const encode = getEncodeChunk(request);
return (0, _Function.pipe)(rpc.handler(request), Stream.toChannel, Channel.mapOutEffect(chunk => Effect.flatMap(encode(Chunk.map(chunk, Exit.succeed)), response => Queue.offer(queue, [index, response]))), Channel.runDrain, Effect.matchCauseEffect({
onSuccess: () => Queue.offer(queue, [index, [emptyExit]]),
onFailure: cause => Effect.flatMap(encode(Chunk.of(Exit.failCause(cause))), response => Queue.offer(queue, [index, response]))
}), Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}, {
concurrency: "unbounded",
discard: true
}), Effect.ensuring(Queue.offer(queue, EOF)), Effect.fork)), Effect.map(([_, queue]) => Stream.fromChannel(channelFromQueue(queue))), Stream.unwrap);
};
/**
* @since 1.0.0
* @category combinators
*/
exports.toHandler = toHandler;
const toHandlerEffect = (router, options) => {
const spanPrefix = options?.spanPrefix ?? "Rpc.router ";
const schema = Schema.Union(...[...router.rpcs].map(rpc => Schema.transform(rpc.schema, Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)), {
decode: request => [request, rpc],
encode: ([request]) => request
})));
const schemaArray = Schema.Array(Rpc.RequestSchema(schema));
const decode = Schema.decodeUnknown(schemaArray);
const getEncode = (0, _rpc.withRequestTag)(req => Schema.encode(Serializable.exitSchema(req)));
const getEncodeChunk = (0, _rpc.withRequestTag)(req => Schema.encode(Schema.Chunk(Serializable.exitSchema(req))));
return u => Effect.flatMap(decode(u), Effect.forEach(req => {
const [request, rpc] = req.request;
if (rpc._tag === "Effect") {
const encode = getEncode(request);
return (0, _Function.pipe)(Effect.exit(rpc.handler(request)), Effect.flatMap(encode), Effect.orDie, Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}
const encode = getEncodeChunk(request);
return (0, _Function.pipe)(rpc.handler(request), Stream.map(Exit.succeed), Stream.catchAllCause(cause => Stream.succeed(Exit.failCause(cause))), Stream.runCollect, Effect.flatMap(encode), Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}, {
concurrency: "unbounded"
}));
};
/**
* @since 1.0.0
* @category combinators
*/
exports.toHandlerEffect = toHandlerEffect;
const toHandlerRaw = router => {
const schema = Schema.Union(...[...router.rpcs].map(rpc => Schema.transform(Schema.typeSchema(rpc.schema), Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)), {
decode: request => [request, rpc],
encode: ([request]) => request
})));
const parse = Schema.decode(schema);
return request => {
const isStream = (_rpc.StreamRequestTypeId in request);
const withHandler = parse(request);
if (isStream) {
return Stream.unwrap(Effect.map(withHandler, ([request, rpc]) => rpc.handler(request)));
}
return Effect.flatMap(withHandler, ([request, rpc]) => rpc.handler(request));
};
};
/**
* @since 1.0.0
* @category combinators
*/
exports.toHandlerRaw = toHandlerRaw;
const toHandlerUndecoded = router => {
const handler = toHandlerRaw(router);
const getEncode = (0, _rpc.withRequestTag)(req => Schema.encode(Serializable.successSchema(req)));
const getEncodeChunk = (0, _rpc.withRequestTag)(req => Schema.encode(Schema.ChunkFromSelf(Serializable.successSchema(req))));
return request => {
const result = handler(request);
if (Effect.isEffect(result)) {
const encode = getEncode(request);
return Effect.flatMap(result, encode);
}
const encode = getEncodeChunk(request);
return Stream.mapChunksEffect(result, encode);
};
};
exports.toHandlerUndecoded = toHandlerUndecoded;
//# sourceMappingURL=Router.js.map
/**
* @since 1.0.0
*/
export * as Client from "./Client.js";
export * as Resolver from "./Resolver.js";
/**
* @since 1.0.0
*/
export * as Error from "./Error.js";
export * as ResolverNoStream from "./ResolverNoStream.js";
/**
* @since 1.0.0
*/
export * as Resolver from "./Resolver.js";
/**
* @since 1.0.0
*/
export * as Router from "./Router.js";

@@ -20,11 +16,3 @@ /**

*/
export * as Schema from "./Schema.js";
/**
* @since 1.0.0
*/
export * as SchemaC from "./SchemaC.js";
/**
* @since 1.0.0
*/
export * as Server from "./Server.js";
export * as Rpc from "./Rpc.js";
//# sourceMappingURL=index.d.ts.map
/**
* @since 1.0.0
*/
import type * as Effect from "effect/Effect";
import type * as Request from "effect/Request";
import type * as Resolver from "effect/RequestResolver";
import type { RpcError, RpcTransportError } from "./Error.js";
import type { RpcSchema } from "./Schema.js";
import * as Headers from "@effect/platform/Http/Headers";
import * as Schema from "@effect/schema/Schema";
import * as Serializable from "@effect/schema/Serializable";
import * as Effect from "effect/Effect";
import * as RequestResolver from "effect/RequestResolver";
import * as Stream from "effect/Stream";
import type * as Router from "./Router.js";
import * as Rpc from "./Rpc.js";
/**
* @category models
* @since 1.0.0
* @category constructors
*/
export interface RpcResolver<R> extends Resolver.RequestResolver<RpcRequest, R> {
}
export declare const make: <HR, E>(handler: (u: ReadonlyArray<unknown>) => Stream.Stream<unknown, E, HR>) => <R extends Router.Router<any, any>>() => RequestResolver.RequestResolver<Rpc.Request<Router.Router.Request<R>>, Serializable.SerializableWithResult.Context<Router.Router.Request<R>> | HR>;
/**
* @category models
* @since 1.0.0
* @category combinators
*/
export interface RpcRequest extends Request.Request<RpcError, unknown> {
readonly payload: RpcRequest.Payload;
readonly hash: number;
readonly schema: RpcSchema.Any;
}
export declare const annotateHeaders: {
(headers: Headers.Input): <Req extends Schema.TaggedRequest.Any, R>(self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>) => RequestResolver.RequestResolver<Rpc.Request<Req>, R>;
<Req extends Schema.TaggedRequest.Any, R>(self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>, headers: Headers.Input): RequestResolver.RequestResolver<Rpc.Request<Req>, R>;
};
/**
* @since 1.0.0
* @category combinators
*/
export declare namespace RpcRequest {
/**
* @category models
* @since 1.0.0
*/
interface Tracing {
readonly spanName: string;
readonly traceId: string;
readonly spanId: string;
readonly sampled: boolean;
}
/**
* @category models
* @since 1.0.0
*/
interface Payload extends Tracing {
readonly _tag: string;
readonly input?: unknown;
}
/**
* @category models
* @since 1.0.0
*/
interface WithInput<M extends string, I> extends Tracing {
readonly _tag: M;
readonly input: I;
}
/**
* @category models
* @since 1.0.0
*/
interface NoInput<M extends string> extends Tracing {
readonly _tag: M;
}
}
export declare const annotateHeadersEffect: {
<E, R2>(headers: Effect.Effect<Headers.Input, E, R2>): <Req extends Schema.TaggedRequest.Any, R>(self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>) => RequestResolver.RequestResolver<Rpc.Request<Req>, R | R2>;
<Req extends Schema.TaggedRequest.Any, R, E, R2>(self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>, headers: Effect.Effect<Headers.Input, E, R2>): RequestResolver.RequestResolver<Rpc.Request<Req>, R | R2>;
};
/**
* @since 1.0.0
* @category models
* @since 1.0.0
*/
export type RpcResponse = RpcResponse.Error | RpcResponse.Success;
export type Client<R extends RequestResolver.RequestResolver<Rpc.Request<any>, never> | Effect.Effect<RequestResolver.RequestResolver<Rpc.Request<any>, never>, never, any>> = R extends Effect.Effect<RequestResolver.RequestResolver<Rpc.Request<infer RReq>>, infer _E, infer R> ? (<Req extends RReq>(request: Req) => Rpc.Rpc.Result<Req, R>) : R extends RequestResolver.RequestResolver<Rpc.Request<infer RReq>, never> ? (<Req extends RReq>(request: Req) => Rpc.Rpc.Result<Req>) : never;
/**
* @since 1.0.0
* @category combinators
*/
export declare namespace RpcResponse {
/**
* @category models
* @since 1.0.0
*/
interface Error {
readonly _tag: "Error";
error: RpcError;
}
/**
* @category models
* @since 1.0.0
*/
interface Success {
readonly _tag: "Success";
value: unknown;
}
}
/**
* @category constructors
* @since 1.0.0
*/
export declare const make: <R>(send: (requests: ReadonlyArray<RpcRequest.Payload>) => Effect.Effect<unknown, RpcTransportError, R>) => RpcResolver<R>;
/**
* @category constructors
* @since 1.0.0
*/
export declare const makeWithSchema: <R>(send: (requests: ReadonlyArray<RpcRequest>) => Effect.Effect<unknown, RpcTransportError, R>) => RpcResolver<R>;
/**
* @category constructors
* @since 1.0.0
*/
export declare const makeSingle: <R>(send: (request: RpcRequest.Payload) => Effect.Effect<unknown, RpcTransportError, R>) => RpcResolver<R>;
/**
* @category constructors
* @since 1.0.0
*/
export declare const makeSingleWithSchema: <R>(send: (request: RpcRequest) => Effect.Effect<unknown, RpcTransportError, R>) => RpcResolver<R>;
export declare const toClient: <R extends RequestResolver.RequestResolver<Rpc.Request<any>, never> | Effect.Effect<RequestResolver.RequestResolver<Rpc.Request<any>, never>, never, any>>(resolver: R, options?: {
readonly spanPrefix?: string;
}) => Client<R>;
//# sourceMappingURL=Resolver.d.ts.map
/**
* @since 1.0.0
*/
import type { Context, Tag } from "effect/Context";
import type { Effect } from "effect/Effect";
import type { LazyArg } from "effect/Function";
import type { Layer } from "effect/Layer";
import type { RpcSchema, RpcService } from "./Schema.js";
import type { RpcUndecodedClient } from "./Server.js";
import type { ParseError } from "@effect/schema/ParseResult";
import * as Schema from "@effect/schema/Schema";
import * as Serializable from "@effect/schema/Serializable";
import * as Context from "effect/Context";
import * as Effect from "effect/Effect";
import { type Pipeable } from "effect/Pipeable";
import * as Stream from "effect/Stream";
import * as Rpc from "./Rpc.js";
/**
* @category handler models
* @since 1.0.0
* @category type ids
*/
export type RpcHandler<R, E, I, O> = RpcHandler.IO<R, E, I, O> | RpcHandler.IOLayer<R, E, I, O> | RpcHandler.NoInput<R, E, O>;
export declare const TypeId: unique symbol;
/**
* @since 1.0.0
* @category type ids
*/
export declare namespace RpcHandler {
/**
* @category handler models
* @since 1.0.0
*/
type IO<R, E, I, O> = (input: I) => Effect<O, E, R>;
/**
* @category handler models
* @since 1.0.0
*/
type IOLayer<R, E, I, O> = (input: I) => Layer<O, E, R>;
/**
* @category handler models
* @since 1.0.0
*/
type NoInput<R, E, O> = Effect<O, E, R>;
/**
* @category handler models
* @since 1.0.0
*/
type Any = RpcHandler<any, any, any, any>;
/**
* @category handler utils
* @since 1.0.0
*/
type FromSchema<C extends RpcSchema.Any> = C extends RpcSchema.IO<infer _RE, infer _IE, infer E, infer _RI, infer _II, infer I, infer _RO, infer _IO, infer O> ? IO<any, E, I, O> : C extends RpcSchema.NoError<infer _RI, infer _II, infer I, infer _RO, infer _IO, infer O> ? IO<any, never, I, O> : C extends RpcSchema.NoInput<infer _RE, infer _IE, infer E, infer _RO, infer _IO, infer O> ? NoInput<any, E, O> : C extends RpcSchema.NoInputNoError<infer _RO, infer _IO, infer O> ? NoInput<any, never, O> : C extends RpcSchema.NoOutput<infer _RE, infer _IE, infer E, infer _RI, infer _II, infer I> ? IO<any, E, I, void> : C extends RpcSchema.NoErrorNoOutput<infer _RI, infer _II, infer I> ? IO<any, never, I, void> : never;
/**
* @category handler utils
* @since 1.0.0
*/
type FromSetupSchema<C> = C extends RpcSchema.NoOutput<infer _RE, infer _IE, infer E, infer _RI, infer _II, infer I> ? IO<any, E, I, Context<any>> | IOLayer<any, E, I, any> : C extends RpcSchema.NoErrorNoOutput<infer _RI, infer _II, infer I> ? IO<any, never, I, Context<any>> | IOLayer<any, never, I, any> : never;
/**
* @category handler utils
* @since 1.0.0
*/
type FromMethod<H extends RpcHandlers, M, XR, E2> = Extract<RpcHandlers.Map<H, XR, E2>, [
M,
any
]> extends [infer _M, infer T] ? T : never;
}
export type TypeId = typeof TypeId;
/**
* @category handlers models
* @since 1.0.0
* @category refinements
*/
export interface RpcHandlers extends Record<string, RpcHandler.Any | {
readonly handlers: RpcHandlers;
}> {
}
export declare const isRouter: (u: unknown) => u is Router<any, any>;
/**
* @since 1.0.0
* @category models
*/
export declare namespace RpcHandlers {
/**
* @category handlers utils
* @since 1.0.0
*/
type FromService<S extends RpcService.DefinitionWithId, Depth extends ReadonlyArray<number> = []> = {
readonly [K in Extract<keyof S, string>]: S[K] extends RpcService.DefinitionWithId ? Depth["length"] extends 3 ? never : {
readonly handlers: FromService<S[K], [0, ...Depth]>;
} : K extends "__setup" ? RpcHandler.FromSetupSchema<S[K]> : S[K] extends RpcSchema.Any ? RpcHandler.FromSchema<S[K]> : never;
};
/**
* @category handlers utils
* @since 1.0.0
*/
type Services<H extends RpcHandlers, Depth extends ReadonlyArray<number> = []> = keyof H extends infer M ? M extends keyof H ? H[M] extends {
readonly handlers: RpcHandlers;
} ? Depth["length"] extends 3 ? never : Services<H[M]["handlers"], [0, ...Depth]> : H[M] extends RpcHandler<infer R, infer _E, infer _I, infer _O> ? R : never : never : never;
/**
* @category handlers utils
* @since 1.0.0
*/
type Errors<H extends RpcHandlers, Depth extends ReadonlyArray<number> = []> = keyof H extends infer M ? M extends keyof H ? H[M] extends {
readonly handlers: RpcHandlers;
} ? Depth["length"] extends 3 ? never : Errors<H[M]["handlers"], [0, ...Depth]> : H[M] extends RpcHandler<infer _R, infer E, infer _I, infer _O> ? E : never : never : never;
/**
* @category handlers utils
* @since 1.0.0
*/
type Map<H extends RpcHandlers, XR, E2, P extends string = "", Depth extends ReadonlyArray<number> = []> = Extract<keyof H, string> extends infer K ? K extends Extract<keyof H, string> ? H[K] extends {
readonly handlers: RpcHandlers;
} ? Depth["length"] extends 3 ? never : Map<H[K]["handlers"], XR, E2, `${P}${K}.`, [0, ...Depth]> : H[K] extends RpcHandler.IO<infer R, infer E, infer _I, infer O> ? [`${P}${K}`, Effect<O, E | E2, Exclude<R, XR>>] : H[K] extends Effect<infer O, infer E, infer R> ? [`${P}${K}`, Effect<O, E | E2, Exclude<R, XR>>] : never : never : never;
export interface Router<Reqs extends Schema.TaggedRequest.Any, R> extends Pipeable {
readonly [TypeId]: TypeId;
readonly rpcs: ReadonlySet<Rpc.Rpc<Reqs, R>>;
}
/**
* @category router models
* @since 1.0.0
* @category models
*/
export interface RpcRouter<S extends RpcService.DefinitionWithId, H extends RpcHandlers> extends RpcRouter.Base {
readonly handlers: H;
readonly schema: S;
readonly undecoded: RpcUndecodedClient<H>;
}
/**
* @since 1.0.0
*/
export declare namespace RpcRouter {
export declare namespace Router {
/**
* @category router models
* @since 1.0.0
* @category models
*/
interface Base {
readonly handlers: RpcHandlers;
readonly schema: RpcService.DefinitionWithId;
readonly undecoded: any;
readonly options: Options;
}
type Context<A extends Router<any, any>> = A extends Router<infer Req, infer R> ? R | Serializable.SerializableWithResult.Context<Req> : never;
/**
* @category router models
* @since 1.0.0
* @category models
*/
interface WithSetup extends Base {
readonly handlers: RpcHandlers & {
readonly __setup: RpcHandler.Any;
};
}
type ContextRaw<A extends Router<any, any>> = A extends Router<infer Req, infer R> ? R | Serializable.Serializable.Context<Req> : never;
/**
* @category router models
* @since 1.0.0
* @category models
*/
interface WithoutSetup extends Base {
readonly handlers: RpcHandlers & {
readonly __setup?: never;
};
}
type Request<A extends Router<any, any>> = A extends Router<infer Req, infer _R> ? Req : never;
/**
* @category router models
* @since 1.0.0
* @category models
*/
interface Options {
readonly spanPrefix: string;
}
type Response = [
index: number,
response: Schema.ExitEncoded<any, any> | ReadonlyArray<Schema.ExitEncoded<any, any>>
];
/**
* @category router utils
* @since 1.0.0
* @category models
*/
type Provide<Router extends Base, XR, PR, PE, Depth extends ReadonlyArray<number> = []> = RpcRouter<Router["schema"], {
readonly [M in keyof Router["handlers"]]: Router["handlers"][M] extends Base ? Depth["length"] extends 3 ? never : Provide<Router["handlers"][M], XR, PR, PE, [0, ...Depth]> : Router["handlers"][M] extends RpcHandler.IO<infer R, infer E, infer I, infer O> ? RpcHandler.IO<Exclude<R, XR> | PR, E | PE, I, O> : Router["handlers"][M] extends RpcHandler.IOLayer<infer R, infer E, infer I, infer O> ? RpcHandler.IOLayer<Exclude<R, XR> | PR, E | PE, I, O> : Router["handlers"][M] extends RpcHandler.NoInput<infer R, infer E, infer O> ? RpcHandler.NoInput<Exclude<R, XR> | PR, E | PE, O> : never;
}>;
/**
* @category router utils
* @since 1.0.0
*/
type SetupServices<R extends WithSetup> = R["handlers"]["__setup"] extends RpcHandler.IOLayer<infer _R, infer _E, infer _I, infer O> ? O : R["handlers"]["__setup"] extends RpcHandler.IO<infer _R, infer _E, infer _I, infer O> ? O extends Context<infer Env> ? Env : never : never;
/**
* @category router utils
* @since 1.0.0
*/
type Services<R extends Base> = R extends WithSetup ? Exclude<RpcHandlers.Services<R["handlers"]> | RpcSchema.Context<R["schema"]>, SetupServices<R>> : RpcHandlers.Services<R["handlers"]> | RpcSchema.Context<R["schema"]>;
/**
* @category router utils
* @since 1.0.0
*/
type Errors<R extends Base> = RpcHandlers.Errors<R["handlers"]>;
type ResponseEffect = Schema.ExitEncoded<any, any> | ReadonlyArray<Schema.ExitEncoded<any, any>>;
}
/**
* @category router constructors
* @since 1.0.0
* @category constructors
*/
export declare const make: <const S extends RpcService.DefinitionWithId, const H extends RpcHandlers.FromService<S>>(schema: S, handlers: H, options?: Partial<RpcRouter.Options>) => RpcRouter<S, H>;
export declare const make: <Rpcs extends readonly (Rpc.Rpc<any, any> | Router<any, any>)[]>(...rpcs: Rpcs) => Router<Rpc.Rpc.Request<Extract<Rpcs[number], {
readonly [Rpc.TypeId]: Rpc.TypeId;
}>> | Router.Request<Extract<Rpcs[number], {
readonly [TypeId]: TypeId;
}>>, Rpc.Rpc.Context<Extract<Rpcs[number], {
readonly [Rpc.TypeId]: Rpc.TypeId;
}>> | Router.Context<Extract<Rpcs[number], {
readonly [TypeId]: TypeId;
}>>>;
/**
* @category router combinators
* @since 1.0.0
* @category context
*/
export declare const provideService: {
<T extends Tag<any, any>>(tag: T, service: Tag.Service<T>): <const Router extends RpcRouter.Base>(self: Router) => RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>;
<const Router extends RpcRouter.Base, T extends Tag<any, any>>(self: Router, tag: T, service: Tag.Service<T>): RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>;
export declare const provideServiceEffect: {
<I, S, E, R2>(tag: Context.Tag<I, S>, effect: Effect.Effect<S, E, R2>): <Reqs extends Schema.TaggedRequest.Any, R>(self: Router<Reqs, R>) => Router<Reqs, Exclude<R, I> | R2>;
<Reqs extends Schema.TaggedRequest.Any, R, I, S, E, R2>(self: Router<Reqs, R>, tag: Context.Tag<I, S>, effect: Effect.Effect<S, E, R2>): Router<Reqs, Exclude<R, I> | R2>;
};
/**
* @category router combinators
* @since 1.0.0
* @category context
*/
export declare const provideServiceEffect: {
<const Router extends RpcRouter.Base, T extends Tag<any, any>, R, E extends RpcService.Errors<Router["schema"]>>(tag: T, effect: Effect<Tag.Service<T>, E, R>): (self: Router) => RpcRouter.Provide<Router, Tag.Identifier<T>, R, E>;
<const Router extends RpcRouter.Base, T extends Tag<any, any>, R, E extends RpcService.Errors<Router["schema"]>>(self: Router, tag: T, effect: Effect<Tag.Service<T>, E, R>): RpcRouter.Provide<Router, Tag.Identifier<T>, R, E>;
export declare const provideService: {
<I, S>(tag: Context.Tag<I, S>, service: S): <Reqs extends Schema.TaggedRequest.Any, R>(self: Router<Reqs, R>) => Router<Reqs, Exclude<R, I>>;
<Reqs extends Schema.TaggedRequest.Any, R, I, S>(self: Router<Reqs, R>, tag: Context.Tag<I, S>, service: S): Router<Reqs, Exclude<R, I>>;
};
/**
* @category router combinators
* @since 1.0.0
* @category combinators
*/
export declare const provideServiceSync: {
<T extends Tag<any, any>>(tag: T, service: LazyArg<Tag.Service<T>>): <const Router extends RpcRouter.Base>(self: Router) => RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>;
<Router extends RpcRouter.Base, T extends Tag<any, any>>(self: Router, tag: T, service: LazyArg<Tag.Service<T>>): RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>;
};
export declare const toHandler: <R extends Router<any, any>>(router: R, options?: {
readonly spanPrefix?: string;
}) => (u: unknown) => Stream.Stream<Router.Response, ParseError, Router.Context<R>>;
/**
* @since 1.0.0
* @category combinators
*/
export declare const toHandlerEffect: <R extends Router<any, any>>(router: R, options?: {
readonly spanPrefix?: string;
}) => (u: unknown) => Effect.Effect<ReadonlyArray<Router.ResponseEffect>, ParseError, Router.Context<R>>;
/**
* @since 1.0.0
* @category combinators
*/
export declare const toHandlerRaw: <R extends Router<any, any>>(router: R) => <Req extends Router.Request<R>>(request: Req) => Rpc.Rpc.Result<Req, Router.ContextRaw<R>>;
/**
* @since 1.0.0
* @category combinators
*/
export declare const toHandlerUndecoded: <R extends Router<any, any>>(router: R) => <Req extends Router.Request<R>>(request: Req) => Rpc.Rpc.ResultUndecoded<Req, Router.Context<R>>;
//# sourceMappingURL=Router.d.ts.map
/**
* @since 1.0.0
*/
export * as Client from "./Client.js";
export * as Resolver from "./Resolver.js";
/**
* @since 1.0.0
*/
export * as Error from "./Error.js";
export * as ResolverNoStream from "./ResolverNoStream.js";
/**
* @since 1.0.0
*/
export * as Resolver from "./Resolver.js";
/**
* @since 1.0.0
*/
export * as Router from "./Router.js";

@@ -20,11 +16,3 @@ /**

*/
export * as Schema from "./Schema.js";
/**
* @since 1.0.0
*/
export * as SchemaC from "./SchemaC.js";
/**
* @since 1.0.0
*/
export * as Server from "./Server.js";
export * as Rpc from "./Rpc.js";
//# sourceMappingURL=index.js.map

@@ -1,22 +0,91 @@

import * as internal from "./internal/resolver.js";
/**
* @category constructors
* @since 1.0.0
*/
export const make = internal.make;
import * as Headers from "@effect/platform/Http/Headers";
import * as Schema from "@effect/schema/Schema";
import * as Serializable from "@effect/schema/Serializable";
import * as Arr from "effect/Array";
import * as Cause from "effect/Cause";
import * as Effect from "effect/Effect";
import * as Exit from "effect/Exit";
import { dual, pipe } from "effect/Function";
import * as Request from "effect/Request";
import * as RequestResolver from "effect/RequestResolver";
import * as Stream from "effect/Stream";
import { StreamRequestTypeId, withRequestTag } from "./internal/rpc.js";
import * as Rpc from "./Rpc.js";
/**
* @since 1.0.0
* @category constructors
*/
export const make = handler => () => {
const getDecode = withRequestTag(req => Schema.decodeUnknown(Serializable.exitSchema(req)));
const getDecodeChunk = withRequestTag(req => Schema.decodeUnknown(Schema.Chunk(Serializable.exitSchema(req))));
return RequestResolver.makeBatched(requests => {
const [effectRequests, streamRequests] = Arr.partition(requests, _ => StreamRequestTypeId in _.request);
const processEffects = pipe(Effect.forEach(effectRequests, _ => Effect.map(Serializable.serialize(_.request), request => ({
..._,
request
}))), Effect.flatMap(payload => Stream.runForEach(Stream.filter(handler(payload), _ => Arr.isArray(_) && _.length === 2), ([index, response]) => {
const request = effectRequests[index];
return Effect.matchCauseEffect(Effect.orDie(getDecode(request.request)(response)), {
onFailure: cause => Request.failCause(request, cause),
onSuccess: exit => Request.complete(request, exit)
});
})), Effect.orDie, Effect.catchAllCause(cause => Effect.forEach(effectRequests, request => Request.failCause(request, cause), {
discard: true
})));
const processStreams = pipe(Effect.forEach(streamRequests, request => {
const decode = getDecodeChunk(request.request);
const stream = pipe(Serializable.serialize(request.request), Effect.map(_ => ({
...request,
request: _
})), Effect.map(payload => pipe(handler([payload]), Stream.mapEffect(_ => Effect.orDie(decode(_[1]))), Stream.flattenChunks, Stream.flatMap(Exit.match({
onFailure: cause => Cause.isEmptyType(cause) ? Stream.empty : Stream.failCause(cause),
onSuccess: Stream.succeed
})))), Effect.orDie, Stream.unwrap);
return Request.succeed(request, stream);
}, {
discard: true
}), Effect.catchAllCause(cause => Effect.forEach(streamRequests, request => Request.failCause(request, cause), {
discard: true
})));
return Effect.zipRight(processStreams, processEffects);
});
};
/**
* @since 1.0.0
* @category combinators
*/
export const makeWithSchema = internal.makeWithSchema;
export const annotateHeaders = /*#__PURE__*/dual(2, (self, headers) => {
const resolved = Headers.fromInput(headers);
return RequestResolver.makeWithEntry(requests => {
requests.forEach(entries => entries.forEach(entry => {
;
entry.request.headers = Headers.merge(entry.request.headers, resolved);
}));
return self.runAll(requests);
});
});
/**
* @category constructors
* @since 1.0.0
* @category combinators
*/
export const makeSingle = internal.makeSingle;
export const annotateHeadersEffect = /*#__PURE__*/dual(2, (self, headers) => RequestResolver.makeWithEntry(requests => headers.pipe(Effect.map(Headers.fromInput), Effect.orDie, Effect.matchCauseEffect({
onFailure: cause => Effect.forEach(requests.flat(), entry => Request.failCause(entry.request, cause), {
discard: true
}),
onSuccess: resolved => {
requests.forEach(entries => entries.forEach(entry => {
;
entry.request.headers = Headers.merge(entry.request.headers, resolved);
}));
return self.runAll(requests);
}
}))));
/**
* @category constructors
* @since 1.0.0
* @category combinators
*/
export const makeSingleWithSchema = internal.makeSingleWithSchema;
export const toClient = (resolver, options) => request => Rpc.call(request, resolver, options);
//# sourceMappingURL=Resolver.js.map

@@ -1,22 +0,208 @@

import * as internal from "./internal/router.js";
import * as Schema from "@effect/schema/Schema";
import * as Serializable from "@effect/schema/Serializable";
import * as Cause from "effect/Cause";
import * as Channel from "effect/Channel";
import * as Chunk from "effect/Chunk";
import * as Context from "effect/Context";
import * as Effect from "effect/Effect";
import * as Exit from "effect/Exit";
import { dual, pipe } from "effect/Function";
import { pipeArguments } from "effect/Pipeable";
import * as Predicate from "effect/Predicate";
import * as Queue from "effect/Queue";
import * as Stream from "effect/Stream";
import { StreamRequestTypeId, withRequestTag } from "./internal/rpc.js";
import * as Rpc from "./Rpc.js";
/**
* @category router constructors
* @since 1.0.0
* @category type ids
*/
export const make = internal.make;
export const TypeId = /*#__PURE__*/Symbol.for("@effect/rpc/Router");
/**
* @category router combinators
* @since 1.0.0
* @category refinements
*/
export const provideService = internal.provideService;
export const isRouter = u => Predicate.hasProperty(u, TypeId);
const fromSet = rpcs => ({
[TypeId]: TypeId,
rpcs,
pipe() {
return pipeArguments(this, arguments);
}
});
/**
* @category router combinators
* @since 1.0.0
* @category constructors
*/
export const provideServiceEffect = internal.provideServiceEffect;
export const make = (...rpcs) => {
const rpcSet = new Set();
rpcs.forEach(rpc => {
if (isRouter(rpc)) {
rpc.rpcs.forEach(rpc => rpcSet.add(rpc));
} else {
rpcSet.add(rpc);
}
});
return fromSet(rpcSet);
};
/**
* @category router combinators
* @since 1.0.0
* @category context
*/
export const provideServiceSync = internal.provideServiceSync;
export const provideServiceEffect = /*#__PURE__*/dual(3, (self, tag, effect) => fromSet(new Set([...self.rpcs].map(Rpc.provideServiceEffect(tag, effect)))));
/**
* @since 1.0.0
* @category context
*/
export const provideService = /*#__PURE__*/dual(3, (self, tag, service) => fromSet(new Set([...self.rpcs].map(Rpc.provideService(tag, service)))));
const EOF = /*#__PURE__*/Symbol.for("@effect/rpc/Router/EOF");
const channelFromQueue = queue => {
const loop = Channel.flatMap(Queue.takeBetween(queue, 1, Number.MAX_SAFE_INTEGER), chunk => {
if (Chunk.unsafeLast(chunk) === EOF) {
return Channel.write(Chunk.dropRight(chunk, 1));
}
return Channel.zipRight(Channel.write(chunk), loop);
});
return loop;
};
const emptyExit = /*#__PURE__*/Schema.encodeSync(Schema.Exit({
failure: Schema.Never,
success: Schema.Never
}))( /*#__PURE__*/Exit.failCause(Cause.empty));
/**
* @since 1.0.0
* @category combinators
*/
export const toHandler = (router, options) => {
const spanPrefix = options?.spanPrefix ?? "Rpc.router ";
const schema = Schema.Union(...[...router.rpcs].map(rpc => Schema.transform(rpc.schema, Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)), {
decode: request => [request, rpc],
encode: ([request]) => request
})));
const schemaArray = Schema.Array(Rpc.RequestSchema(schema));
const decode = Schema.decodeUnknown(schemaArray);
const getEncode = withRequestTag(req => Schema.encode(Serializable.exitSchema(req)));
const getEncodeChunk = withRequestTag(req => Schema.encode(Schema.Chunk(Serializable.exitSchema(req))));
return u => pipe(decode(u), Effect.zip(Queue.unbounded()), Effect.tap(([requests, queue]) => pipe(Effect.forEach(requests, (req, index) => {
const [request, rpc] = req.request;
if (rpc._tag === "Effect") {
const encode = getEncode(request);
return pipe(Effect.exit(rpc.handler(request)), Effect.flatMap(encode), Effect.orDie, Effect.matchCauseEffect({
onSuccess: response => Queue.offer(queue, [index, response]),
onFailure: cause => Effect.flatMap(encode(Exit.failCause(cause)), response => Queue.offer(queue, [index, response]))
}), Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}
const encode = getEncodeChunk(request);
return pipe(rpc.handler(request), Stream.toChannel, Channel.mapOutEffect(chunk => Effect.flatMap(encode(Chunk.map(chunk, Exit.succeed)), response => Queue.offer(queue, [index, response]))), Channel.runDrain, Effect.matchCauseEffect({
onSuccess: () => Queue.offer(queue, [index, [emptyExit]]),
onFailure: cause => Effect.flatMap(encode(Chunk.of(Exit.failCause(cause))), response => Queue.offer(queue, [index, response]))
}), Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}, {
concurrency: "unbounded",
discard: true
}), Effect.ensuring(Queue.offer(queue, EOF)), Effect.fork)), Effect.map(([_, queue]) => Stream.fromChannel(channelFromQueue(queue))), Stream.unwrap);
};
/**
* @since 1.0.0
* @category combinators
*/
export const toHandlerEffect = (router, options) => {
const spanPrefix = options?.spanPrefix ?? "Rpc.router ";
const schema = Schema.Union(...[...router.rpcs].map(rpc => Schema.transform(rpc.schema, Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)), {
decode: request => [request, rpc],
encode: ([request]) => request
})));
const schemaArray = Schema.Array(Rpc.RequestSchema(schema));
const decode = Schema.decodeUnknown(schemaArray);
const getEncode = withRequestTag(req => Schema.encode(Serializable.exitSchema(req)));
const getEncodeChunk = withRequestTag(req => Schema.encode(Schema.Chunk(Serializable.exitSchema(req))));
return u => Effect.flatMap(decode(u), Effect.forEach(req => {
const [request, rpc] = req.request;
if (rpc._tag === "Effect") {
const encode = getEncode(request);
return pipe(Effect.exit(rpc.handler(request)), Effect.flatMap(encode), Effect.orDie, Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}
const encode = getEncodeChunk(request);
return pipe(rpc.handler(request), Stream.map(Exit.succeed), Stream.catchAllCause(cause => Stream.succeed(Exit.failCause(cause))), Stream.runCollect, Effect.flatMap(encode), Effect.locally(Rpc.currentHeaders, req.headers), Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
}));
}, {
concurrency: "unbounded"
}));
};
/**
* @since 1.0.0
* @category combinators
*/
export const toHandlerRaw = router => {
const schema = Schema.Union(...[...router.rpcs].map(rpc => Schema.transform(Schema.typeSchema(rpc.schema), Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)), {
decode: request => [request, rpc],
encode: ([request]) => request
})));
const parse = Schema.decode(schema);
return request => {
const isStream = (StreamRequestTypeId in request);
const withHandler = parse(request);
if (isStream) {
return Stream.unwrap(Effect.map(withHandler, ([request, rpc]) => rpc.handler(request)));
}
return Effect.flatMap(withHandler, ([request, rpc]) => rpc.handler(request));
};
};
/**
* @since 1.0.0
* @category combinators
*/
export const toHandlerUndecoded = router => {
const handler = toHandlerRaw(router);
const getEncode = withRequestTag(req => Schema.encode(Serializable.successSchema(req)));
const getEncodeChunk = withRequestTag(req => Schema.encode(Schema.ChunkFromSelf(Serializable.successSchema(req))));
return request => {
const result = handler(request);
if (Effect.isEffect(result)) {
const encode = getEncode(request);
return Effect.flatMap(result, encode);
}
const encode = getEncodeChunk(request);
return Stream.mapChunksEffect(result, encode);
};
};
//# sourceMappingURL=Router.js.map
{
"name": "@effect/rpc",
"version": "0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49",
"version": "0.0.0-snapshot-e0f0eba005ab024d629f3728d81590db23057c74",
"description": "Functional programming in TypeScript",

@@ -8,9 +8,14 @@ "license": "MIT",

"type": "git",
"url": "https://github.com/effect-ts/effect.git"
"url": "https://github.com/Effect-TS/effect.git",
"directory": "packages/rpc"
},
"sideEffects": [],
"peerDependencies": {
"effect": "^0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49",
"@effect/schema": "^0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49"
"@effect/platform": "^0.0.0-snapshot-e0f0eba005ab024d629f3728d81590db23057c74",
"@effect/schema": "^0.0.0-snapshot-e0f0eba005ab024d629f3728d81590db23057c74",
"effect": "^0.0.0-snapshot-e0f0eba005ab024d629f3728d81590db23057c74"
},
"publishConfig": {
"provenance": true
},
"main": "./dist/cjs/index.js",

@@ -26,12 +31,2 @@ "module": "./dist/esm/index.js",

},
"./Client": {
"types": "./dist/dts/Client.d.ts",
"import": "./dist/esm/Client.js",
"default": "./dist/cjs/Client.js"
},
"./Error": {
"types": "./dist/dts/Error.d.ts",
"import": "./dist/esm/Error.js",
"default": "./dist/cjs/Error.js"
},
"./Resolver": {

@@ -42,2 +37,7 @@ "types": "./dist/dts/Resolver.d.ts",

},
"./ResolverNoStream": {
"types": "./dist/dts/ResolverNoStream.d.ts",
"import": "./dist/esm/ResolverNoStream.js",
"default": "./dist/cjs/ResolverNoStream.js"
},
"./Router": {

@@ -48,16 +48,6 @@ "types": "./dist/dts/Router.d.ts",

},
"./Schema": {
"types": "./dist/dts/Schema.d.ts",
"import": "./dist/esm/Schema.js",
"default": "./dist/cjs/Schema.js"
},
"./SchemaC": {
"types": "./dist/dts/SchemaC.d.ts",
"import": "./dist/esm/SchemaC.js",
"default": "./dist/cjs/SchemaC.js"
},
"./Server": {
"types": "./dist/dts/Server.d.ts",
"import": "./dist/esm/Server.js",
"default": "./dist/cjs/Server.js"
"./Rpc": {
"types": "./dist/dts/Rpc.d.ts",
"import": "./dist/esm/Rpc.js",
"default": "./dist/cjs/Rpc.js"
}

@@ -67,22 +57,13 @@ },

"*": {
"Client": [
"./dist/dts/Client.d.ts"
],
"Error": [
"./dist/dts/Error.d.ts"
],
"Resolver": [
"./dist/dts/Resolver.d.ts"
],
"ResolverNoStream": [
"./dist/dts/ResolverNoStream.d.ts"
],
"Router": [
"./dist/dts/Router.d.ts"
],
"Schema": [
"./dist/dts/Schema.d.ts"
],
"SchemaC": [
"./dist/dts/SchemaC.d.ts"
],
"Server": [
"./dist/dts/Server.d.ts"
"Rpc": [
"./dist/dts/Rpc.d.ts"
]

@@ -89,0 +70,0 @@ }

/**
* @since 1.0.0
*/
export * as Client from "./Client.js"
export * as Resolver from "./Resolver.js"

@@ -9,3 +9,3 @@ /**

*/
export * as Error from "./Error.js"
export * as ResolverNoStream from "./ResolverNoStream.js"

@@ -15,7 +15,2 @@ /**

*/
export * as Resolver from "./Resolver.js"
/**
* @since 1.0.0
*/
export * as Router from "./Router.js"

@@ -26,12 +21,2 @@

*/
export * as Schema from "./Schema.js"
/**
* @since 1.0.0
*/
export * as SchemaC from "./SchemaC.js"
/**
* @since 1.0.0
*/
export * as Server from "./Server.js"
export * as Rpc from "./Rpc.js"
/**
* @since 1.0.0
*/
import type * as Effect from "effect/Effect"
import type * as Request from "effect/Request"
import type * as Resolver from "effect/RequestResolver"
import type { RpcError, RpcTransportError } from "./Error.js"
import * as internal from "./internal/resolver.js"
import type { RpcSchema } from "./Schema.js"
import * as Headers from "@effect/platform/Http/Headers"
import type { ParseError } from "@effect/schema/ParseResult"
import * as Schema from "@effect/schema/Schema"
import * as Serializable from "@effect/schema/Serializable"
import * as Arr from "effect/Array"
import * as Cause from "effect/Cause"
import * as Effect from "effect/Effect"
import * as Exit from "effect/Exit"
import { dual, pipe } from "effect/Function"
import * as Request from "effect/Request"
import * as RequestResolver from "effect/RequestResolver"
import * as Stream from "effect/Stream"
import { StreamRequestTypeId, withRequestTag } from "./internal/rpc.js"
import type * as Router from "./Router.js"
import * as Rpc from "./Rpc.js"
/**
* @category models
* @since 1.0.0
* @category constructors
*/
export interface RpcResolver<R> extends Resolver.RequestResolver<RpcRequest, R> {}
export const make = <HR, E>(
handler: (u: ReadonlyArray<unknown>) => Stream.Stream<unknown, E, HR>
) =>
<R extends Router.Router<any, any>>(): RequestResolver.RequestResolver<
Rpc.Request<Router.Router.Request<R>>,
Serializable.SerializableWithResult.Context<Router.Router.Request<R>> | HR
> => {
const getDecode = withRequestTag((req) => Schema.decodeUnknown(Serializable.exitSchema(req)))
const getDecodeChunk = withRequestTag((req) => Schema.decodeUnknown(Schema.Chunk(Serializable.exitSchema(req))))
/**
* @category models
* @since 1.0.0
*/
export interface RpcRequest extends Request.Request<RpcError, unknown> {
readonly payload: RpcRequest.Payload
readonly hash: number
readonly schema: RpcSchema.Any
}
return RequestResolver.makeBatched((requests: Arr.NonEmptyArray<Rpc.Request<Schema.TaggedRequest.Any>>) => {
const [effectRequests, streamRequests] = Arr.partition(
requests,
(_): _ is Rpc.Request<Rpc.StreamRequest.Any> => StreamRequestTypeId in _.request
)
/**
* @since 1.0.0
*/
export namespace RpcRequest {
/**
* @category models
* @since 1.0.0
*/
export interface Tracing {
readonly spanName: string
readonly traceId: string
readonly spanId: string
readonly sampled: boolean
}
const processEffects = pipe(
Effect.forEach(effectRequests, (_) =>
Effect.map(
Serializable.serialize(_.request),
(request) => ({ ..._, request })
)),
Effect.flatMap((payload) =>
Stream.runForEach(
Stream.filter(
handler(payload),
(_): _ is Router.Router.Response => Arr.isArray(_) && _.length === 2
),
([index, response]): Effect.Effect<void, ParseError, any> => {
const request = effectRequests[index]
return Effect.matchCauseEffect(Effect.orDie(getDecode(request.request)(response)), {
onFailure: (cause) => Request.failCause(request, cause as any),
onSuccess: (exit) => Request.complete(request, exit as any)
})
}
)
),
Effect.orDie,
Effect.catchAllCause((cause) =>
Effect.forEach(
effectRequests,
(request) => Request.failCause(request, cause),
{ discard: true }
)
)
)
/**
* @category models
* @since 1.0.0
*/
export interface Payload extends Tracing {
readonly _tag: string
readonly input?: unknown
}
const processStreams = pipe(
Effect.forEach(streamRequests, (request) => {
const decode = getDecodeChunk(request.request)
const stream = pipe(
Serializable.serialize(request.request),
Effect.map((_) => ({ ...request, request: _ })),
Effect.map((payload) =>
pipe(
handler([payload]),
Stream.mapEffect((_) => Effect.orDie(decode((_ as Router.Router.Response)[1]))),
Stream.flattenChunks,
Stream.flatMap(Exit.match({
onFailure: (cause) => Cause.isEmptyType(cause) ? Stream.empty : Stream.failCause(cause),
onSuccess: Stream.succeed
}))
)
),
Effect.orDie,
Stream.unwrap
)
return Request.succeed(request, stream as any)
}, { discard: true }),
Effect.catchAllCause((cause) =>
Effect.forEach(
streamRequests,
(request) => Request.failCause(request, cause),
{ discard: true }
)
)
)
/**
* @category models
* @since 1.0.0
*/
export interface WithInput<M extends string, I> extends Tracing {
readonly _tag: M
readonly input: I
}
/**
* @category models
* @since 1.0.0
*/
export interface NoInput<M extends string> extends Tracing {
readonly _tag: M
}
return Effect.zipRight(processStreams, processEffects)
})
}
/**
* @category models
* @since 1.0.0
* @category combinators
*/
export type RpcResponse = RpcResponse.Error | RpcResponse.Success
export const annotateHeaders: {
(
headers: Headers.Input
): <Req extends Schema.TaggedRequest.Any, R>(
self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>
) => RequestResolver.RequestResolver<Rpc.Request<Req>, R>
<Req extends Schema.TaggedRequest.Any, R>(
self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>,
headers: Headers.Input
): RequestResolver.RequestResolver<Rpc.Request<Req>, R>
} = dual(2, <Req extends Schema.TaggedRequest.Any, R>(
self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>,
headers: Headers.Input
): RequestResolver.RequestResolver<Rpc.Request<Req>, R> => {
const resolved = Headers.fromInput(headers)
return RequestResolver.makeWithEntry((requests) => {
requests.forEach((entries) =>
entries.forEach((entry) => {
;(entry.request as any).headers = Headers.merge(entry.request.headers, resolved)
})
)
return self.runAll(requests)
})
})
/**
* @since 1.0.0
* @category combinators
*/
export namespace RpcResponse {
/**
* @category models
* @since 1.0.0
*/
export interface Error {
readonly _tag: "Error"
error: RpcError
}
export const annotateHeadersEffect: {
<E, R2>(
headers: Effect.Effect<Headers.Input, E, R2>
): <Req extends Schema.TaggedRequest.Any, R>(
self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>
) => RequestResolver.RequestResolver<Rpc.Request<Req>, R | R2>
<Req extends Schema.TaggedRequest.Any, R, E, R2>(
self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>,
headers: Effect.Effect<Headers.Input, E, R2>
): RequestResolver.RequestResolver<Rpc.Request<Req>, R | R2>
} = dual(2, <Req extends Schema.TaggedRequest.Any, R, E, R2>(
self: RequestResolver.RequestResolver<Rpc.Request<Req>, R>,
headers: Effect.Effect<Headers.Input, E, R2>
): RequestResolver.RequestResolver<Rpc.Request<Req>, R | R2> =>
RequestResolver.makeWithEntry((requests) =>
headers.pipe(
Effect.map(Headers.fromInput),
Effect.orDie,
Effect.matchCauseEffect({
onFailure: (cause) =>
Effect.forEach(
requests.flat(),
(entry) => Request.failCause(entry.request, cause),
{ discard: true }
),
onSuccess: (resolved) => {
requests.forEach((entries) =>
entries.forEach((entry) => {
;(entry.request as any).headers = Headers.merge(entry.request.headers, resolved)
})
)
return self.runAll(requests)
}
})
)
))
/**
* @category models
* @since 1.0.0
*/
export interface Success {
readonly _tag: "Success"
value: unknown
}
}
/**
* @category constructors
* @since 1.0.0
* @category models
*/
export const make: <R>(
send: (
requests: ReadonlyArray<RpcRequest.Payload>
) => Effect.Effect<unknown, RpcTransportError, R>
) => RpcResolver<R> = internal.make
export type Client<
R extends
| RequestResolver.RequestResolver<Rpc.Request<any>, never>
| Effect.Effect<RequestResolver.RequestResolver<Rpc.Request<any>, never>, never, any>
> = R extends Effect.Effect<RequestResolver.RequestResolver<Rpc.Request<infer RReq>>, infer _E, infer R> ?
(<Req extends RReq>(request: Req) => Rpc.Rpc.Result<Req, R>)
: R extends RequestResolver.RequestResolver<Rpc.Request<infer RReq>, never> ?
(<Req extends RReq>(request: Req) => Rpc.Rpc.Result<Req>)
: never
/**
* @category constructors
* @since 1.0.0
* @category combinators
*/
export const makeWithSchema: <R>(
send: (
requests: ReadonlyArray<RpcRequest>
) => Effect.Effect<unknown, RpcTransportError, R>
) => RpcResolver<R> = internal.makeWithSchema
/**
* @category constructors
* @since 1.0.0
*/
export const makeSingle: <R>(
send: (
request: RpcRequest.Payload
) => Effect.Effect<unknown, RpcTransportError, R>
) => RpcResolver<R> = internal.makeSingle
/**
* @category constructors
* @since 1.0.0
*/
export const makeSingleWithSchema: <R>(
send: (request: RpcRequest) => Effect.Effect<unknown, RpcTransportError, R>
) => RpcResolver<R> = internal.makeSingleWithSchema
export const toClient = <
R extends
| RequestResolver.RequestResolver<Rpc.Request<any>, never>
| Effect.Effect<RequestResolver.RequestResolver<Rpc.Request<any>, never>, never, any>
>(
resolver: R,
options?: {
readonly spanPrefix?: string
}
): Client<R> => ((request: Schema.TaggedRequest.Any) => Rpc.call(request, resolver, options)) as any
/**
* @since 1.0.0
*/
import type { Context, Tag } from "effect/Context"
import type { Effect } from "effect/Effect"
import type { LazyArg } from "effect/Function"
import type { Layer } from "effect/Layer"
import * as internal from "./internal/router.js"
import type { RpcSchema, RpcService } from "./Schema.js"
import type { RpcUndecodedClient } from "./Server.js"
import type { ParseError } from "@effect/schema/ParseResult"
import * as Schema from "@effect/schema/Schema"
import * as Serializable from "@effect/schema/Serializable"
import * as Cause from "effect/Cause"
import * as Channel from "effect/Channel"
import * as Chunk from "effect/Chunk"
import * as Context from "effect/Context"
import * as Effect from "effect/Effect"
import * as Exit from "effect/Exit"
import { dual, pipe } from "effect/Function"
import { type Pipeable, pipeArguments } from "effect/Pipeable"
import * as Predicate from "effect/Predicate"
import * as Queue from "effect/Queue"
import * as Stream from "effect/Stream"
import { StreamRequestTypeId, withRequestTag } from "./internal/rpc.js"
import * as Rpc from "./Rpc.js"
/**
* @category handler models
* @since 1.0.0
* @category type ids
*/
export type RpcHandler<R, E, I, O> =
| RpcHandler.IO<R, E, I, O>
| RpcHandler.IOLayer<R, E, I, O>
| RpcHandler.NoInput<R, E, O>
export const TypeId: unique symbol = Symbol.for("@effect/rpc/Router")
/**
* @since 1.0.0
* @category type ids
*/
export declare namespace RpcHandler {
/**
* @category handler models
* @since 1.0.0
*/
export type IO<R, E, I, O> = (input: I) => Effect<O, E, R>
export type TypeId = typeof TypeId
/**
* @category handler models
* @since 1.0.0
*/
export type IOLayer<R, E, I, O> = (input: I) => Layer<O, E, R>
/**
* @since 1.0.0
* @category refinements
*/
export const isRouter = (u: unknown): u is Router<any, any> => Predicate.hasProperty(u, TypeId)
/**
* @since 1.0.0
* @category models
*/
export interface Router<Reqs extends Schema.TaggedRequest.Any, R> extends Pipeable {
readonly [TypeId]: TypeId
readonly rpcs: ReadonlySet<Rpc.Rpc<Reqs, R>>
}
/**
* @since 1.0.0
* @category models
*/
export declare namespace Router {
/**
* @category handler models
* @since 1.0.0
* @category models
*/
export type NoInput<R, E, O> = Effect<O, E, R>
export type Context<A extends Router<any, any>> = A extends Router<infer Req, infer R>
? R | Serializable.SerializableWithResult.Context<Req>
: never
/**
* @category handler models
* @since 1.0.0
* @category models
*/
export type Any = RpcHandler<any, any, any, any>
export type ContextRaw<A extends Router<any, any>> = A extends Router<infer Req, infer R>
? R | Serializable.Serializable.Context<Req>
: never
/**
* @category handler utils
* @since 1.0.0
* @category models
*/
export type FromSchema<C extends RpcSchema.Any> = C extends RpcSchema.IO<
infer _RE,
infer _IE,
infer E,
infer _RI,
infer _II,
infer I,
infer _RO,
infer _IO,
infer O
> ? IO<any, E, I, O>
: C extends RpcSchema.NoError<infer _RI, infer _II, infer I, infer _RO, infer _IO, infer O> ? IO<any, never, I, O>
: C extends RpcSchema.NoInput<infer _RE, infer _IE, infer E, infer _RO, infer _IO, infer O> ? NoInput<any, E, O>
: C extends RpcSchema.NoInputNoError<infer _RO, infer _IO, infer O> ? NoInput<any, never, O>
: C extends RpcSchema.NoOutput<infer _RE, infer _IE, infer E, infer _RI, infer _II, infer I> ? IO<any, E, I, void>
: C extends RpcSchema.NoErrorNoOutput<infer _RI, infer _II, infer I> ? IO<any, never, I, void>
export type Request<A extends Router<any, any>> = A extends Router<infer Req, infer _R> ? Req
: never
/**
* @category handler utils
* @since 1.0.0
* @category models
*/
export type FromSetupSchema<C> = C extends RpcSchema.NoOutput<
infer _RE,
infer _IE,
infer E,
infer _RI,
infer _II,
infer I
> ? IO<any, E, I, Context<any>> | IOLayer<any, E, I, any>
: C extends RpcSchema.NoErrorNoOutput<infer _RI, infer _II, infer I>
? IO<any, never, I, Context<any>> | IOLayer<any, never, I, any>
: never
export type Response = [
index: number,
response: Schema.ExitEncoded<any, any> | ReadonlyArray<Schema.ExitEncoded<any, any>>
]
/**
* @category handler utils
* @since 1.0.0
* @category models
*/
export type FromMethod<H extends RpcHandlers, M, XR, E2> = Extract<
RpcHandlers.Map<H, XR, E2>,
[M, any]
> extends [infer _M, infer T] ? T
: never
export type ResponseEffect = Schema.ExitEncoded<any, any> | ReadonlyArray<Schema.ExitEncoded<any, any>>
}
/**
* @category handlers models
* @since 1.0.0
*/
export interface RpcHandlers extends Record<string, RpcHandler.Any | { readonly handlers: RpcHandlers }> {}
const fromSet = <Reqs extends Schema.TaggedRequest.Any, R>(
rpcs: ReadonlySet<Rpc.Rpc<Reqs, R>>
): Router<Reqs, R> => ({
[TypeId]: TypeId,
rpcs,
pipe() {
return pipeArguments(this, arguments)
}
})
/**
* @since 1.0.0
* @category constructors
*/
export declare namespace RpcHandlers {
/**
* @category handlers utils
* @since 1.0.0
*/
export type FromService<S extends RpcService.DefinitionWithId, Depth extends ReadonlyArray<number> = []> = {
readonly [
K in Extract<
keyof S,
string
>
]: S[K] extends RpcService.DefinitionWithId ?
Depth["length"] extends 3 ? never : { readonly handlers: FromService<S[K], [0, ...Depth]> }
: K extends "__setup" ? RpcHandler.FromSetupSchema<S[K]>
: S[K] extends RpcSchema.Any ? RpcHandler.FromSchema<S[K]>
: never
}
/**
* @category handlers utils
* @since 1.0.0
*/
export type Services<H extends RpcHandlers, Depth extends ReadonlyArray<number> = []> = keyof H extends infer M
? M extends keyof H ?
H[M] extends { readonly handlers: RpcHandlers } ?
Depth["length"] extends 3 ? never : Services<H[M]["handlers"], [0, ...Depth]>
: H[M] extends RpcHandler<infer R, infer _E, infer _I, infer _O> ? R
: never
: never
: never
/**
* @category handlers utils
* @since 1.0.0
*/
export type Errors<H extends RpcHandlers, Depth extends ReadonlyArray<number> = []> = keyof H extends infer M
? M extends keyof H ?
H[M] extends { readonly handlers: RpcHandlers } ?
Depth["length"] extends 3 ? never : Errors<H[M]["handlers"], [0, ...Depth]>
: H[M] extends RpcHandler<infer _R, infer E, infer _I, infer _O> ? E
: never
: never
: never
/**
* @category handlers utils
* @since 1.0.0
*/
export type Map<
H extends RpcHandlers,
XR,
E2,
P extends string = "",
Depth extends ReadonlyArray<number> = []
> = Extract<keyof H, string> extends infer K
? K extends Extract<keyof H, string>
? H[K] extends { readonly handlers: RpcHandlers } ?
Depth["length"] extends 3 ? never : Map<H[K]["handlers"], XR, E2, `${P}${K}.`, [0, ...Depth]>
: H[K] extends RpcHandler.IO<infer R, infer E, infer _I, infer O>
? [`${P}${K}`, Effect<O, E | E2, Exclude<R, XR>>]
: H[K] extends Effect<infer O, infer E, infer R> ? [`${P}${K}`, Effect<O, E | E2, Exclude<R, XR>>]
: never
: never
: never
export const make = <Rpcs extends ReadonlyArray<Rpc.Rpc<any, any> | Router<any, any>>>(
...rpcs: Rpcs
): Router<
| Rpc.Rpc.Request<
Extract<Rpcs[number], { readonly [Rpc.TypeId]: Rpc.TypeId }>
>
| Router.Request<
Extract<Rpcs[number], { readonly [TypeId]: TypeId }>
>,
| Rpc.Rpc.Context<
Extract<Rpcs[number], { readonly [Rpc.TypeId]: Rpc.TypeId }>
>
| Router.Context<
Extract<Rpcs[number], { readonly [TypeId]: TypeId }>
>
> => {
const rpcSet = new Set<Rpc.Rpc<any, any>>()
rpcs.forEach((rpc) => {
if (isRouter(rpc)) {
rpc.rpcs.forEach((rpc) => rpcSet.add(rpc))
} else {
rpcSet.add(rpc)
}
})
return fromSet(rpcSet)
}
/**
* @category router models
* @since 1.0.0
* @category context
*/
export interface RpcRouter<
S extends RpcService.DefinitionWithId,
H extends RpcHandlers
> extends RpcRouter.Base {
readonly handlers: H
readonly schema: S
readonly undecoded: RpcUndecodedClient<H>
}
export const provideServiceEffect: {
<I, S, E, R2>(
tag: Context.Tag<I, S>,
effect: Effect.Effect<S, E, R2>
): <Reqs extends Schema.TaggedRequest.Any, R>(self: Router<Reqs, R>) => Router<Reqs, Exclude<R, I> | R2>
<Reqs extends Schema.TaggedRequest.Any, R, I, S, E, R2>(
self: Router<Reqs, R>,
tag: Context.Tag<I, S>,
effect: Effect.Effect<S, E, R2>
): Router<Reqs, Exclude<R, I> | R2>
} = dual(3, <Reqs extends Schema.TaggedRequest.Any, R, I, S, E, R2>(
self: Router<Reqs, R>,
tag: Context.Tag<I, S>,
effect: Effect.Effect<S, E, R2>
): Router<Reqs, Exclude<R, I> | R2> => fromSet(new Set([...self.rpcs].map(Rpc.provideServiceEffect(tag, effect)))))
/**
* @since 1.0.0
* @category context
*/
export declare namespace RpcRouter {
/**
* @category router models
* @since 1.0.0
*/
export interface Base {
readonly handlers: RpcHandlers
readonly schema: RpcService.DefinitionWithId
readonly undecoded: any
readonly options: Options
}
export const provideService: {
<I, S>(
tag: Context.Tag<I, S>,
service: S
): <Reqs extends Schema.TaggedRequest.Any, R>(self: Router<Reqs, R>) => Router<Reqs, Exclude<R, I>>
<Reqs extends Schema.TaggedRequest.Any, R, I, S>(
self: Router<Reqs, R>,
tag: Context.Tag<I, S>,
service: S
): Router<Reqs, Exclude<R, I>>
} = dual(3, <Reqs extends Schema.TaggedRequest.Any, R, I, S>(
self: Router<Reqs, R>,
tag: Context.Tag<I, S>,
service: S
): Router<Reqs, Exclude<R, I>> => fromSet(new Set([...self.rpcs].map(Rpc.provideService(tag, service)))))
/**
* @category router models
* @since 1.0.0
*/
export interface WithSetup extends Base {
readonly handlers: RpcHandlers & {
readonly __setup: RpcHandler.Any
}
}
const EOF = Symbol.for("@effect/rpc/Router/EOF")
/**
* @category router models
* @since 1.0.0
*/
export interface WithoutSetup extends Base {
readonly handlers: RpcHandlers & {
readonly __setup?: never
const channelFromQueue = <A>(queue: Queue.Queue<A | typeof EOF>) => {
const loop: Channel.Channel<Chunk.Chunk<A>> = Channel.flatMap(
Queue.takeBetween(queue, 1, Number.MAX_SAFE_INTEGER),
(chunk) => {
if (Chunk.unsafeLast(chunk) === EOF) {
return Channel.write(Chunk.dropRight(chunk as Chunk.Chunk<A>, 1))
}
return Channel.zipRight(Channel.write(chunk as Chunk.Chunk<A>), loop)
}
}
)
return loop
}
/**
* @category router models
* @since 1.0.0
*/
export interface Options {
readonly spanPrefix: string
}
const emptyExit = Schema.encodeSync(Schema.Exit({
failure: Schema.Never,
success: Schema.Never
}))(Exit.failCause(Cause.empty))
/**
* @category router utils
* @since 1.0.0
*/
export type Provide<Router extends Base, XR, PR, PE, Depth extends ReadonlyArray<number> = []> = RpcRouter<
Router["schema"],
{
readonly [M in keyof Router["handlers"]]: Router["handlers"][M] extends Base
? Depth["length"] extends 3 ? never : Provide<Router["handlers"][M], XR, PR, PE, [0, ...Depth]>
: Router["handlers"][M] extends RpcHandler.IO<
infer R,
infer E,
infer I,
infer O
> ? RpcHandler.IO<Exclude<R, XR> | PR, E | PE, I, O>
: Router["handlers"][M] extends RpcHandler.IOLayer<
infer R,
infer E,
infer I,
infer O
> ? RpcHandler.IOLayer<Exclude<R, XR> | PR, E | PE, I, O>
: Router["handlers"][M] extends RpcHandler.NoInput<
infer R,
infer E,
infer O
> ? RpcHandler.NoInput<Exclude<R, XR> | PR, E | PE, O>
: never
}
>
/**
* @category router utils
* @since 1.0.0
*/
export type SetupServices<R extends WithSetup> = R["handlers"]["__setup"] extends RpcHandler.IOLayer<
infer _R,
infer _E,
infer _I,
infer O
> ? O
: R["handlers"]["__setup"] extends RpcHandler.IO<
infer _R,
infer _E,
infer _I,
infer O
> ? O extends Context<infer Env> ? Env
: never
: never
/**
* @category router utils
* @since 1.0.0
*/
export type Services<R extends Base> = R extends WithSetup
? Exclude<RpcHandlers.Services<R["handlers"]> | RpcSchema.Context<R["schema"]>, SetupServices<R>>
: RpcHandlers.Services<R["handlers"]> | RpcSchema.Context<R["schema"]>
/**
* @category router utils
* @since 1.0.0
*/
export type Errors<R extends Base> = RpcHandlers.Errors<R["handlers"]>
}
/**
* @category router constructors
* @since 1.0.0
* @category combinators
*/
export const make: <
const S extends RpcService.DefinitionWithId,
const H extends RpcHandlers.FromService<S>
>(
schema: S,
handlers: H,
options?: Partial<RpcRouter.Options>
) => RpcRouter<S, H> = internal.make
export const toHandler = <R extends Router<any, any>>(router: R, options?: {
readonly spanPrefix?: string
}) => {
const spanPrefix = options?.spanPrefix ?? "Rpc.router "
const schema = Schema
.Union(
...[...router.rpcs].map((rpc) =>
Schema.transform(
rpc.schema,
Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)),
{ decode: (request) => [request, rpc] as const, encode: ([request]) => request }
)
)
)
const schemaArray = Schema.Array(Rpc.RequestSchema(schema))
const decode = Schema.decodeUnknown(schemaArray)
const getEncode = withRequestTag((req) => Schema.encode(Serializable.exitSchema(req)))
const getEncodeChunk = withRequestTag((req) => Schema.encode(Schema.Chunk(Serializable.exitSchema(req))))
return (u: unknown): Stream.Stream<Router.Response, ParseError, Router.Context<R>> =>
pipe(
decode(u),
Effect.zip(Queue.unbounded<Router.Response | typeof EOF>()),
Effect.tap(([requests, queue]) =>
pipe(
Effect.forEach(requests, (req, index) => {
const [request, rpc] = req.request
if (rpc._tag === "Effect") {
const encode = getEncode(request)
return pipe(
Effect.exit(rpc.handler(request)),
Effect.flatMap(encode),
Effect.orDie,
Effect.matchCauseEffect({
onSuccess: (response) => Queue.offer(queue, [index, response]),
onFailure: (cause) =>
Effect.flatMap(
encode(Exit.failCause(cause)),
(response) => Queue.offer(queue, [index, response])
)
}),
Effect.locally(Rpc.currentHeaders, req.headers as any),
Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
})
)
}
const encode = getEncodeChunk(request)
return pipe(
rpc.handler(request),
Stream.toChannel,
Channel.mapOutEffect((chunk) =>
Effect.flatMap(
encode(Chunk.map(chunk, Exit.succeed)),
(response) => Queue.offer(queue, [index, response])
)
),
Channel.runDrain,
Effect.matchCauseEffect({
onSuccess: () => Queue.offer(queue, [index, [emptyExit]]),
onFailure: (cause) =>
Effect.flatMap(
encode(Chunk.of(Exit.failCause(cause))),
(response) => Queue.offer(queue, [index, response])
)
}),
Effect.locally(Rpc.currentHeaders, req.headers as any),
Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
})
)
}, { concurrency: "unbounded", discard: true }),
Effect.ensuring(Queue.offer(queue, EOF)),
Effect.fork
)
),
Effect.map(([_, queue]) => Stream.fromChannel(channelFromQueue(queue))),
Stream.unwrap
)
}
/**
* @category router combinators
* @since 1.0.0
* @category combinators
*/
export const provideService: {
<T extends Tag<any, any>>(
tag: T,
service: Tag.Service<T>
): <const Router extends RpcRouter.Base>(
self: Router
) => RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>
<const Router extends RpcRouter.Base, T extends Tag<any, any>>(
self: Router,
tag: T,
service: Tag.Service<T>
): RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>
} = internal.provideService
export const toHandlerEffect = <R extends Router<any, any>>(router: R, options?: {
readonly spanPrefix?: string
}) => {
const spanPrefix = options?.spanPrefix ?? "Rpc.router "
const schema = Schema
.Union(
...[...router.rpcs].map((rpc) =>
Schema.transform(
rpc.schema,
Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)),
{ decode: (request) => [request, rpc] as const, encode: ([request]) => request }
)
)
)
const schemaArray = Schema.Array(Rpc.RequestSchema(schema))
const decode = Schema.decodeUnknown(schemaArray)
const getEncode = withRequestTag((req) => Schema.encode(Serializable.exitSchema(req)))
const getEncodeChunk = withRequestTag((req) => Schema.encode(Schema.Chunk(Serializable.exitSchema(req))))
return (u: unknown): Effect.Effect<ReadonlyArray<Router.ResponseEffect>, ParseError, Router.Context<R>> =>
Effect.flatMap(
decode(u),
Effect.forEach((req): Effect.Effect<Router.ResponseEffect, ParseError, any> => {
const [request, rpc] = req.request
if (rpc._tag === "Effect") {
const encode = getEncode(request)
return pipe(
Effect.exit(rpc.handler(request)),
Effect.flatMap(encode),
Effect.orDie,
Effect.locally(Rpc.currentHeaders, req.headers as any),
Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
})
)
}
const encode = getEncodeChunk(request)
return pipe(
rpc.handler(request),
Stream.map(Exit.succeed),
Stream.catchAllCause((cause) => Stream.succeed(Exit.failCause(cause))),
Stream.runCollect,
Effect.flatMap(encode),
Effect.locally(Rpc.currentHeaders, req.headers as any),
Effect.withSpan(`${spanPrefix}${request._tag}`, {
kind: "server",
parent: {
_tag: "ExternalSpan",
traceId: req.traceId,
spanId: req.spanId,
sampled: req.sampled,
context: Context.empty()
},
captureStackTrace: false
})
)
}, { concurrency: "unbounded" })
)
}
/**
* @category router combinators
* @since 1.0.0
* @category combinators
*/
export const provideServiceEffect: {
<
const Router extends RpcRouter.Base,
T extends Tag<any, any>,
R,
E extends RpcService.Errors<Router["schema"]>
>(
tag: T,
effect: Effect<Tag.Service<T>, E, R>
): (self: Router) => RpcRouter.Provide<Router, Tag.Identifier<T>, R, E>
<
const Router extends RpcRouter.Base,
T extends Tag<any, any>,
R,
E extends RpcService.Errors<Router["schema"]>
>(
self: Router,
tag: T,
effect: Effect<Tag.Service<T>, E, R>
): RpcRouter.Provide<Router, Tag.Identifier<T>, R, E>
} = internal.provideServiceEffect
export const toHandlerRaw = <R extends Router<any, any>>(router: R) => {
const schema: Schema.Schema<
readonly [Schema.TaggedRequest.Any, Rpc.Rpc<any, any>],
unknown,
Router.ContextRaw<R>
> = Schema.Union(...[...router.rpcs].map((rpc) =>
Schema.transform(
Schema.typeSchema(rpc.schema),
Schema.typeSchema(Schema.Tuple(rpc.schema, Schema.Any)),
{ decode: (request) => [request, rpc] as const, encode: ([request]) => request }
)
))
const parse = Schema.decode(schema)
return <Req extends Router.Request<R>>(request: Req): Rpc.Rpc.Result<Req, Router.ContextRaw<R>> => {
const isStream = StreamRequestTypeId in request
const withHandler = parse(request)
if (isStream) {
return Stream.unwrap(Effect.map(
withHandler,
([request, rpc]) => rpc.handler(request)
)) as any
}
return Effect.flatMap(
withHandler,
([request, rpc]) => rpc.handler(request) as any
) as any
}
}
/**
* @category router combinators
* @since 1.0.0
* @category combinators
*/
export const provideServiceSync: {
<T extends Tag<any, any>>(
tag: T,
service: LazyArg<Tag.Service<T>>
): <const Router extends RpcRouter.Base>(
self: Router
) => RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>
<Router extends RpcRouter.Base, T extends Tag<any, any>>(
self: Router,
tag: T,
service: LazyArg<Tag.Service<T>>
): RpcRouter.Provide<Router, Tag.Identifier<T>, never, never>
} = internal.provideServiceSync
export const toHandlerUndecoded = <R extends Router<any, any>>(router: R) => {
const handler = toHandlerRaw(router)
const getEncode = withRequestTag((req) => Schema.encode(Serializable.successSchema(req)))
const getEncodeChunk = withRequestTag((req) => Schema.encode(Schema.ChunkFromSelf(Serializable.successSchema(req))))
return <Req extends Router.Request<R>>(request: Req): Rpc.Rpc.ResultUndecoded<Req, Router.Context<R>> => {
const result = handler(request)
if (Effect.isEffect(result)) {
const encode = getEncode(request)
return Effect.flatMap(result, encode) as any
}
const encode = getEncodeChunk(request)
return Stream.mapChunksEffect(result, encode) as any
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc