@effect-app/infra 1.33.7 → 1.34.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 +16 -0
- package/_cjs/api/routing2.cjs +210 -0
- package/_cjs/api/routing2.cjs.map +1 -0
- package/dist/api/routing2.d.ts +101 -0
- package/dist/api/routing2.d.ts.map +1 -0
- package/dist/api/routing2.js +214 -0
- package/package.json +15 -5
- package/src/api/routing2.ts +561 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @effect-app/infra
|
|
2
2
|
|
|
3
|
+
## 1.34.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c63f8d4: Play with Layer based http routes
|
|
8
|
+
|
|
9
|
+
## 1.33.8
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [0ea3023]
|
|
14
|
+
- effect-app@1.26.8
|
|
15
|
+
- @effect-app/core@1.15.8
|
|
16
|
+
- @effect-app/infra-adapters@1.17.8
|
|
17
|
+
- @effect-app/schema@1.17.8
|
|
18
|
+
|
|
3
19
|
## 1.33.7
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.toHttpApp = exports.makeRouter = exports.RouterSymbol = void 0;
|
|
7
|
+
var _Effect = require("@effect-app/core/Effect");
|
|
8
|
+
var _utils = require("@effect-app/core/utils");
|
|
9
|
+
var _rpc = require("@effect/rpc");
|
|
10
|
+
var _schema = require("@effect/schema");
|
|
11
|
+
var _effectApp = require("effect-app");
|
|
12
|
+
var _http = require("effect-app/http");
|
|
13
|
+
var _errorReporter = require("../errorReporter.cjs");
|
|
14
|
+
var _logger = require("../logger.cjs");
|
|
15
|
+
var _DynamicMiddleware = require("./routing/DynamicMiddleware.cjs");
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
17
|
+
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
18
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
19
|
+
/*
|
|
20
|
+
TODO: Effect.retry(r2, optimisticConcurrencySchedule) / was for PATCH only
|
|
21
|
+
TODO: uninteruptible commands! was for All except GET.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const logRequestError = (0, _errorReporter.logError)("Request");
|
|
25
|
+
const reportRequestError = (0, _errorReporter.reportError)("Request");
|
|
26
|
+
/**
|
|
27
|
+
* Plain jane JSON version
|
|
28
|
+
* @deprecated use HttpRpcRouterNoStream.toHttpApp once support options
|
|
29
|
+
*/
|
|
30
|
+
const toHttpApp = (self, options) => {
|
|
31
|
+
const handler = _rpc.RpcRouter.toHandler(self, options);
|
|
32
|
+
return _effectApp.Effect.withFiberRuntime(fiber => {
|
|
33
|
+
const context = fiber.getFiberRef(_effectApp.FiberRef.currentContext);
|
|
34
|
+
const request = _effectApp.Context.unsafeGet(context, _http.HttpServerRequest.HttpServerRequest);
|
|
35
|
+
return _effectApp.Effect.flatMap(request.json, _ => handler(_).pipe(_effectApp.Stream.provideContext(context), _effectApp.Stream.runCollect, _effectApp.Effect.map(_ => _effectApp.Chunk.toReadonlyArray(_)), _effectApp.Effect.andThen(_ => {
|
|
36
|
+
let status = 200;
|
|
37
|
+
for (const r of _.flat()) {
|
|
38
|
+
if (typeof r === "number") continue;
|
|
39
|
+
const results = Array.isArray(r) ? r : [r];
|
|
40
|
+
if (results.some(_ => _._tag === "Failure" && _.cause._tag === "Die")) {
|
|
41
|
+
status = 500;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
if (results.some(_ => _._tag === "Failure" && _.cause._tag === "Fail")) {
|
|
45
|
+
status = 422; // 418
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return _http.HttpServerResponse.json(_, {
|
|
50
|
+
status
|
|
51
|
+
});
|
|
52
|
+
}), _effectApp.Effect.orDie, _effectApp.Effect.tapDefect((0, _errorReporter.reportError)("RPCHttpApp"))));
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
exports.toHttpApp = toHttpApp;
|
|
56
|
+
const RouterSymbol = exports.RouterSymbol = Symbol();
|
|
57
|
+
const makeRouter = (middleware, devMode) => {
|
|
58
|
+
const rpc = (0, _DynamicMiddleware.makeRpc)(middleware);
|
|
59
|
+
function matchFor(rsc) {
|
|
60
|
+
const meta = rsc.meta;
|
|
61
|
+
if (!meta) throw new Error("Resource has no meta specified"); // TODO: do something with moduleName+cur etc.
|
|
62
|
+
const filtered = (0, _utils.typedKeysOf)(rsc).reduce((acc, cur) => {
|
|
63
|
+
if (_effectApp.Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
|
|
64
|
+
acc[cur] = rsc[cur];
|
|
65
|
+
}
|
|
66
|
+
return acc;
|
|
67
|
+
}, {});
|
|
68
|
+
const matchWithServices = action => {
|
|
69
|
+
return (services, f) => req => _effectApp.Effect.andThen(_effectApp.Effect.all({
|
|
70
|
+
svc: (0, _Effect.allLower)(services),
|
|
71
|
+
ctx: middleware.makeContext
|
|
72
|
+
}), ({
|
|
73
|
+
ctx,
|
|
74
|
+
svc
|
|
75
|
+
}) => f(req, {
|
|
76
|
+
...svc,
|
|
77
|
+
...ctx,
|
|
78
|
+
Response: rsc[action].success
|
|
79
|
+
}));
|
|
80
|
+
};
|
|
81
|
+
const controllers = (controllers, layers) => {
|
|
82
|
+
const mapped = (0, _utils.typedKeysOf)(filtered).reduce((acc, cur) => {
|
|
83
|
+
const handler = controllers[cur];
|
|
84
|
+
const req = rsc[cur];
|
|
85
|
+
acc[cur] = rpc.effect(handler._tag === "raw" ? class extends req {
|
|
86
|
+
static success = _effectApp.S.encodedSchema(req.success);
|
|
87
|
+
get [_schema.Serializable.symbol]() {
|
|
88
|
+
return this.constructor;
|
|
89
|
+
}
|
|
90
|
+
get [_schema.Serializable.symbolResult]() {
|
|
91
|
+
return {
|
|
92
|
+
failure: req.failure,
|
|
93
|
+
success: _effectApp.S.encodedSchema(req.success)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
} : req, req => _effectApp.Effect.annotateCurrentSpan("requestInput", Object.entries(req).reduce((prev, [key, value]) => {
|
|
97
|
+
prev[key] = key === "password" ? "<redacted>" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? typeof value === "string" && value.length > 256 ? value.substring(0, 253) + "..." : value : Array.isArray(value) ? `Array[${value.length}]` : value === null || value === undefined ? `${value}` : typeof value === "object" && value ? `Object[${Object.keys(value).length}]` : typeof value;
|
|
98
|
+
return prev;
|
|
99
|
+
}, {})).pipe(
|
|
100
|
+
// can't use andThen due to some being a function and effect
|
|
101
|
+
_effectApp.Effect.zipRight(handler.handler(req)), _effectApp.Effect.tapErrorCause(cause => _effectApp.Cause.isFailure(cause) ? logRequestError(cause) : _effectApp.Effect.void), _effectApp.Effect.tapDefect(cause => _effectApp.Effect.all([reportRequestError(cause, {
|
|
102
|
+
action: `${meta.moduleName}.${req._tag}`
|
|
103
|
+
}), _rpc.Rpc.currentHeaders.pipe(_effectApp.Effect.andThen(headers => {
|
|
104
|
+
return _logger.InfraLogger.logError("Finished request", cause).pipe(_effectApp.Effect.annotateLogs({
|
|
105
|
+
action: `${meta.moduleName}.${req._tag}`,
|
|
106
|
+
req: (0, _utils.pretty)(req),
|
|
107
|
+
headers: (0, _utils.pretty)(headers)
|
|
108
|
+
// resHeaders: pretty(
|
|
109
|
+
// Object
|
|
110
|
+
// .entries(headers)
|
|
111
|
+
// .reduce((prev, [key, value]) => {
|
|
112
|
+
// prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
113
|
+
// return prev
|
|
114
|
+
// }, {} as Record<string, any>)
|
|
115
|
+
// )
|
|
116
|
+
}));
|
|
117
|
+
}))])), devMode ? _ => _ : _effectApp.Effect.catchAllDefect(() => _effectApp.Effect.die("Internal Server Error")), _effectApp.Effect.withSpan("Request." + meta.moduleName + "." + req._tag, {
|
|
118
|
+
captureStackTrace: () => handler.stack
|
|
119
|
+
})), meta.moduleName); // TODO
|
|
120
|
+
return acc;
|
|
121
|
+
}, {});
|
|
122
|
+
const rpcRouter = _rpc.RpcRouter.make(...Object.values(mapped));
|
|
123
|
+
const r = class Router extends _http.HttpRouter.Tag(meta.moduleName + "Router")() {};
|
|
124
|
+
const layer = r.use(router => _effectApp.Effect.gen(function* () {
|
|
125
|
+
const httpApp = toHttpApp(rpcRouter, {
|
|
126
|
+
spanPrefix: rsc.meta.moduleName + "."
|
|
127
|
+
});
|
|
128
|
+
const services = (yield* _effectApp.Effect.context()).pipe(_effectApp.Context.omit(_effectApp.Scope.Scope), _effectApp.Context.omit(_effectApp.Tracer.ParentSpan));
|
|
129
|
+
yield* router.all("/", httpApp.pipe(_http.HttpMiddleware.make(_effectApp.Effect.provide(services))),
|
|
130
|
+
// TODO: not queries.
|
|
131
|
+
{
|
|
132
|
+
uninterruptible: true
|
|
133
|
+
});
|
|
134
|
+
}));
|
|
135
|
+
const routes = layer.pipe(_effectApp.Layer.provideMerge(r.Live), layers ? _effectApp.Layer.provide(layers) : _ => _);
|
|
136
|
+
// Effect.Effect<HttpRouter.HttpRouter<unknown, HttpRouter.HttpRouter.DefaultServices>, never, UserRouter>
|
|
137
|
+
return {
|
|
138
|
+
moduleName: meta.moduleName,
|
|
139
|
+
Router: r,
|
|
140
|
+
routes
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
const r = {
|
|
144
|
+
controllers,
|
|
145
|
+
...(0, _utils.typedKeysOf)(filtered).reduce((prev, cur) => {
|
|
146
|
+
;
|
|
147
|
+
prev[cur] = (svcOrFnOrEffect, fnOrNone) => {
|
|
148
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n");
|
|
149
|
+
return _effectApp.Effect.isEffect(svcOrFnOrEffect) ? class {
|
|
150
|
+
static stack = stack;
|
|
151
|
+
static _tag = "d";
|
|
152
|
+
static handler = () => svcOrFnOrEffect;
|
|
153
|
+
} : typeof svcOrFnOrEffect === "function" ? class {
|
|
154
|
+
static stack = stack;
|
|
155
|
+
static _tag = "d";
|
|
156
|
+
static handler = req => _effectApp.Effect.andThen(_effectApp.Effect.all({
|
|
157
|
+
ctx: middleware.makeContext
|
|
158
|
+
}), ({
|
|
159
|
+
ctx
|
|
160
|
+
}) => svcOrFnOrEffect(req, {
|
|
161
|
+
...ctx,
|
|
162
|
+
Response: rsc[cur].success
|
|
163
|
+
}));
|
|
164
|
+
} : class {
|
|
165
|
+
static stack = stack;
|
|
166
|
+
static _tag = "d";
|
|
167
|
+
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
|
|
168
|
+
};
|
|
169
|
+
} // "Raw" variations are for when you don't want to decode just to encode it again on the response
|
|
170
|
+
;
|
|
171
|
+
prev[cur + "Raw"] = (svcOrFnOrEffect, fnOrNone) => {
|
|
172
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n");
|
|
173
|
+
return _effectApp.Effect.isEffect(svcOrFnOrEffect) ? class {
|
|
174
|
+
static stack = stack;
|
|
175
|
+
static _tag = "raw";
|
|
176
|
+
static handler = () => svcOrFnOrEffect;
|
|
177
|
+
} : typeof svcOrFnOrEffect === "function" ? class {
|
|
178
|
+
static stack = stack;
|
|
179
|
+
static _tag = "raw";
|
|
180
|
+
static handler = (req, ctx) => svcOrFnOrEffect(req, {
|
|
181
|
+
...ctx,
|
|
182
|
+
Response: rsc[cur].success
|
|
183
|
+
});
|
|
184
|
+
} : class {
|
|
185
|
+
static stack = stack;
|
|
186
|
+
static _tag = "raw";
|
|
187
|
+
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
return prev;
|
|
191
|
+
}, {})
|
|
192
|
+
};
|
|
193
|
+
return r;
|
|
194
|
+
}
|
|
195
|
+
function matchAll(handlers) {
|
|
196
|
+
const routers = (0, _utils.typedValuesOf)(handlers);
|
|
197
|
+
const r = _http.HttpRouter.Default.use(router => _effectApp.Effect.gen(function* () {
|
|
198
|
+
for (const route of routers) {
|
|
199
|
+
yield* router.mount("/rpc/" + route.moduleName, yield* route.Router.router);
|
|
200
|
+
}
|
|
201
|
+
})).pipe(_effectApp.Layer.provide(routers.map(r => r.routes).flat()));
|
|
202
|
+
return r;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
matchAll,
|
|
206
|
+
matchFor
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
exports.makeRouter = makeRouter;
|
|
210
|
+
//# sourceMappingURL=routing2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing2.cjs","names":["_Effect","require","_utils","_rpc","_schema","_effectApp","_http","_errorReporter","_logger","_DynamicMiddleware","logRequestError","logError","reportRequestError","reportError","toHttpApp","self","options","handler","RpcRouter","toHandler","Effect","withFiberRuntime","fiber","context","getFiberRef","FiberRef","currentContext","request","Context","unsafeGet","HttpServerRequest","flatMap","json","_","pipe","Stream","provideContext","runCollect","map","Chunk","toReadonlyArray","andThen","status","r","flat","results","Array","isArray","some","_tag","cause","HttpServerResponse","orDie","tapDefect","exports","RouterSymbol","Symbol","makeRouter","middleware","devMode","rpc","makeRpc","matchFor","rsc","meta","Error","filtered","typedKeysOf","reduce","acc","cur","Predicate","isObject","matchWithServices","action","services","f","req","all","svc","allLower","ctx","makeContext","Response","success","controllers","layers","mapped","effect","S","encodedSchema","Serializable","symbol","constructor","symbolResult","failure","annotateCurrentSpan","Object","entries","prev","key","value","length","substring","undefined","keys","zipRight","tapErrorCause","Cause","isFailure","void","moduleName","Rpc","currentHeaders","headers","InfraLogger","annotateLogs","pretty","catchAllDefect","die","withSpan","captureStackTrace","stack","rpcRouter","make","values","Router","HttpRouter","Tag","layer","use","router","gen","httpApp","spanPrefix","omit","Scope","Tracer","ParentSpan","HttpMiddleware","provide","uninterruptible","routes","Layer","provideMerge","Live","svcOrFnOrEffect","fnOrNone","split","slice","join","isEffect","matchAll","handlers","routers","typedValuesOf","Default","route","mount"],"sources":["../../src/api/routing2.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { type EffectUnunified, type LowerServices } from "@effect-app/core/Effect";
|
|
2
|
+
import type * as HttpApp from "@effect/platform/HttpApp";
|
|
3
|
+
import { Rpc, RpcRouter } from "@effect/rpc";
|
|
4
|
+
import type { NonEmptyArray } from "effect-app";
|
|
5
|
+
import { Effect, Layer, S } from "effect-app";
|
|
6
|
+
import type { GetEffectContext, RPCContextMap } from "effect-app/client/req";
|
|
7
|
+
import type { HttpServerError } from "effect-app/http";
|
|
8
|
+
import { HttpRouter } from "effect-app/http";
|
|
9
|
+
import type { Middleware } from "./routing/DynamicMiddleware.js";
|
|
10
|
+
export type _R<T extends Effect<any, any, any>> = [T] extends [
|
|
11
|
+
Effect<any, any, infer R>
|
|
12
|
+
] ? R : never;
|
|
13
|
+
export type _E<T extends Effect<any, any, any>> = [T] extends [
|
|
14
|
+
Effect<any, infer E, any>
|
|
15
|
+
] ? E : never;
|
|
16
|
+
export type EffectDeps<A> = {
|
|
17
|
+
[K in keyof A as A[K] extends Effect<any, any, any> ? K : never]: A[K] extends Effect<any, any, any> ? A[K] : never;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Plain jane JSON version
|
|
21
|
+
* @deprecated use HttpRpcRouterNoStream.toHttpApp once support options
|
|
22
|
+
*/
|
|
23
|
+
export declare const toHttpApp: <R extends RpcRouter.RpcRouter<any, any>>(self: R, options?: {
|
|
24
|
+
readonly spanPrefix?: string;
|
|
25
|
+
}) => HttpApp.Default<HttpServerError.RequestError, RpcRouter.RpcRouter.Context<R>>;
|
|
26
|
+
export interface Hint<Err extends string> {
|
|
27
|
+
Err: Err;
|
|
28
|
+
}
|
|
29
|
+
type HandleVoid<Expected, Actual, Result> = [Expected] extends [void] ? [Actual] extends [void] ? Result : Hint<"You're returning non void for a void Response, please fix"> : Result;
|
|
30
|
+
type AnyRequestModule = S.Schema.Any & {
|
|
31
|
+
success?: S.Schema.Any;
|
|
32
|
+
failure?: S.Schema.Any;
|
|
33
|
+
};
|
|
34
|
+
type GetSuccess<T> = T extends {
|
|
35
|
+
success: S.Schema.Any;
|
|
36
|
+
} ? T["success"] : typeof S.Void;
|
|
37
|
+
type GetFailure<T extends {
|
|
38
|
+
failure?: S.Schema.Any;
|
|
39
|
+
}> = T["failure"] extends never ? typeof S.Never : T["failure"];
|
|
40
|
+
export interface Handler<Action extends AnyRequestModule, RT extends "raw" | "d", A, E, R> {
|
|
41
|
+
new (): {};
|
|
42
|
+
_tag: RT;
|
|
43
|
+
stack: string;
|
|
44
|
+
handler: (req: S.Schema.Type<Action>) => Effect<A, E, R>;
|
|
45
|
+
}
|
|
46
|
+
type AHandler<Action extends AnyRequestModule> = Handler<Action, "raw", S.Schema.Encoded<GetSuccess<Action>>, S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError, any> | Handler<Action, "d", S.Schema.Type<GetSuccess<Action>>, S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError, any>;
|
|
47
|
+
type Filter<T> = {
|
|
48
|
+
[K in keyof T as T[K] extends S.Schema.All & {
|
|
49
|
+
success: S.Schema.Any;
|
|
50
|
+
failure: S.Schema.Any;
|
|
51
|
+
} ? K : never]: T[K];
|
|
52
|
+
};
|
|
53
|
+
interface ExtendedMiddleware<Context, CTXMap extends Record<string, RPCContextMap.Any>> extends Middleware<Context, CTXMap> {
|
|
54
|
+
makeContext: Effect<{
|
|
55
|
+
[K in keyof CTXMap as CTXMap[K][1] extends never ? never : CTXMap[K][0]]: CTXMap[K][1];
|
|
56
|
+
}, never, never>;
|
|
57
|
+
}
|
|
58
|
+
export declare const RouterSymbol: unique symbol;
|
|
59
|
+
export interface RouterS<Rsc> {
|
|
60
|
+
[RouterSymbol]: Rsc;
|
|
61
|
+
}
|
|
62
|
+
export declare const makeRouter: <Context, CTXMap extends Record<string, RPCContextMap.Any>>(middleware: ExtendedMiddleware<Context, CTXMap>, devMode: boolean) => {
|
|
63
|
+
matchAll: <T extends {
|
|
64
|
+
[key: string]: {
|
|
65
|
+
Router: {
|
|
66
|
+
router: Effect<HttpRouter.HttpRouter<any, any>, any, any>;
|
|
67
|
+
};
|
|
68
|
+
routes: Layer.Layer<any, any, any>;
|
|
69
|
+
moduleName: string;
|
|
70
|
+
};
|
|
71
|
+
}>(handlers: T) => Layer.Layer<never, Layer.Layer.Error<(typeof handlers)[keyof typeof handlers]["routes"]>, Layer.Layer.Context<(typeof handlers)[keyof typeof handlers]["routes"]>>;
|
|
72
|
+
matchFor: <Rsc extends Record<string, any> & {
|
|
73
|
+
meta: {
|
|
74
|
+
moduleName: string;
|
|
75
|
+
};
|
|
76
|
+
}>(rsc: Rsc) => {
|
|
77
|
+
controllers: <THandlers extends { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]>; }, TLayers extends NonEmptyArray<Layer.Layer.Any>>(controllers: THandlers, layers?: TLayers) => {
|
|
78
|
+
moduleName: string;
|
|
79
|
+
Router: HttpRouter.HttpRouter.TagClass<RouterS<Rsc>, string, never, never>;
|
|
80
|
+
routes: Layer.Layer<RouterS<Rsc>, { [k in keyof TLayers]: Layer.Layer.Error<TLayers[k]>; }[number], { [k_1 in keyof TLayers]: Layer.Layer.Context<TLayers[k_1]>; }[number] | Exclude<[{ [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<THandlers[K]["handler"]>>>; }[keyof Filter<Rsc>]] extends [Rpc.Rpc<any, infer R>] ? R : never, { [k_2 in keyof TLayers]: Layer.Layer.Success<TLayers[k_2]>; }[number]>>;
|
|
81
|
+
};
|
|
82
|
+
} & { [Key in keyof Filter<Rsc>]: {
|
|
83
|
+
<R2, E, A>(f: Effect<A, E, R2>): HandleVoid<S.Schema.Type<GetSuccess<Rsc[Key]>>, A, Handler<Rsc[Key], "d", A, E, Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>>>;
|
|
84
|
+
<R2, E_1, A_1>(f: (req: S.Schema.Type<Rsc[Key]>, ctx: { [key in keyof CTXMap as CTXMap[key][3] extends true ? never : key extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as CTXMap[key_1][3] extends true ? never : key_1 extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & { [key_2 in keyof CTXMap as CTXMap[key_2][3] extends false ? never : key_2 extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key_2] extends true ? CTXMap[key_2][0] : never : never]: CTXMap[key_2][1]; } & { [key_3 in keyof CTXMap as CTXMap[key_3][3] extends false ? never : key_3 extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key_3] extends false ? CTXMap[key_3][0] : never : CTXMap[key_3][0]]?: CTXMap[key_3][1]; } & {
|
|
85
|
+
Response: Rsc[Key]["success"];
|
|
86
|
+
}) => Effect<A_1, E_1, R2>): HandleVoid<S.Schema.Type<GetSuccess<Rsc[Key]>>, A_1, Handler<Rsc[Key], "d", A_1, E_1, Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>>>;
|
|
87
|
+
<SVC extends Record<string, EffectUnunified<any, any, any>>, R2, E_2, A_2>(services: SVC, f: (req: S.Schema.Type<Rsc[Key]>, ctx: import("@effect-app/core/utils").ComputeFlat<LowerServices<EffectDeps<SVC>> & { [key in keyof CTXMap as CTXMap[key][3] extends true ? never : key extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as CTXMap[key_1][3] extends true ? never : key_1 extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & { [key_2 in keyof CTXMap as CTXMap[key_2][3] extends false ? never : key_2 extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key_2] extends true ? CTXMap[key_2][0] : never : never]: CTXMap[key_2][1]; } & { [key_3 in keyof CTXMap as CTXMap[key_3][3] extends false ? never : key_3 extends keyof Rsc[Key]["config"] ? Rsc[Key]["config"][key_3] extends false ? CTXMap[key_3][0] : never : CTXMap[key_3][0]]?: CTXMap[key_3][1]; } & {
|
|
88
|
+
Response: Rsc[Key]["success"];
|
|
89
|
+
}>) => Effect<A_2, E_2, R2>): HandleVoid<S.Schema.Type<GetSuccess<Rsc[Key]>>, A_2, Handler<Rsc[Key], "d", A_2, E_2, Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>>>;
|
|
90
|
+
}; } & { [Key_1 in keyof Filter<Rsc> as Key_1 extends string ? `${Key_1}Raw` : never]: {
|
|
91
|
+
<R2_1, E, A>(f: Effect<A, E, R2_1>): HandleVoid<S.Schema.Encoded<GetSuccess<Rsc[Key_1]>>, A, Handler<Rsc[Key_1], "raw", A, E, Exclude<R2_1, GetEffectContext<CTXMap, Rsc[Key_1]["config"]>>>>;
|
|
92
|
+
<R2_1, E_1, A_1>(f: (req: S.Schema.Type<Rsc[Key_1]>, ctx: { [key in keyof CTXMap as CTXMap[key][3] extends true ? never : key extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as CTXMap[key_1][3] extends true ? never : key_1 extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & { [key_2 in keyof CTXMap as CTXMap[key_2][3] extends false ? never : key_2 extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key_2] extends true ? CTXMap[key_2][0] : never : never]: CTXMap[key_2][1]; } & { [key_3 in keyof CTXMap as CTXMap[key_3][3] extends false ? never : key_3 extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key_3] extends false ? CTXMap[key_3][0] : never : CTXMap[key_3][0]]?: CTXMap[key_3][1]; } & {
|
|
93
|
+
Response: Rsc[Key_1]["success"];
|
|
94
|
+
}) => Effect<A_1, E_1, R2_1>): HandleVoid<S.Schema.Encoded<GetSuccess<Rsc[Key_1]>>, A_1, Handler<Rsc[Key_1], "raw", A_1, E_1, Exclude<R2_1, GetEffectContext<CTXMap, Rsc[Key_1]["config"]>>>>;
|
|
95
|
+
<SVC extends Record<string, EffectUnunified<any, any, any>>, R2, E_2, A_2>(services: SVC, f: (req: S.Schema.Type<Rsc[Key_1]>, ctx: import("@effect-app/core/utils").ComputeFlat<LowerServices<EffectDeps<SVC>> & { [key in keyof CTXMap as CTXMap[key][3] extends true ? never : key extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as CTXMap[key_1][3] extends true ? never : key_1 extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & { [key_2 in keyof CTXMap as CTXMap[key_2][3] extends false ? never : key_2 extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key_2] extends true ? CTXMap[key_2][0] : never : never]: CTXMap[key_2][1]; } & { [key_3 in keyof CTXMap as CTXMap[key_3][3] extends false ? never : key_3 extends keyof Rsc[Key_1]["config"] ? Rsc[Key_1]["config"][key_3] extends false ? CTXMap[key_3][0] : never : CTXMap[key_3][0]]?: CTXMap[key_3][1]; } & {
|
|
96
|
+
Response: Rsc[Key_1]["success"];
|
|
97
|
+
}>) => Effect<A_2, E_2, R2>): HandleVoid<S.Schema.Encoded<GetSuccess<Rsc[Key_1]>>, A_2, Handler<Rsc[Key_1], "raw", A_2, E_2, Exclude<R2, GetEffectContext<CTXMap, Rsc[Key_1]["config"]>>>>;
|
|
98
|
+
}; };
|
|
99
|
+
};
|
|
100
|
+
export {};
|
|
101
|
+
//# sourceMappingURL=routing2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing2.d.ts","sourceRoot":"","sources":["../../src/api/routing2.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
/*
|
|
5
|
+
TODO: Effect.retry(r2, optimisticConcurrencySchedule) / was for PATCH only
|
|
6
|
+
TODO: uninteruptible commands! was for All except GET.
|
|
7
|
+
*/
|
|
8
|
+
import { allLower } from "@effect-app/core/Effect";
|
|
9
|
+
import { pretty, typedKeysOf, typedValuesOf } from "@effect-app/core/utils";
|
|
10
|
+
import { Rpc, RpcRouter } from "@effect/rpc";
|
|
11
|
+
import { Serializable } from "@effect/schema";
|
|
12
|
+
import { Cause, Chunk, Context, Effect, FiberRef, Layer, Predicate, S, Scope, Stream, Tracer } from "effect-app";
|
|
13
|
+
import { HttpMiddleware, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http";
|
|
14
|
+
import { logError, reportError } from "../errorReporter.js";
|
|
15
|
+
import { InfraLogger } from "../logger.js";
|
|
16
|
+
import { makeRpc } from "./routing/DynamicMiddleware.js";
|
|
17
|
+
const logRequestError = logError("Request");
|
|
18
|
+
const reportRequestError = reportError("Request");
|
|
19
|
+
/**
|
|
20
|
+
* Plain jane JSON version
|
|
21
|
+
* @deprecated use HttpRpcRouterNoStream.toHttpApp once support options
|
|
22
|
+
*/
|
|
23
|
+
export const toHttpApp = (self, options) => {
|
|
24
|
+
const handler = RpcRouter.toHandler(self, options);
|
|
25
|
+
return Effect.withFiberRuntime((fiber) => {
|
|
26
|
+
const context = fiber.getFiberRef(FiberRef.currentContext);
|
|
27
|
+
const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest);
|
|
28
|
+
return Effect.flatMap(request.json, (_) => handler(_).pipe(Stream.provideContext(context), Stream.runCollect, Effect.map((_) => Chunk.toReadonlyArray(_)), Effect.andThen((_) => {
|
|
29
|
+
let status = 200;
|
|
30
|
+
for (const r of _.flat()) {
|
|
31
|
+
if (typeof r === "number")
|
|
32
|
+
continue;
|
|
33
|
+
const results = Array.isArray(r) ? r : [r];
|
|
34
|
+
if (results.some((_) => _._tag === "Failure" && _.cause._tag === "Die")) {
|
|
35
|
+
status = 500;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
if (results.some((_) => _._tag === "Failure" && _.cause._tag === "Fail")) {
|
|
39
|
+
status = 422; // 418
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return HttpServerResponse.json(_, { status });
|
|
44
|
+
}), Effect.orDie, Effect.tapDefect(reportError("RPCHttpApp"))));
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
export const RouterSymbol = Symbol();
|
|
48
|
+
export const makeRouter = (middleware, devMode) => {
|
|
49
|
+
const rpc = makeRpc(middleware);
|
|
50
|
+
function matchFor(rsc) {
|
|
51
|
+
const meta = rsc.meta;
|
|
52
|
+
if (!meta)
|
|
53
|
+
throw new Error("Resource has no meta specified"); // TODO: do something with moduleName+cur etc.
|
|
54
|
+
const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
|
|
55
|
+
if (Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
|
|
56
|
+
acc[cur] = rsc[cur];
|
|
57
|
+
}
|
|
58
|
+
return acc;
|
|
59
|
+
}, {});
|
|
60
|
+
const matchWithServices = (action) => {
|
|
61
|
+
return (services, f) => (req) => Effect.andThen(Effect.all({ svc: allLower(services), ctx: middleware.makeContext }), ({ ctx, svc }) => f(req, { ...svc, ...ctx, Response: rsc[action].success }));
|
|
62
|
+
};
|
|
63
|
+
const controllers = (controllers, layers) => {
|
|
64
|
+
const mapped = typedKeysOf(filtered).reduce((acc, cur) => {
|
|
65
|
+
const handler = controllers[cur];
|
|
66
|
+
const req = rsc[cur];
|
|
67
|
+
acc[cur] = rpc.effect(handler._tag === "raw"
|
|
68
|
+
? class extends req {
|
|
69
|
+
static success = S.encodedSchema(req.success);
|
|
70
|
+
get [Serializable.symbol]() {
|
|
71
|
+
return this.constructor;
|
|
72
|
+
}
|
|
73
|
+
get [Serializable.symbolResult]() {
|
|
74
|
+
return {
|
|
75
|
+
failure: req.failure,
|
|
76
|
+
success: S.encodedSchema(req.success)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
: req, (req) => Effect
|
|
81
|
+
.annotateCurrentSpan("requestInput", Object.entries(req).reduce((prev, [key, value]) => {
|
|
82
|
+
prev[key] = key === "password"
|
|
83
|
+
? "<redacted>"
|
|
84
|
+
: typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
85
|
+
? typeof value === "string" && value.length > 256
|
|
86
|
+
? (value.substring(0, 253) + "...")
|
|
87
|
+
: value
|
|
88
|
+
: Array.isArray(value)
|
|
89
|
+
? `Array[${value.length}]`
|
|
90
|
+
: value === null || value === undefined
|
|
91
|
+
? `${value}`
|
|
92
|
+
: typeof value === "object" && value
|
|
93
|
+
? `Object[${Object.keys(value).length}]`
|
|
94
|
+
: typeof value;
|
|
95
|
+
return prev;
|
|
96
|
+
}, {}))
|
|
97
|
+
.pipe(
|
|
98
|
+
// can't use andThen due to some being a function and effect
|
|
99
|
+
Effect.zipRight(handler.handler(req)), Effect.tapErrorCause((cause) => Cause.isFailure(cause) ? logRequestError(cause) : Effect.void), Effect.tapDefect((cause) => Effect
|
|
100
|
+
.all([
|
|
101
|
+
reportRequestError(cause, {
|
|
102
|
+
action: `${meta.moduleName}.${req._tag}`
|
|
103
|
+
}),
|
|
104
|
+
Rpc.currentHeaders.pipe(Effect.andThen((headers) => {
|
|
105
|
+
return InfraLogger
|
|
106
|
+
.logError("Finished request", cause)
|
|
107
|
+
.pipe(Effect.annotateLogs({
|
|
108
|
+
action: `${meta.moduleName}.${req._tag}`,
|
|
109
|
+
req: pretty(req),
|
|
110
|
+
headers: pretty(headers)
|
|
111
|
+
// resHeaders: pretty(
|
|
112
|
+
// Object
|
|
113
|
+
// .entries(headers)
|
|
114
|
+
// .reduce((prev, [key, value]) => {
|
|
115
|
+
// prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
116
|
+
// return prev
|
|
117
|
+
// }, {} as Record<string, any>)
|
|
118
|
+
// )
|
|
119
|
+
}));
|
|
120
|
+
}))
|
|
121
|
+
])), devMode ? (_) => _ : Effect.catchAllDefect(() => Effect.die("Internal Server Error")), Effect.withSpan("Request." + meta.moduleName + "." + req._tag, {
|
|
122
|
+
captureStackTrace: () => handler.stack
|
|
123
|
+
})), meta.moduleName); // TODO
|
|
124
|
+
return acc;
|
|
125
|
+
}, {});
|
|
126
|
+
const rpcRouter = RpcRouter.make(...Object.values(mapped));
|
|
127
|
+
const r = (class Router extends HttpRouter.Tag(meta.moduleName + "Router")() {
|
|
128
|
+
});
|
|
129
|
+
const layer = r.use((router) => Effect.gen(function* () {
|
|
130
|
+
const httpApp = toHttpApp(rpcRouter, {
|
|
131
|
+
spanPrefix: rsc
|
|
132
|
+
.meta
|
|
133
|
+
.moduleName + "."
|
|
134
|
+
});
|
|
135
|
+
const services = (yield* Effect.context()).pipe(Context.omit(Scope.Scope), Context.omit(Tracer.ParentSpan));
|
|
136
|
+
yield* router
|
|
137
|
+
.all("/", (httpApp
|
|
138
|
+
.pipe(HttpMiddleware.make(Effect.provide(services)))),
|
|
139
|
+
// TODO: not queries.
|
|
140
|
+
{ uninterruptible: true });
|
|
141
|
+
}));
|
|
142
|
+
const routes = layer.pipe(Layer.provideMerge(r.Live), layers ? Layer.provide(layers) : (_) => _);
|
|
143
|
+
// Effect.Effect<HttpRouter.HttpRouter<unknown, HttpRouter.HttpRouter.DefaultServices>, never, UserRouter>
|
|
144
|
+
return {
|
|
145
|
+
moduleName: meta.moduleName,
|
|
146
|
+
Router: r,
|
|
147
|
+
routes
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
const r = {
|
|
151
|
+
controllers,
|
|
152
|
+
...typedKeysOf(filtered).reduce((prev, cur) => {
|
|
153
|
+
;
|
|
154
|
+
prev[cur] = (svcOrFnOrEffect, fnOrNone) => {
|
|
155
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n");
|
|
156
|
+
return Effect.isEffect(svcOrFnOrEffect)
|
|
157
|
+
? class {
|
|
158
|
+
static stack = stack;
|
|
159
|
+
static _tag = "d";
|
|
160
|
+
static handler = () => svcOrFnOrEffect;
|
|
161
|
+
}
|
|
162
|
+
: typeof svcOrFnOrEffect === "function"
|
|
163
|
+
? class {
|
|
164
|
+
static stack = stack;
|
|
165
|
+
static _tag = "d";
|
|
166
|
+
static handler = (req) => Effect.andThen(Effect.all({ ctx: middleware.makeContext }), ({ ctx }) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].success }));
|
|
167
|
+
}
|
|
168
|
+
: class {
|
|
169
|
+
static stack = stack;
|
|
170
|
+
static _tag = "d";
|
|
171
|
+
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
|
|
172
|
+
};
|
|
173
|
+
} // "Raw" variations are for when you don't want to decode just to encode it again on the response
|
|
174
|
+
;
|
|
175
|
+
prev[cur + "Raw"] = (svcOrFnOrEffect, fnOrNone) => {
|
|
176
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n");
|
|
177
|
+
return Effect.isEffect(svcOrFnOrEffect)
|
|
178
|
+
? class {
|
|
179
|
+
static stack = stack;
|
|
180
|
+
static _tag = "raw";
|
|
181
|
+
static handler = () => svcOrFnOrEffect;
|
|
182
|
+
}
|
|
183
|
+
: typeof svcOrFnOrEffect === "function"
|
|
184
|
+
? class {
|
|
185
|
+
static stack = stack;
|
|
186
|
+
static _tag = "raw";
|
|
187
|
+
static handler = (req, ctx) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].success });
|
|
188
|
+
}
|
|
189
|
+
: class {
|
|
190
|
+
static stack = stack;
|
|
191
|
+
static _tag = "raw";
|
|
192
|
+
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
return prev;
|
|
196
|
+
}, {})
|
|
197
|
+
};
|
|
198
|
+
return r;
|
|
199
|
+
}
|
|
200
|
+
function matchAll(handlers) {
|
|
201
|
+
const routers = typedValuesOf(handlers);
|
|
202
|
+
const r = HttpRouter
|
|
203
|
+
.Default
|
|
204
|
+
.use((router) => Effect.gen(function* () {
|
|
205
|
+
for (const route of routers) {
|
|
206
|
+
yield* router.mount(("/rpc/" + route.moduleName), yield* route.Router.router);
|
|
207
|
+
}
|
|
208
|
+
}))
|
|
209
|
+
.pipe(Layer.provide(routers.map((r) => r.routes).flat()));
|
|
210
|
+
return r;
|
|
211
|
+
}
|
|
212
|
+
return { matchAll, matchFor };
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGluZzIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JvdXRpbmcyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDBEQUEwRDtBQUMxRCw0REFBNEQ7QUFDNUQsdURBQXVEO0FBQ3ZEOzs7RUFHRTtBQUNGLE9BQU8sRUFBRSxRQUFRLEVBQTRDLE1BQU0seUJBQXlCLENBQUE7QUFDNUYsT0FBTyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFHM0UsT0FBTyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDNUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRTdDLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBR2hILE9BQU8sRUFBRSxjQUFjLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixFQUFFLGtCQUFrQixFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDbkcsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUMzRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBRTFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQTtBQUV4RCxNQUFNLGVBQWUsR0FBRyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUE7QUFDM0MsTUFBTSxrQkFBa0IsR0FBRyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUE7QUFlakQ7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLENBQTBDLElBQU8sRUFBRSxPQUUzRSxFQUdDLEVBQUU7SUFDRixNQUFNLE9B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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"proper-lockfile": "^4.1.2",
|
|
21
21
|
"pure-rand": "6.1.0",
|
|
22
22
|
"redlock": "^4.2.0",
|
|
23
|
-
"@effect-app/
|
|
24
|
-
"@effect-app/
|
|
25
|
-
"effect-app": "1.26.
|
|
26
|
-
"@effect-app/infra-adapters": "1.17.
|
|
23
|
+
"@effect-app/schema": "1.17.8",
|
|
24
|
+
"@effect-app/core": "1.15.8",
|
|
25
|
+
"effect-app": "1.26.8",
|
|
26
|
+
"@effect-app/infra-adapters": "1.17.8"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@babel/cli": "^7.25.7",
|
|
@@ -147,6 +147,16 @@
|
|
|
147
147
|
"default": "./_cjs/api/routing/schema/jwt.cjs"
|
|
148
148
|
}
|
|
149
149
|
},
|
|
150
|
+
"./api/routing2": {
|
|
151
|
+
"import": {
|
|
152
|
+
"types": "./dist/api/routing2.d.ts",
|
|
153
|
+
"default": "./dist/api/routing2.js"
|
|
154
|
+
},
|
|
155
|
+
"require": {
|
|
156
|
+
"types": "./dist/api/routing2.d.ts",
|
|
157
|
+
"default": "./_cjs/api/routing2.cjs"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
150
160
|
"./api/setupRequest": {
|
|
151
161
|
"import": {
|
|
152
162
|
"types": "./dist/api/setupRequest.d.ts",
|
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
/*
|
|
5
|
+
TODO: Effect.retry(r2, optimisticConcurrencySchedule) / was for PATCH only
|
|
6
|
+
TODO: uninteruptible commands! was for All except GET.
|
|
7
|
+
*/
|
|
8
|
+
import { allLower, type EffectUnunified, type LowerServices } from "@effect-app/core/Effect"
|
|
9
|
+
import { pretty, typedKeysOf, typedValuesOf } from "@effect-app/core/utils"
|
|
10
|
+
import type { Compute } from "@effect-app/core/utils"
|
|
11
|
+
import type * as HttpApp from "@effect/platform/HttpApp"
|
|
12
|
+
import { Rpc, RpcRouter } from "@effect/rpc"
|
|
13
|
+
import { Serializable } from "@effect/schema"
|
|
14
|
+
import type { NonEmptyArray } from "effect-app"
|
|
15
|
+
import { Cause, Chunk, Context, Effect, FiberRef, Layer, Predicate, S, Scope, Stream, Tracer } from "effect-app"
|
|
16
|
+
import type { GetEffectContext, RPCContextMap } from "effect-app/client/req"
|
|
17
|
+
import type { HttpServerError } from "effect-app/http"
|
|
18
|
+
import { HttpMiddleware, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
19
|
+
import { logError, reportError } from "../errorReporter.js"
|
|
20
|
+
import { InfraLogger } from "../logger.js"
|
|
21
|
+
import type { Middleware } from "./routing/DynamicMiddleware.js"
|
|
22
|
+
import { makeRpc } from "./routing/DynamicMiddleware.js"
|
|
23
|
+
|
|
24
|
+
const logRequestError = logError("Request")
|
|
25
|
+
const reportRequestError = reportError("Request")
|
|
26
|
+
|
|
27
|
+
export type _R<T extends Effect<any, any, any>> = [T] extends [
|
|
28
|
+
Effect<any, any, infer R>
|
|
29
|
+
] ? R
|
|
30
|
+
: never
|
|
31
|
+
|
|
32
|
+
export type _E<T extends Effect<any, any, any>> = [T] extends [
|
|
33
|
+
Effect<any, infer E, any>
|
|
34
|
+
] ? E
|
|
35
|
+
: never
|
|
36
|
+
|
|
37
|
+
export type EffectDeps<A> = {
|
|
38
|
+
[K in keyof A as A[K] extends Effect<any, any, any> ? K : never]: A[K] extends Effect<any, any, any> ? A[K] : never
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Plain jane JSON version
|
|
42
|
+
* @deprecated use HttpRpcRouterNoStream.toHttpApp once support options
|
|
43
|
+
*/
|
|
44
|
+
export const toHttpApp = <R extends RpcRouter.RpcRouter<any, any>>(self: R, options?: {
|
|
45
|
+
readonly spanPrefix?: string
|
|
46
|
+
}): HttpApp.Default<
|
|
47
|
+
HttpServerError.RequestError,
|
|
48
|
+
RpcRouter.RpcRouter.Context<R>
|
|
49
|
+
> => {
|
|
50
|
+
const handler = RpcRouter.toHandler(self, options)
|
|
51
|
+
return Effect.withFiberRuntime((fiber) => {
|
|
52
|
+
const context = fiber.getFiberRef(FiberRef.currentContext)
|
|
53
|
+
const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest)
|
|
54
|
+
return Effect.flatMap(
|
|
55
|
+
request.json,
|
|
56
|
+
(_) =>
|
|
57
|
+
handler(_).pipe(
|
|
58
|
+
Stream.provideContext(context),
|
|
59
|
+
Stream.runCollect,
|
|
60
|
+
Effect.map((_) => Chunk.toReadonlyArray(_)),
|
|
61
|
+
Effect.andThen((_) => {
|
|
62
|
+
let status = 200
|
|
63
|
+
for (const r of _.flat()) {
|
|
64
|
+
if (typeof r === "number") continue
|
|
65
|
+
const results = Array.isArray(r) ? r : [r]
|
|
66
|
+
if (results.some((_: S.ExitEncoded<any, any, any>) => _._tag === "Failure" && _.cause._tag === "Die")) {
|
|
67
|
+
status = 500
|
|
68
|
+
break
|
|
69
|
+
}
|
|
70
|
+
if (results.some((_: S.ExitEncoded<any, any, any>) => _._tag === "Failure" && _.cause._tag === "Fail")) {
|
|
71
|
+
status = 422 // 418
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return HttpServerResponse.json(_, { status })
|
|
76
|
+
}),
|
|
77
|
+
Effect.orDie,
|
|
78
|
+
Effect.tapDefect(reportError("RPCHttpApp"))
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type GetRouteContext<CTXMap extends Record<string, RPCContextMap.Any>, T> =
|
|
85
|
+
// & CTX
|
|
86
|
+
// inverted
|
|
87
|
+
& {
|
|
88
|
+
[
|
|
89
|
+
key in keyof CTXMap as CTXMap[key][3] extends true ? never
|
|
90
|
+
: key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
|
|
91
|
+
: never
|
|
92
|
+
]?: CTXMap[key][1]
|
|
93
|
+
}
|
|
94
|
+
& {
|
|
95
|
+
[
|
|
96
|
+
key in keyof CTXMap as CTXMap[key][3] extends true ? never
|
|
97
|
+
: key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never
|
|
98
|
+
: CTXMap[key][0]
|
|
99
|
+
]: CTXMap[key][1]
|
|
100
|
+
}
|
|
101
|
+
// normal
|
|
102
|
+
& {
|
|
103
|
+
[
|
|
104
|
+
key in keyof CTXMap as CTXMap[key][3] extends false ? never
|
|
105
|
+
: key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
|
|
106
|
+
: never
|
|
107
|
+
]: CTXMap[key][1]
|
|
108
|
+
}
|
|
109
|
+
& {
|
|
110
|
+
[
|
|
111
|
+
key in keyof CTXMap as CTXMap[key][3] extends false ? never
|
|
112
|
+
: key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never
|
|
113
|
+
: CTXMap[key][0]
|
|
114
|
+
]?: CTXMap[key][1]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface Hint<Err extends string> {
|
|
118
|
+
Err: Err
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type HandleVoid<Expected, Actual, Result> = [Expected] extends [void]
|
|
122
|
+
? [Actual] extends [void] ? Result : Hint<"You're returning non void for a void Response, please fix">
|
|
123
|
+
: Result
|
|
124
|
+
|
|
125
|
+
type AnyRequestModule = S.Schema.Any & { success?: S.Schema.Any; failure?: S.Schema.Any }
|
|
126
|
+
|
|
127
|
+
type GetSuccess<T> = T extends { success: S.Schema.Any } ? T["success"] : typeof S.Void
|
|
128
|
+
|
|
129
|
+
type GetSuccessShape<Action extends { success?: S.Schema.Any }, RT extends "d" | "raw"> = RT extends "raw"
|
|
130
|
+
? S.Schema.Encoded<GetSuccess<Action>>
|
|
131
|
+
: S.Schema.Type<GetSuccess<Action>>
|
|
132
|
+
type GetFailure<T extends { failure?: S.Schema.Any }> = T["failure"] extends never ? typeof S.Never : T["failure"]
|
|
133
|
+
|
|
134
|
+
export interface Handler<Action extends AnyRequestModule, RT extends "raw" | "d", A, E, R> {
|
|
135
|
+
new(): {}
|
|
136
|
+
_tag: RT
|
|
137
|
+
stack: string
|
|
138
|
+
handler: (
|
|
139
|
+
req: S.Schema.Type<Action>
|
|
140
|
+
) => Effect<
|
|
141
|
+
A,
|
|
142
|
+
E,
|
|
143
|
+
R
|
|
144
|
+
>
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Separate "raw" vs "d" to verify A (Encoded for "raw" vs Type for "d")
|
|
148
|
+
type AHandler<Action extends AnyRequestModule> =
|
|
149
|
+
| Handler<
|
|
150
|
+
Action,
|
|
151
|
+
"raw",
|
|
152
|
+
S.Schema.Encoded<GetSuccess<Action>>,
|
|
153
|
+
S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
|
|
154
|
+
any
|
|
155
|
+
>
|
|
156
|
+
| Handler<
|
|
157
|
+
Action,
|
|
158
|
+
"d",
|
|
159
|
+
S.Schema.Type<GetSuccess<Action>>,
|
|
160
|
+
S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
|
|
161
|
+
any
|
|
162
|
+
>
|
|
163
|
+
|
|
164
|
+
type Filter<T> = {
|
|
165
|
+
[K in keyof T as T[K] extends S.Schema.All & { success: S.Schema.Any; failure: S.Schema.Any } ? K : never]: T[K]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
interface ExtendedMiddleware<Context, CTXMap extends Record<string, RPCContextMap.Any>>
|
|
169
|
+
extends Middleware<Context, CTXMap>
|
|
170
|
+
{
|
|
171
|
+
// TODO
|
|
172
|
+
makeContext: Effect<
|
|
173
|
+
{ [K in keyof CTXMap as CTXMap[K][1] extends never ? never : CTXMap[K][0]]: CTXMap[K][1] },
|
|
174
|
+
never,
|
|
175
|
+
never
|
|
176
|
+
>
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const RouterSymbol = Symbol()
|
|
180
|
+
export interface RouterS<Rsc> {
|
|
181
|
+
[RouterSymbol]: Rsc
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const makeRouter = <Context, CTXMap extends Record<string, RPCContextMap.Any>>(
|
|
185
|
+
middleware: ExtendedMiddleware<Context, CTXMap>,
|
|
186
|
+
devMode: boolean
|
|
187
|
+
) => {
|
|
188
|
+
const rpc = makeRpc(middleware)
|
|
189
|
+
function matchFor<Rsc extends Record<string, any> & { meta: { moduleName: string } }>(
|
|
190
|
+
rsc: Rsc
|
|
191
|
+
) {
|
|
192
|
+
const meta = (rsc as any).meta as { moduleName: string }
|
|
193
|
+
if (!meta) throw new Error("Resource has no meta specified") // TODO: do something with moduleName+cur etc.
|
|
194
|
+
|
|
195
|
+
type Filtered = Filter<Rsc>
|
|
196
|
+
const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
|
|
197
|
+
if (Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
|
|
198
|
+
acc[cur as keyof Filtered] = rsc[cur]
|
|
199
|
+
}
|
|
200
|
+
return acc
|
|
201
|
+
}, {} as Filtered)
|
|
202
|
+
|
|
203
|
+
const matchWithServices = <Key extends keyof Filtered>(action: Key) => {
|
|
204
|
+
return <
|
|
205
|
+
SVC extends Record<
|
|
206
|
+
string,
|
|
207
|
+
Effect<any, any, any>
|
|
208
|
+
>,
|
|
209
|
+
R2,
|
|
210
|
+
E,
|
|
211
|
+
A
|
|
212
|
+
>(
|
|
213
|
+
services: SVC,
|
|
214
|
+
f: (
|
|
215
|
+
req: S.Schema.Type<Rsc[Key]>,
|
|
216
|
+
ctx: Compute<
|
|
217
|
+
LowerServices<EffectDeps<SVC>> & GetRouteContext<CTXMap, Rsc[Key]["config"]> & {
|
|
218
|
+
Response: Rsc[Key]["success"]
|
|
219
|
+
},
|
|
220
|
+
"flat"
|
|
221
|
+
>
|
|
222
|
+
) => Effect<A, E, R2>
|
|
223
|
+
) =>
|
|
224
|
+
(req: any) =>
|
|
225
|
+
Effect.andThen(
|
|
226
|
+
Effect.all({ svc: allLower(services), ctx: middleware.makeContext }),
|
|
227
|
+
({ ctx, svc }) => f(req, { ...svc, ...ctx, Response: rsc[action].success } as any)
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
type MatchWithServicesNew<RT extends "raw" | "d", Key extends keyof Rsc> = {
|
|
232
|
+
<R2, E, A>(
|
|
233
|
+
f: Effect<A, E, R2>
|
|
234
|
+
): HandleVoid<
|
|
235
|
+
GetSuccessShape<Rsc[Key], RT>,
|
|
236
|
+
A,
|
|
237
|
+
Handler<
|
|
238
|
+
Rsc[Key],
|
|
239
|
+
RT,
|
|
240
|
+
A,
|
|
241
|
+
E,
|
|
242
|
+
Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>
|
|
243
|
+
>
|
|
244
|
+
>
|
|
245
|
+
|
|
246
|
+
<R2, E, A>(
|
|
247
|
+
f: (
|
|
248
|
+
req: S.Schema.Type<Rsc[Key]>,
|
|
249
|
+
ctx: GetRouteContext<CTXMap, Rsc[Key]["config"]> & { Response: Rsc[Key]["success"] }
|
|
250
|
+
) => Effect<A, E, R2>
|
|
251
|
+
): HandleVoid<
|
|
252
|
+
GetSuccessShape<Rsc[Key], RT>,
|
|
253
|
+
A,
|
|
254
|
+
Handler<
|
|
255
|
+
Rsc[Key],
|
|
256
|
+
RT,
|
|
257
|
+
A,
|
|
258
|
+
E,
|
|
259
|
+
Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>
|
|
260
|
+
>
|
|
261
|
+
>
|
|
262
|
+
|
|
263
|
+
<
|
|
264
|
+
SVC extends Record<
|
|
265
|
+
string,
|
|
266
|
+
EffectUnunified<any, any, any>
|
|
267
|
+
>,
|
|
268
|
+
R2,
|
|
269
|
+
E,
|
|
270
|
+
A
|
|
271
|
+
>(
|
|
272
|
+
services: SVC,
|
|
273
|
+
f: (
|
|
274
|
+
req: S.Schema.Type<Rsc[Key]>,
|
|
275
|
+
ctx: Compute<
|
|
276
|
+
LowerServices<EffectDeps<SVC>> & GetRouteContext<CTXMap, Rsc[Key]["config"]> & {
|
|
277
|
+
Response: Rsc[Key]["success"]
|
|
278
|
+
},
|
|
279
|
+
"flat"
|
|
280
|
+
>
|
|
281
|
+
) => Effect<A, E, R2>
|
|
282
|
+
): HandleVoid<
|
|
283
|
+
GetSuccessShape<Rsc[Key], RT>,
|
|
284
|
+
A,
|
|
285
|
+
Handler<
|
|
286
|
+
Rsc[Key],
|
|
287
|
+
RT,
|
|
288
|
+
A,
|
|
289
|
+
E,
|
|
290
|
+
Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>
|
|
291
|
+
>
|
|
292
|
+
>
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
type Keys = keyof Filtered
|
|
296
|
+
|
|
297
|
+
const controllers = <
|
|
298
|
+
THandlers extends {
|
|
299
|
+
// import to keep them separate via | for type checking!!
|
|
300
|
+
[K in Keys]: AHandler<Rsc[K]>
|
|
301
|
+
},
|
|
302
|
+
TLayers extends NonEmptyArray<Layer.Layer.Any>
|
|
303
|
+
>(
|
|
304
|
+
controllers: THandlers,
|
|
305
|
+
layers?: TLayers
|
|
306
|
+
) => {
|
|
307
|
+
const mapped = typedKeysOf(filtered).reduce((acc, cur) => {
|
|
308
|
+
const handler = controllers[cur as keyof typeof controllers]
|
|
309
|
+
const req = rsc[cur]
|
|
310
|
+
|
|
311
|
+
acc[cur] = rpc.effect(
|
|
312
|
+
handler._tag === "raw"
|
|
313
|
+
? class extends (req as any) {
|
|
314
|
+
static success = S.encodedSchema(req.success)
|
|
315
|
+
get [Serializable.symbol]() {
|
|
316
|
+
return this.constructor
|
|
317
|
+
}
|
|
318
|
+
get [Serializable.symbolResult]() {
|
|
319
|
+
return {
|
|
320
|
+
failure: req.failure,
|
|
321
|
+
success: S.encodedSchema(req.success)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} as any
|
|
325
|
+
: req,
|
|
326
|
+
(req) =>
|
|
327
|
+
Effect
|
|
328
|
+
.annotateCurrentSpan(
|
|
329
|
+
"requestInput",
|
|
330
|
+
Object.entries(req).reduce((prev, [key, value]: [string, unknown]) => {
|
|
331
|
+
prev[key] = key === "password"
|
|
332
|
+
? "<redacted>"
|
|
333
|
+
: typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
334
|
+
? typeof value === "string" && value.length > 256
|
|
335
|
+
? (value.substring(0, 253) + "...")
|
|
336
|
+
: value
|
|
337
|
+
: Array.isArray(value)
|
|
338
|
+
? `Array[${value.length}]`
|
|
339
|
+
: value === null || value === undefined
|
|
340
|
+
? `${value}`
|
|
341
|
+
: typeof value === "object" && value
|
|
342
|
+
? `Object[${Object.keys(value).length}]`
|
|
343
|
+
: typeof value
|
|
344
|
+
return prev
|
|
345
|
+
}, {} as Record<string, string | number | boolean>)
|
|
346
|
+
)
|
|
347
|
+
.pipe(
|
|
348
|
+
// can't use andThen due to some being a function and effect
|
|
349
|
+
Effect.zipRight(handler.handler(req as any) as any),
|
|
350
|
+
Effect.tapErrorCause((cause) => Cause.isFailure(cause) ? logRequestError(cause) : Effect.void),
|
|
351
|
+
Effect.tapDefect((cause) =>
|
|
352
|
+
Effect
|
|
353
|
+
.all([
|
|
354
|
+
reportRequestError(cause, {
|
|
355
|
+
action: `${meta.moduleName}.${req._tag}`
|
|
356
|
+
}),
|
|
357
|
+
Rpc.currentHeaders.pipe(Effect.andThen((headers) => {
|
|
358
|
+
return InfraLogger
|
|
359
|
+
.logError("Finished request", cause)
|
|
360
|
+
.pipe(Effect.annotateLogs({
|
|
361
|
+
action: `${meta.moduleName}.${req._tag}`,
|
|
362
|
+
req: pretty(req),
|
|
363
|
+
headers: pretty(headers)
|
|
364
|
+
// resHeaders: pretty(
|
|
365
|
+
// Object
|
|
366
|
+
// .entries(headers)
|
|
367
|
+
// .reduce((prev, [key, value]) => {
|
|
368
|
+
// prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
369
|
+
// return prev
|
|
370
|
+
// }, {} as Record<string, any>)
|
|
371
|
+
// )
|
|
372
|
+
}))
|
|
373
|
+
}))
|
|
374
|
+
])
|
|
375
|
+
),
|
|
376
|
+
devMode ? (_) => _ : Effect.catchAllDefect(() => Effect.die("Internal Server Error")),
|
|
377
|
+
Effect.withSpan("Request." + meta.moduleName + "." + req._tag, {
|
|
378
|
+
captureStackTrace: () => handler.stack
|
|
379
|
+
})
|
|
380
|
+
),
|
|
381
|
+
meta.moduleName
|
|
382
|
+
) // TODO
|
|
383
|
+
return acc
|
|
384
|
+
}, {} as any) as {
|
|
385
|
+
[K in Keys]: Rpc.Rpc<
|
|
386
|
+
Rsc[K],
|
|
387
|
+
_R<ReturnType<THandlers[K]["handler"]>>
|
|
388
|
+
>
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
type RPCRouteR<T extends Rpc.Rpc<any, any>> = [T] extends [
|
|
392
|
+
Rpc.Rpc<any, infer R>
|
|
393
|
+
] ? R
|
|
394
|
+
: never
|
|
395
|
+
|
|
396
|
+
type RPCRouteReq<T extends Rpc.Rpc<any, any>> = [T] extends [
|
|
397
|
+
Rpc.Rpc<infer Req, any>
|
|
398
|
+
] ? Req
|
|
399
|
+
: never
|
|
400
|
+
|
|
401
|
+
const rpcRouter = RpcRouter.make(...Object.values(mapped) as any) as RpcRouter.RpcRouter<
|
|
402
|
+
RPCRouteReq<typeof mapped[keyof typeof mapped]>,
|
|
403
|
+
RPCRouteR<typeof mapped[keyof typeof mapped]>
|
|
404
|
+
>
|
|
405
|
+
|
|
406
|
+
type Router = RouterS<Rsc>
|
|
407
|
+
const r: HttpRouter.HttpRouter.TagClass<
|
|
408
|
+
Router,
|
|
409
|
+
string,
|
|
410
|
+
never,
|
|
411
|
+
never
|
|
412
|
+
> = (class Router extends HttpRouter.Tag(meta.moduleName + "Router")<Router>() {}) as any
|
|
413
|
+
|
|
414
|
+
const layer = r.use((router) =>
|
|
415
|
+
Effect.gen(function*() {
|
|
416
|
+
const httpApp = toHttpApp(rpcRouter, {
|
|
417
|
+
spanPrefix: rsc
|
|
418
|
+
.meta
|
|
419
|
+
.moduleName + "."
|
|
420
|
+
})
|
|
421
|
+
const services = (yield* Effect.context<never>()).pipe(
|
|
422
|
+
Context.omit(Scope.Scope as never),
|
|
423
|
+
Context.omit(Tracer.ParentSpan as never)
|
|
424
|
+
)
|
|
425
|
+
yield* router
|
|
426
|
+
.all(
|
|
427
|
+
"/",
|
|
428
|
+
(httpApp
|
|
429
|
+
.pipe(HttpMiddleware.make(Effect.provide(services)))) as any,
|
|
430
|
+
// TODO: not queries.
|
|
431
|
+
{ uninterruptible: true }
|
|
432
|
+
)
|
|
433
|
+
})
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
const routes = layer.pipe(
|
|
437
|
+
Layer.provideMerge(r.Live),
|
|
438
|
+
layers ? Layer.provide(layers) : (_) => _
|
|
439
|
+
) as Layer.Layer<
|
|
440
|
+
Router,
|
|
441
|
+
{ [k in keyof TLayers]: Layer.Layer.Error<TLayers[k]> }[number],
|
|
442
|
+
| { [k in keyof TLayers]: Layer.Layer.Context<TLayers[k]> }[number]
|
|
443
|
+
| Exclude<
|
|
444
|
+
RPCRouteR<
|
|
445
|
+
{ [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<THandlers[K]["handler"]>>> }[keyof Filter<Rsc>]
|
|
446
|
+
>,
|
|
447
|
+
{ [k in keyof TLayers]: Layer.Layer.Success<TLayers[k]> }[number]
|
|
448
|
+
>
|
|
449
|
+
>
|
|
450
|
+
|
|
451
|
+
// Effect.Effect<HttpRouter.HttpRouter<unknown, HttpRouter.HttpRouter.DefaultServices>, never, UserRouter>
|
|
452
|
+
|
|
453
|
+
return {
|
|
454
|
+
moduleName: meta.moduleName,
|
|
455
|
+
Router: r,
|
|
456
|
+
routes
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const r = {
|
|
461
|
+
controllers,
|
|
462
|
+
...typedKeysOf(filtered).reduce(
|
|
463
|
+
(prev, cur) => {
|
|
464
|
+
;(prev as any)[cur] = (svcOrFnOrEffect: any, fnOrNone: any) => {
|
|
465
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n")
|
|
466
|
+
return Effect.isEffect(svcOrFnOrEffect)
|
|
467
|
+
? class {
|
|
468
|
+
static stack = stack
|
|
469
|
+
static _tag = "d"
|
|
470
|
+
static handler = () => svcOrFnOrEffect
|
|
471
|
+
}
|
|
472
|
+
: typeof svcOrFnOrEffect === "function"
|
|
473
|
+
? class {
|
|
474
|
+
static stack = stack
|
|
475
|
+
static _tag = "d"
|
|
476
|
+
static handler = (req: any) =>
|
|
477
|
+
Effect.andThen(
|
|
478
|
+
Effect.all({ ctx: middleware.makeContext }),
|
|
479
|
+
({ ctx }) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].success })
|
|
480
|
+
)
|
|
481
|
+
}
|
|
482
|
+
: class {
|
|
483
|
+
static stack = stack
|
|
484
|
+
static _tag = "d"
|
|
485
|
+
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
|
|
486
|
+
}
|
|
487
|
+
} // "Raw" variations are for when you don't want to decode just to encode it again on the response
|
|
488
|
+
// e.g for direct projection from DB
|
|
489
|
+
// but more importantly, to skip Effectful decoders, like to resolve relationships from the database or remote client.
|
|
490
|
+
;(prev as any)[(cur as any) + "Raw"] = (svcOrFnOrEffect: any, fnOrNone: any) => {
|
|
491
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n")
|
|
492
|
+
return Effect.isEffect(svcOrFnOrEffect)
|
|
493
|
+
? class {
|
|
494
|
+
static stack = stack
|
|
495
|
+
static _tag = "raw"
|
|
496
|
+
static handler = () => svcOrFnOrEffect
|
|
497
|
+
}
|
|
498
|
+
: typeof svcOrFnOrEffect === "function"
|
|
499
|
+
? class {
|
|
500
|
+
static stack = stack
|
|
501
|
+
static _tag = "raw"
|
|
502
|
+
static handler = (req: any, ctx: any) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].success })
|
|
503
|
+
}
|
|
504
|
+
: class {
|
|
505
|
+
static stack = stack
|
|
506
|
+
static _tag = "raw"
|
|
507
|
+
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return prev
|
|
511
|
+
},
|
|
512
|
+
{} as
|
|
513
|
+
& {
|
|
514
|
+
// use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
|
|
515
|
+
/**
|
|
516
|
+
* Requires the Type shape
|
|
517
|
+
*/
|
|
518
|
+
[Key in keyof Filtered]: MatchWithServicesNew<"d", Key>
|
|
519
|
+
}
|
|
520
|
+
& {
|
|
521
|
+
// use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
|
|
522
|
+
/**
|
|
523
|
+
* Requires the Encoded shape (e.g directly undecoded from DB, so that we don't do multiple Decode/Encode)
|
|
524
|
+
*/
|
|
525
|
+
[Key in keyof Filtered as Key extends string ? `${Key}Raw` : never]: MatchWithServicesNew<"raw", Key>
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
}
|
|
529
|
+
return r
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
type RequestHandlersTest = {
|
|
533
|
+
[key: string]: {
|
|
534
|
+
Router: { router: Effect<HttpRouter.HttpRouter<any, any>, any, any> }
|
|
535
|
+
routes: Layer.Layer<any, any, any>
|
|
536
|
+
moduleName: string
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function matchAll<T extends RequestHandlersTest>(handlers: T) {
|
|
540
|
+
const routers = typedValuesOf(handlers)
|
|
541
|
+
|
|
542
|
+
const r = HttpRouter
|
|
543
|
+
.Default
|
|
544
|
+
.use((router) =>
|
|
545
|
+
Effect.gen(function*() {
|
|
546
|
+
for (const route of routers) {
|
|
547
|
+
yield* router.mount(("/rpc/" + route.moduleName) as any, yield* route.Router.router)
|
|
548
|
+
}
|
|
549
|
+
})
|
|
550
|
+
)
|
|
551
|
+
.pipe(Layer.provide(routers.map((r) => r.routes).flat() as unknown as NonEmptyArray<Layer.Layer.Any>))
|
|
552
|
+
|
|
553
|
+
return r as Layer.Layer<
|
|
554
|
+
never,
|
|
555
|
+
Layer.Layer.Error<typeof handlers[keyof typeof handlers]["routes"]>,
|
|
556
|
+
Layer.Layer.Context<typeof handlers[keyof typeof handlers]["routes"]>
|
|
557
|
+
>
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return { matchAll, matchFor }
|
|
561
|
+
}
|