@effect-app/infra 2.26.0 → 2.27.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 +18 -0
- package/_cjs/api/routing.cjs +15 -6
- package/_cjs/api/routing.cjs.map +1 -1
- package/_cjs/api/{routing7.cjs → routing.legacy2.cjs} +7 -16
- package/_cjs/api/routing.legacy2.cjs.map +1 -0
- package/_cjs/api/{routing6.cjs → routing.legacy3.cjs} +1 -1
- package/_cjs/api/routing.legacy3.cjs.map +1 -0
- package/dist/api/routing.d.ts +309 -22
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +22 -8
- package/dist/api/routing.legacy2.d.ts +192 -0
- package/dist/api/routing.legacy2.d.ts.map +1 -0
- package/dist/api/routing.legacy2.js +226 -0
- package/dist/api/{routing6.d.ts → routing.legacy3.d.ts} +1 -1
- package/dist/api/routing.legacy3.d.ts.map +1 -0
- package/dist/api/routing.legacy3.js +233 -0
- package/package.json +29 -29
- package/src/api/{routing7.ts → routing.legacy2.ts} +10 -121
- package/src/api/routing.ts +125 -10
- package/test/{controller7.test.ts → controller.legacy2.test.ts} +12 -59
- package/test/{controller6.test.ts → controller.legacy3.test.ts} +2 -2
- package/test/controller.test.ts +57 -10
- package/test/dist/controller.legacy2.test.d.ts.map +1 -0
- package/test/dist/controller.legacy3.test.d.ts.map +1 -0
- package/test/dist/controller.test copy.d.ts +169 -0
- package/test/dist/controller.test copy.d.ts.map +1 -0
- package/test/dist/controller.test copy.js +46 -23
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/controller6.test.d.ts.map +1 -1
- package/test/dist/controller7.test.d.ts.map +1 -1
- package/_cjs/api/routing6.cjs.map +0 -1
- package/_cjs/api/routing7.cjs.map +0 -1
- package/dist/api/routing6.d.ts.map +0 -1
- package/dist/api/routing6.js +0 -233
- package/dist/api/routing7.d.ts +0 -375
- package/dist/api/routing7.d.ts.map +0 -1
- package/dist/api/routing7.js +0 -240
- package/test/dist/controller5.test.d.ts.map +0 -1
- package/vitest.config.ts.timestamp-1711656440838-19c636fe320df.mjs +0 -0
- package/vitest.config.ts.timestamp-1711724061890-6ecedb0a07fdd.mjs +0 -0
- package/vitest.config.ts.timestamp-1711743489537-da8d9e5f66c9f.mjs +0 -0
- package/vitest.config.ts.timestamp-1711744615239-dcf257a844e01.mjs +0 -37
- /package/src/api/{routing6.ts → routing.legacy3.ts} +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Rpc, RpcRouter } from "@effect/rpc";
|
|
2
|
+
import { Array, Cause, Chunk, Context, Effect, FiberRef, flow, Layer, Predicate, S, Schema, Stream } from "effect-app";
|
|
3
|
+
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http";
|
|
4
|
+
import { pretty, typedKeysOf, typedValuesOf } from "effect-app/utils";
|
|
5
|
+
import { logError, reportError } from "../errorReporter.js";
|
|
6
|
+
import { InfraLogger } from "../logger.js";
|
|
7
|
+
import { makeRpc } from "./routing/DynamicMiddleware.js";
|
|
8
|
+
const logRequestError = logError("Request");
|
|
9
|
+
const reportRequestError = reportError("Request");
|
|
10
|
+
/**
|
|
11
|
+
* Plain jane JSON version
|
|
12
|
+
* @deprecated use HttpRpcRouterNoStream.toHttpApp once support options
|
|
13
|
+
*/
|
|
14
|
+
export const toHttpApp = (self, options) => {
|
|
15
|
+
const handler = RpcRouter.toHandler(self, options);
|
|
16
|
+
return Effect.withFiberRuntime((fiber) => {
|
|
17
|
+
const context = fiber.getFiberRef(FiberRef.currentContext);
|
|
18
|
+
const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest);
|
|
19
|
+
return Effect.flatMap(request.json, (_) => handler(_).pipe(Stream.provideContext(context), Stream.runCollect, Effect.map((_) => Chunk.toReadonlyArray(_)), Effect.andThen((_) => {
|
|
20
|
+
let status = 200;
|
|
21
|
+
for (const r of _.flat()) {
|
|
22
|
+
if (typeof r === "number")
|
|
23
|
+
continue;
|
|
24
|
+
const results = Array.isArray(r) ? r : [r];
|
|
25
|
+
if (results.some((_) => _._tag === "Failure" && _.cause._tag === "Die")) {
|
|
26
|
+
status = 500;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
if (results.some((_) => _._tag === "Failure" && _.cause._tag === "Fail")) {
|
|
30
|
+
status = 422; // 418
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return HttpServerResponse.json(_, { status });
|
|
35
|
+
}), Effect.orDie, Effect.tapDefect(reportError("RPCHttpApp"))));
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export const RouterSymbol = Symbol();
|
|
39
|
+
// export interface RouteMatcher<
|
|
40
|
+
// Filtered extends Record<string, any>,
|
|
41
|
+
// CTXMap extends Record<string, any>,
|
|
42
|
+
// Rsc extends Filtered
|
|
43
|
+
// > extends RouteMatcherInt<Filtered, CTXMap, Rsc> {}
|
|
44
|
+
export const makeMiddleware = (content) => content;
|
|
45
|
+
export const makeRouter = (middleware, devMode) => {
|
|
46
|
+
function matchFor(rsc) {
|
|
47
|
+
const meta = rsc.meta;
|
|
48
|
+
const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
|
|
49
|
+
if (Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
|
|
50
|
+
acc[cur] = rsc[cur];
|
|
51
|
+
}
|
|
52
|
+
return acc;
|
|
53
|
+
}, {});
|
|
54
|
+
const items = typedKeysOf(filtered).reduce((prev, cur) => {
|
|
55
|
+
;
|
|
56
|
+
prev[cur] = Object.assign((fnOrEffect) => {
|
|
57
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n");
|
|
58
|
+
return Effect.isEffect(fnOrEffect)
|
|
59
|
+
? class {
|
|
60
|
+
static request = rsc[cur];
|
|
61
|
+
static stack = stack;
|
|
62
|
+
static _tag = "d";
|
|
63
|
+
static handler = () => fnOrEffect;
|
|
64
|
+
}
|
|
65
|
+
: class {
|
|
66
|
+
static request = rsc[cur];
|
|
67
|
+
static stack = stack;
|
|
68
|
+
static _tag = "d";
|
|
69
|
+
static handler = fnOrEffect;
|
|
70
|
+
};
|
|
71
|
+
}, {
|
|
72
|
+
success: rsc[cur].success,
|
|
73
|
+
successRaw: S.encodedSchema(rsc[cur].success),
|
|
74
|
+
failure: rsc[cur].failure,
|
|
75
|
+
raw: // "Raw" variations are for when you don't want to decode just to encode it again on the response
|
|
76
|
+
// e.g for direct projection from DB
|
|
77
|
+
// but more importantly, to skip Effectful decoders, like to resolve relationships from the database or remote client.
|
|
78
|
+
(fnOrEffect) => {
|
|
79
|
+
const stack = new Error().stack?.split("\n").slice(2).join("\n");
|
|
80
|
+
return Effect.isEffect(fnOrEffect)
|
|
81
|
+
? class {
|
|
82
|
+
static request = rsc[cur];
|
|
83
|
+
static stack = stack;
|
|
84
|
+
static _tag = "raw";
|
|
85
|
+
static handler = () => fnOrEffect;
|
|
86
|
+
}
|
|
87
|
+
: class {
|
|
88
|
+
static request = rsc[cur];
|
|
89
|
+
static stack = stack;
|
|
90
|
+
static _tag = "raw";
|
|
91
|
+
static handler = (req, ctx) => fnOrEffect(req, { ...ctx, Response: rsc[cur].success });
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return prev;
|
|
96
|
+
}, {});
|
|
97
|
+
const f = (layers, make) => {
|
|
98
|
+
const r = (class Router extends HttpRouter.Tag(`${meta.moduleName}Router`)() {
|
|
99
|
+
});
|
|
100
|
+
const layer = r.use((router) => Effect.gen(function* () {
|
|
101
|
+
const controllers = yield* make;
|
|
102
|
+
const rpc = yield* makeRpc(middleware);
|
|
103
|
+
// return make.pipe(Effect.map((c) => controllers(c, layers)))
|
|
104
|
+
const mapped = typedKeysOf(filtered).reduce((acc, cur) => {
|
|
105
|
+
const handler = controllers[cur];
|
|
106
|
+
const req = rsc[cur];
|
|
107
|
+
acc[cur] = rpc.effect(handler._tag === "raw"
|
|
108
|
+
? class extends req {
|
|
109
|
+
static success = S.encodedSchema(req.success);
|
|
110
|
+
get [Schema.symbolSerializable]() {
|
|
111
|
+
return this.constructor;
|
|
112
|
+
}
|
|
113
|
+
get [Schema.symbolWithResult]() {
|
|
114
|
+
return {
|
|
115
|
+
failure: req.failure,
|
|
116
|
+
success: S.encodedSchema(req.success)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
: req, (req) =>
|
|
121
|
+
// TODO: render more data... similar to console?
|
|
122
|
+
Effect
|
|
123
|
+
.annotateCurrentSpan("requestInput", Object.entries(req).reduce((prev, [key, value]) => {
|
|
124
|
+
prev[key] = key === "password"
|
|
125
|
+
? "<redacted>"
|
|
126
|
+
: typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
127
|
+
? typeof value === "string" && value.length > 256
|
|
128
|
+
? (value.substring(0, 253) + "...")
|
|
129
|
+
: value
|
|
130
|
+
: Array.isArray(value)
|
|
131
|
+
? `Array[${value.length}]`
|
|
132
|
+
: value === null || value === undefined
|
|
133
|
+
? `${value}`
|
|
134
|
+
: typeof value === "object" && value
|
|
135
|
+
? `Object[${Object.keys(value).length}]`
|
|
136
|
+
: typeof value;
|
|
137
|
+
return prev;
|
|
138
|
+
}, {}))
|
|
139
|
+
.pipe(
|
|
140
|
+
// can't use andThen due to some being a function and effect
|
|
141
|
+
Effect.zipRight(handler.handler(req)), Effect.tapErrorCause((cause) => Cause.isFailure(cause) ? logRequestError(cause) : Effect.void), Effect.tapDefect((cause) => Effect
|
|
142
|
+
.all([
|
|
143
|
+
reportRequestError(cause, {
|
|
144
|
+
action: `${meta.moduleName}.${req._tag}`
|
|
145
|
+
}),
|
|
146
|
+
Rpc.currentHeaders.pipe(Effect.andThen((headers) => {
|
|
147
|
+
return InfraLogger
|
|
148
|
+
.logError("Finished request", cause)
|
|
149
|
+
.pipe(Effect.annotateLogs({
|
|
150
|
+
action: `${meta.moduleName}.${req._tag}`,
|
|
151
|
+
req: pretty(req),
|
|
152
|
+
headers: pretty(headers)
|
|
153
|
+
// resHeaders: pretty(
|
|
154
|
+
// Object
|
|
155
|
+
// .entries(headers)
|
|
156
|
+
// .reduce((prev, [key, value]) => {
|
|
157
|
+
// prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
158
|
+
// return prev
|
|
159
|
+
// }, {} as Record<string, any>)
|
|
160
|
+
// )
|
|
161
|
+
}));
|
|
162
|
+
}))
|
|
163
|
+
])), devMode ? (_) => _ : Effect.catchAllDefect(() => Effect.die("Internal Server Error")), Effect.withSpan("Request." + meta.moduleName + "." + req._tag, {
|
|
164
|
+
captureStackTrace: () => handler.stack
|
|
165
|
+
})), meta.moduleName); // TODO
|
|
166
|
+
return acc;
|
|
167
|
+
}, {});
|
|
168
|
+
const rpcRouter = RpcRouter.make(...Object.values(mapped));
|
|
169
|
+
const httpApp = toHttpApp(rpcRouter, {
|
|
170
|
+
spanPrefix: rsc
|
|
171
|
+
.meta
|
|
172
|
+
.moduleName + "."
|
|
173
|
+
});
|
|
174
|
+
yield* router
|
|
175
|
+
.all("/", httpApp,
|
|
176
|
+
// TODO: not queries.
|
|
177
|
+
{ uninterruptible: true });
|
|
178
|
+
}));
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
180
|
+
const routes = layer.pipe(Layer.provideMerge(r.Live), layers && Array.isNonEmptyReadonlyArray(layers) ? Layer.provide(layers) : (_) => _,
|
|
181
|
+
// TODO: only provide to the middleware?
|
|
182
|
+
middleware.dependencies ? Layer.provide(middleware.dependencies) : (_) => _);
|
|
183
|
+
// Effect.Effect<HttpRouter.HttpRouter<unknown, HttpRouter.HttpRouter.DefaultServices>, never, UserRouter>
|
|
184
|
+
return {
|
|
185
|
+
moduleName: meta.moduleName,
|
|
186
|
+
Router: r,
|
|
187
|
+
routes
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
const effect = ((m) => f(m.dependencies, m.effect));
|
|
191
|
+
const total = Object.keys(filtered).length;
|
|
192
|
+
// TODO
|
|
193
|
+
const accum = {};
|
|
194
|
+
const router2 = typedKeysOf(filtered).reduce((prev, cur) => {
|
|
195
|
+
prev[cur] = Object.assign((it) => {
|
|
196
|
+
accum[cur] = items[cur](it);
|
|
197
|
+
if (Object.keys(accum).length === total)
|
|
198
|
+
return accum;
|
|
199
|
+
return router2;
|
|
200
|
+
}, {
|
|
201
|
+
raw: (it) => {
|
|
202
|
+
accum[cur] = items[cur](it);
|
|
203
|
+
if (Object.keys(accum).length === total)
|
|
204
|
+
return accum;
|
|
205
|
+
return router2;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
return prev;
|
|
209
|
+
}, {});
|
|
210
|
+
return Object.assign(effect, router2);
|
|
211
|
+
}
|
|
212
|
+
function matchAll(handlers, requestLayer) {
|
|
213
|
+
const routers = typedValuesOf(handlers);
|
|
214
|
+
const rootRouter = class extends HttpRouter.Tag("RootRouter")() {
|
|
215
|
+
};
|
|
216
|
+
const r = rootRouter
|
|
217
|
+
.use((router) => Effect.gen(function* () {
|
|
218
|
+
for (const route of routers) {
|
|
219
|
+
yield* router.mount(("/rpc/" + route.moduleName), yield* route
|
|
220
|
+
.Router
|
|
221
|
+
.router
|
|
222
|
+
.pipe(Effect.map(HttpRouter.use(flow(Effect.provide(requestLayer))))));
|
|
223
|
+
}
|
|
224
|
+
}))
|
|
225
|
+
.pipe(Layer.provide(routers.map((r) => r.routes).flat()));
|
|
226
|
+
return {
|
|
227
|
+
layer: r,
|
|
228
|
+
Router: rootRouter
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return { matchAll, matchFor };
|
|
232
|
+
};
|
|
233
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGluZy5sZWdhY3kzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9yb3V0aW5nLmxlZ2FjeTMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBU0EsT0FBTyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFFNUMsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBR3RILE9BQU8sRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUNuRixPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUVyRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQzNELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFFMUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGdDQUFnQyxDQUFBO0FBRXhELE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQUMzQyxNQUFNLGtCQUFrQixHQUFHLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQWVqRDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsQ0FBMEMsSUFBTyxFQUFFLE9BRTNFLEVBR0MsRUFBRTtJQUNGLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQ2xELE9BQU8sTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDdkMsTUFBTSxPQUFPLEdB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.27.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"proper-lockfile": "^4.1.2",
|
|
14
14
|
"pure-rand": "6.1.0",
|
|
15
15
|
"query-string": "^9.1.1",
|
|
16
|
-
"effect-app": "2.13.
|
|
16
|
+
"effect-app": "2.13.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@azure/cosmos": "^4.1.1",
|
|
@@ -38,17 +38,17 @@
|
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@azure/cosmos": "^4.1.1",
|
|
40
40
|
"@azure/service-bus": "^7.9.5",
|
|
41
|
-
"@effect/experimental": "^0.32.
|
|
42
|
-
"@effect/platform": "^0.69.
|
|
43
|
-
"@effect/rpc-http": "^0.42.
|
|
44
|
-
"@effect/rpc": "^0.44.
|
|
45
|
-
"@effect/sql": "^0.20.
|
|
46
|
-
"@effect/vitest": "^0.13.
|
|
41
|
+
"@effect/experimental": "^0.32.5",
|
|
42
|
+
"@effect/platform": "^0.69.21",
|
|
43
|
+
"@effect/rpc-http": "^0.42.21",
|
|
44
|
+
"@effect/rpc": "^0.44.21",
|
|
45
|
+
"@effect/sql": "^0.20.5",
|
|
46
|
+
"@effect/vitest": "^0.13.14",
|
|
47
47
|
"@sendgrid/helpers": "^8.0.0",
|
|
48
48
|
"@sendgrid/mail": "^8.1.4",
|
|
49
49
|
"redis": "^3.1.2",
|
|
50
50
|
"redlock": "^4.2.0",
|
|
51
|
-
"effect": "^3.10.
|
|
51
|
+
"effect": "^3.10.14",
|
|
52
52
|
"express": "^4.21.1"
|
|
53
53
|
},
|
|
54
54
|
"typesVersions": {
|
|
@@ -649,6 +649,26 @@
|
|
|
649
649
|
"default": "./_cjs/api/routing.legacy.cjs"
|
|
650
650
|
}
|
|
651
651
|
},
|
|
652
|
+
"./api/routing.legacy2": {
|
|
653
|
+
"import": {
|
|
654
|
+
"types": "./dist/api/routing.legacy2.d.ts",
|
|
655
|
+
"default": "./dist/api/routing.legacy2.js"
|
|
656
|
+
},
|
|
657
|
+
"require": {
|
|
658
|
+
"types": "./dist/api/routing.legacy2.d.ts",
|
|
659
|
+
"default": "./_cjs/api/routing.legacy2.cjs"
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
"./api/routing.legacy3": {
|
|
663
|
+
"import": {
|
|
664
|
+
"types": "./dist/api/routing.legacy3.d.ts",
|
|
665
|
+
"default": "./dist/api/routing.legacy3.js"
|
|
666
|
+
},
|
|
667
|
+
"require": {
|
|
668
|
+
"types": "./dist/api/routing.legacy3.d.ts",
|
|
669
|
+
"default": "./_cjs/api/routing.legacy3.cjs"
|
|
670
|
+
}
|
|
671
|
+
},
|
|
652
672
|
"./api/routing/DynamicMiddleware": {
|
|
653
673
|
"import": {
|
|
654
674
|
"types": "./dist/api/routing/DynamicMiddleware.d.ts",
|
|
@@ -679,26 +699,6 @@
|
|
|
679
699
|
"default": "./_cjs/api/routing/utils.cjs"
|
|
680
700
|
}
|
|
681
701
|
},
|
|
682
|
-
"./api/routing6": {
|
|
683
|
-
"import": {
|
|
684
|
-
"types": "./dist/api/routing6.d.ts",
|
|
685
|
-
"default": "./dist/api/routing6.js"
|
|
686
|
-
},
|
|
687
|
-
"require": {
|
|
688
|
-
"types": "./dist/api/routing6.d.ts",
|
|
689
|
-
"default": "./_cjs/api/routing6.cjs"
|
|
690
|
-
}
|
|
691
|
-
},
|
|
692
|
-
"./api/routing7": {
|
|
693
|
-
"import": {
|
|
694
|
-
"types": "./dist/api/routing7.d.ts",
|
|
695
|
-
"default": "./dist/api/routing7.js"
|
|
696
|
-
},
|
|
697
|
-
"require": {
|
|
698
|
-
"types": "./dist/api/routing7.d.ts",
|
|
699
|
-
"default": "./_cjs/api/routing7.cjs"
|
|
700
|
-
}
|
|
701
|
-
},
|
|
702
702
|
"./api/setupRequest": {
|
|
703
703
|
"import": {
|
|
704
704
|
"types": "./dist/api/setupRequest.d.ts",
|
|
@@ -2,24 +2,14 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
|
+
/*
|
|
6
|
+
TODO: Effect.retry(r2, optimisticConcurrencySchedule) / was for PATCH only
|
|
7
|
+
TODO: uninteruptible commands! was for All except GET.
|
|
8
|
+
*/
|
|
5
9
|
import type * as HttpApp from "@effect/platform/HttpApp"
|
|
6
10
|
import { Rpc, RpcRouter } from "@effect/rpc"
|
|
7
11
|
import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect-app"
|
|
8
|
-
import {
|
|
9
|
-
Array,
|
|
10
|
-
Cause,
|
|
11
|
-
Chunk,
|
|
12
|
-
Context,
|
|
13
|
-
Effect,
|
|
14
|
-
FiberRef,
|
|
15
|
-
flow,
|
|
16
|
-
Layer,
|
|
17
|
-
Predicate,
|
|
18
|
-
S,
|
|
19
|
-
Schedule,
|
|
20
|
-
Schema,
|
|
21
|
-
Stream
|
|
22
|
-
} from "effect-app"
|
|
12
|
+
import { Array, Cause, Chunk, Context, Effect, FiberRef, flow, Layer, Predicate, S, Schema, Stream } from "effect-app"
|
|
23
13
|
import type { GetEffectContext, RPCContextMap } from "effect-app/client/req"
|
|
24
14
|
import type { HttpServerError } from "effect-app/http"
|
|
25
15
|
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
@@ -29,10 +19,6 @@ import { logError, reportError } from "../errorReporter.js"
|
|
|
29
19
|
import { InfraLogger } from "../logger.js"
|
|
30
20
|
import type { Middleware } from "./routing/DynamicMiddleware.js"
|
|
31
21
|
import { makeRpc } from "./routing/DynamicMiddleware.js"
|
|
32
|
-
import { determineMethod } from "./routing/utils.js"
|
|
33
|
-
|
|
34
|
-
const optimisticConcurrencySchedule = Schedule.once
|
|
35
|
-
&& Schedule.recurWhile<{ _tag: string }>((a) => a._tag === "OptimisticConcurrencyException")
|
|
36
22
|
|
|
37
23
|
const logRequestError = logError("Request")
|
|
38
24
|
const reportRequestError = reportError("Request")
|
|
@@ -102,12 +88,7 @@ type HandleVoid<Expected, Actual, Result> = [Expected] extends [void]
|
|
|
102
88
|
? [Actual] extends [void] ? Result : Hint<"You're returning non void for a void Response, please fix">
|
|
103
89
|
: Result
|
|
104
90
|
|
|
105
|
-
|
|
106
|
-
_tag: string
|
|
107
|
-
config: any
|
|
108
|
-
success: S.Schema.Any
|
|
109
|
-
failure: S.Schema.Any
|
|
110
|
-
}
|
|
91
|
+
type AnyRequestModule = S.Schema.Any & { _tag: string; success?: S.Schema.Any; failure?: S.Schema.Any }
|
|
111
92
|
export interface AddAction<Actions extends AnyRequestModule, Accum extends Record<string, any> = {}> {
|
|
112
93
|
accum: Accum
|
|
113
94
|
add<A extends Handler<Actions, any, any>>(
|
|
@@ -383,13 +364,6 @@ export const makeRouter = <
|
|
|
383
364
|
const handler = controllers[cur as keyof typeof controllers]
|
|
384
365
|
const req = rsc[cur]
|
|
385
366
|
|
|
386
|
-
const method = determineMethod(String(cur), req)
|
|
387
|
-
const isCommand = method._tag === "command"
|
|
388
|
-
|
|
389
|
-
const handle = isCommand
|
|
390
|
-
? (req: any) => Effect.retry(handler.handler(req) as any, optimisticConcurrencySchedule)
|
|
391
|
-
: (req: any) => Effect.interruptible(handler.handler(req) as any)
|
|
392
|
-
|
|
393
367
|
acc[cur] = rpc.effect(
|
|
394
368
|
handler._tag === "raw"
|
|
395
369
|
? class extends (req as any) {
|
|
@@ -429,7 +403,7 @@ export const makeRouter = <
|
|
|
429
403
|
)
|
|
430
404
|
.pipe(
|
|
431
405
|
// can't use andThen due to some being a function and effect
|
|
432
|
-
Effect.zipRight(
|
|
406
|
+
Effect.zipRight(handler.handler(req as any) as any),
|
|
433
407
|
Effect.tapErrorCause((cause) => Cause.isFailure(cause) ? logRequestError(cause) : Effect.void),
|
|
434
408
|
Effect.tapDefect((cause) =>
|
|
435
409
|
Effect
|
|
@@ -484,6 +458,7 @@ export const makeRouter = <
|
|
|
484
458
|
.all(
|
|
485
459
|
"/",
|
|
486
460
|
httpApp as any,
|
|
461
|
+
// TODO: not queries.
|
|
487
462
|
{ uninterruptible: true }
|
|
488
463
|
)
|
|
489
464
|
})
|
|
@@ -747,84 +722,7 @@ export const makeRouter = <
|
|
|
747
722
|
return this as any
|
|
748
723
|
}
|
|
749
724
|
}
|
|
750
|
-
|
|
751
|
-
type HndlrWithInput<Action extends AnyRequestModule, Mode extends "d" | "raw"> = (
|
|
752
|
-
req: S.Schema.Type<Action>
|
|
753
|
-
) => Effect<
|
|
754
|
-
GetSuccessShape<Action, Mode>,
|
|
755
|
-
S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
|
|
756
|
-
any
|
|
757
|
-
>
|
|
758
|
-
|
|
759
|
-
type Hndlr<Action extends AnyRequestModule, Mode extends "d" | "raw"> = Effect<
|
|
760
|
-
GetSuccessShape<Action, Mode>,
|
|
761
|
-
S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
|
|
762
|
-
any
|
|
763
|
-
>
|
|
764
|
-
|
|
765
|
-
type Hndlrs<Action extends AnyRequestModule, Mode extends "d" | "raw"> =
|
|
766
|
-
| HndlrWithInput<Action, Mode>
|
|
767
|
-
| Hndlr<Action, Mode>
|
|
768
|
-
|
|
769
|
-
type DHndlrs<Action extends AnyRequestModule> = Hndlrs<Action, "d">
|
|
770
|
-
|
|
771
|
-
type RawHndlrs<Action extends AnyRequestModule> =
|
|
772
|
-
| { raw: HndlrWithInput<Action, "raw"> }
|
|
773
|
-
| { raw: Hndlr<Action, "raw"> }
|
|
774
|
-
|
|
775
|
-
type CheckAction<Action extends AnyRequestModule, Impl, Mode extends "raw" | "d", Default> = Impl extends
|
|
776
|
-
(...args: any[]) => any ? [Effect.Success<ReturnType<Impl>>] extends [void] ? HndlrWithInput<Action, Mode>
|
|
777
|
-
: Hint<"You're returning non void for a void Response, please fix">
|
|
778
|
-
// this is insane this works...
|
|
779
|
-
: Impl extends Effect.Effect<any, any, any> ? [Effect.Success<Impl>] extends [void] ? Hndlr<Action, Mode>
|
|
780
|
-
: Effect<
|
|
781
|
-
Hint<"You're returning non void for a void Response, please fix">,
|
|
782
|
-
S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
|
|
783
|
-
any
|
|
784
|
-
>
|
|
785
|
-
: Default
|
|
786
|
-
|
|
787
|
-
const router3: <
|
|
788
|
-
const Impl extends {
|
|
789
|
-
[K in keyof Filter<Rsc>]:
|
|
790
|
-
// incase we expect a void return, we want to make sure the return really is only void
|
|
791
|
-
// the problem is that anything is assignable to void. This helps catch accidental return of e.g Errors instead of yielding them
|
|
792
|
-
Impl[K] extends { raw: any } ? [GetSuccessShape<Rsc[K], "raw">] extends [void]
|
|
793
|
-
// this is insane this works...
|
|
794
|
-
? { raw: CheckAction<Rsc[K], Impl[K]["raw"], "raw", Hndlrs<Rsc[K], "raw">> }
|
|
795
|
-
: RawHndlrs<Rsc[K]>
|
|
796
|
-
: [GetSuccessShape<Rsc[K], "d">] extends [void]
|
|
797
|
-
// this is insane this works...
|
|
798
|
-
? CheckAction<Rsc[K], Impl[K], "d", DHndlrs<Rsc[K]>>
|
|
799
|
-
: DHndlrs<Rsc[K]>
|
|
800
|
-
}
|
|
801
|
-
>(
|
|
802
|
-
impl: Impl
|
|
803
|
-
) => {
|
|
804
|
-
[K in keyof Impl & keyof Filter<Rsc>]: Handler<
|
|
805
|
-
Filter<Rsc>[K],
|
|
806
|
-
Impl[K] extends { raw: any } ? "raw" : "d",
|
|
807
|
-
Exclude<
|
|
808
|
-
| Context
|
|
809
|
-
| Exclude<
|
|
810
|
-
Impl[K] extends { raw: any } ? Impl[K]["raw"] extends (...args: any[]) => Effect<any, any, infer R> ? R
|
|
811
|
-
: Impl[K]["raw"] extends Effect<any, any, infer R> ? R
|
|
812
|
-
: never
|
|
813
|
-
: Impl[K] extends (...args: any[]) => Effect<any, any, infer R> ? R
|
|
814
|
-
: Impl[K] extends Effect<any, any, infer R> ? R
|
|
815
|
-
: never,
|
|
816
|
-
GetEffectContext<CTXMap, Rsc[K]["config"]>
|
|
817
|
-
>,
|
|
818
|
-
HttpRouter.HttpRouter.Provided
|
|
819
|
-
>
|
|
820
|
-
>
|
|
821
|
-
} = (obj: Record<keyof Filtered, any>) =>
|
|
822
|
-
typedKeysOf(obj).reduce((acc, cur) => {
|
|
823
|
-
acc[cur] = "raw" in obj[cur] ? items[cur].raw(obj[cur].raw) : items[cur](obj[cur])
|
|
824
|
-
return acc
|
|
825
|
-
}, {} as any)
|
|
826
|
-
|
|
827
|
-
return Object.assign(effect, items, { router, router3 })
|
|
725
|
+
return Object.assign(effect, items, { router })
|
|
828
726
|
}
|
|
829
727
|
|
|
830
728
|
type HR<T> = T extends HttpRouter.HttpRouter<any, infer R> ? R : never
|
|
@@ -880,16 +778,7 @@ export const makeRouter = <
|
|
|
880
778
|
}
|
|
881
779
|
}
|
|
882
780
|
|
|
883
|
-
return {
|
|
884
|
-
matchAll,
|
|
885
|
-
matchFor: <
|
|
886
|
-
const ModuleName extends string,
|
|
887
|
-
const Rsc extends Record<string, any>
|
|
888
|
-
>(
|
|
889
|
-
rsc: Rsc & { meta: { moduleName: ModuleName } }
|
|
890
|
-
) => matchFor(rsc).router3,
|
|
891
|
-
Router: matchFor
|
|
892
|
-
}
|
|
781
|
+
return { matchAll, matchFor }
|
|
893
782
|
}
|
|
894
783
|
|
|
895
784
|
export type MakeDeps<Make> = Make extends { readonly dependencies: ReadonlyArray<Layer.Layer.Any> }
|