@effect-app/infra 1.15.0 → 1.16.1

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @effect-app/infra
2
2
 
3
+ ## 1.16.1
4
+
5
+ ### Patch Changes
6
+
7
+ - fup
8
+
9
+ ## 1.16.0
10
+
11
+ ### Minor Changes
12
+
13
+ - feat: add new router support
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies
18
+ - effect-app@1.15.0
19
+ - @effect-app/infra-adapters@1.10.1
20
+
3
21
  ## 1.15.0
4
22
 
5
23
  ### Minor Changes
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.makeRouter = void 0;
7
+ var _Effect = require("@effect-app/core/Effect");
8
+ var _utils = require("@effect-app/core/utils");
9
+ var _routing = require("@effect-app/infra/api/routing");
10
+ var _effectApp = require("effect-app");
11
+ var _http = require("effect-app/http");
12
+ var _schema = require("effect-app/schema");
13
+ // TODO: support FLIP
14
+ const makeRouter = (handleRequestEnv /* Middleware */) => {
15
+ function match(requestHandler, errorHandler, middleware) {
16
+ let middlewareLayer = undefined;
17
+ if (middleware) {
18
+ const {
19
+ handler,
20
+ makeRequestLayer
21
+ } = middleware(requestHandler);
22
+ requestHandler = handler; // todo
23
+ middlewareLayer = makeRequestLayer;
24
+ }
25
+ // const rdesc = yield* RouteDescriptors.flatMap((_) => _.get)
26
+ const handler = (0, _routing.makeRequestHandler)(requestHandler,
27
+ // one argument if no middleware, 2 if has middleware. TODO: clean this shit up
28
+ errorHandler, middlewareLayer);
29
+ const route = _http.HttpRouter.makeRoute(requestHandler.Request.method, requestHandler.Request.path, handler.pipe(_effectApp.Effect.withSpan("Request." + requestHandler.name, {
30
+ captureStackTrace: () => requestHandler.stack
31
+ })));
32
+ // TODO
33
+ // rdesc.push(makeRouteDescriptor(
34
+ // requestHandler.Request.path,
35
+ // requestHandler.Request.method,
36
+ // requestHandler
37
+ // ))
38
+ return route;
39
+ }
40
+ function handle(_, name, adaptResponse) {
41
+ const Request = _effectApp.S.REST.extractRequest(_);
42
+ const Response = _effectApp.S.REST.extractResponse(_);
43
+ return h => ({
44
+ adaptResponse,
45
+ stack: h.stack,
46
+ h: h.handler,
47
+ name,
48
+ Request,
49
+ Response,
50
+ ResponseOpenApi: _.ResponseOpenApi ?? Response,
51
+ Context: null,
52
+ CTX: null,
53
+ rt: h._tag
54
+ });
55
+ }
56
+ function matchFor(rsc) {
57
+ const filtered = (0, _utils.typedKeysOf)(rsc).reduce((acc, cur) => {
58
+ if (_effectApp.Predicate.isObject(rsc[cur]) && rsc[cur].Request) {
59
+ acc[cur] = rsc[cur];
60
+ }
61
+ return acc;
62
+ }, {});
63
+ const matchWithServices = action => {
64
+ return (services, f) => (req, ctx) => _effectApp.Effect.andThen((0, _Effect.allLower)(services), svc2 => f(req, {
65
+ ...ctx,
66
+ ...svc2,
67
+ Response: rsc[action].Response
68
+ }));
69
+ };
70
+ const controllers = controllers => {
71
+ const handlers = (0, _utils.typedKeysOf)(filtered).reduce((acc, cur) => {
72
+ if (cur === "meta") return acc;
73
+ const m = rsc.meta;
74
+ if (!m) throw new Error("Resource has no meta specified");
75
+ acc[cur] = handle(rsc[cur], m.moduleName + "." + cur)(controllers[cur]);
76
+ return acc;
77
+ }, {});
78
+ const mapped = (0, _utils.typedKeysOf)(handlers).reduce((acc, cur) => {
79
+ const handler = handlers[cur];
80
+ const req = handler.Request;
81
+ class Request extends req {
82
+ static path = "/" + handler.name + (req.path === "/" ? "" : req.path);
83
+ static method = req.method === "AUTO" ? _schema.REST.determineMethod(handler.name.split(".")[1], req) : req.method;
84
+ }
85
+ if (req.method === "AUTO") {
86
+ Object.assign(Request, {
87
+ [Request.method === "GET" || Request.method === "DELETE" ? "Query" : "Body"]: req.Auto
88
+ });
89
+ }
90
+ Object.assign(handler, {
91
+ Request
92
+ });
93
+ acc[cur] = match(handler, errorHandler(req), handleRequestEnv // TODO
94
+ );
95
+ return acc;
96
+ }, {});
97
+ return _http.HttpRouter.fromIterable(Object.values(mapped));
98
+ };
99
+ const r = {
100
+ controllers,
101
+ ...(0, _utils.typedKeysOf)(filtered).reduce((prev, cur) => {
102
+ ;
103
+ prev[cur] = (svcOrFnOrEffect, fnOrNone) => {
104
+ const stack = new Error().stack?.split("\n").slice(2).join("\n");
105
+ return _effectApp.Effect.isEffect(svcOrFnOrEffect) ? class {
106
+ static stack = stack;
107
+ static _tag = "d";
108
+ static handler = () => svcOrFnOrEffect;
109
+ } : typeof svcOrFnOrEffect === "function" ? class {
110
+ static stack = stack;
111
+ static _tag = "d";
112
+ static handler = (req, ctx) => svcOrFnOrEffect(req, {
113
+ ...ctx,
114
+ Response: rsc[cur].Response
115
+ });
116
+ } : class {
117
+ static stack = stack;
118
+ static _tag = "d";
119
+ static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
120
+ };
121
+ };
122
+ prev[cur + "Raw"] = (svcOrFnOrEffect, fnOrNone) => {
123
+ const stack = new Error().stack?.split("\n").slice(2).join("\n");
124
+ return _effectApp.Effect.isEffect(svcOrFnOrEffect) ? class {
125
+ static stack = stack;
126
+ static _tag = "raw";
127
+ static handler = () => svcOrFnOrEffect;
128
+ } : typeof svcOrFnOrEffect === "function" ? class {
129
+ static stack = stack;
130
+ static _tag = "raw";
131
+ static handler = (req, ctx) => svcOrFnOrEffect(req, {
132
+ ...ctx,
133
+ Response: rsc[cur].Response
134
+ });
135
+ } : class {
136
+ static stack = stack;
137
+ static _tag = "raw";
138
+ static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
139
+ };
140
+ };
141
+ return prev;
142
+ }, {})
143
+ };
144
+ return r;
145
+ }
146
+ const errorHandler = resourceRequest => {
147
+ return (req, res, r2) => (0, _routing.defaultErrorHandler)(req, res, _effectApp.Effect.catchTag(r2, "ParseError", _ => _effectApp.Effect.die(_)), resourceRequest.failure);
148
+ };
149
+ /**
150
+ * Gather all handlers of a module and attach them to the Server.
151
+ * If no `allowAnonymous` flag is on the Request, will require a valid authenticated user.
152
+ */
153
+ function matchAll(handlers) {
154
+ const r = (0, _utils.typedKeysOf)(handlers).reduce((acc, cur) => {
155
+ return _http.HttpRouter.concat(acc, handlers[cur]);
156
+ }, _http.HttpRouter.empty);
157
+ return r;
158
+ }
159
+ return {
160
+ matchFor,
161
+ matchAll
162
+ };
163
+ };
164
+ exports.makeRouter = makeRouter;
165
+ //# sourceMappingURL=router.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.cjs","names":["_Effect","require","_utils","_routing","_effectApp","_http","_schema","makeRouter","handleRequestEnv","match","requestHandler","errorHandler","middleware","middlewareLayer","undefined","handler","makeRequestLayer","makeRequestHandler","route","HttpRouter","makeRoute","Request","method","path","pipe","Effect","withSpan","name","captureStackTrace","stack","handle","_","adaptResponse","S","REST","extractRequest","Response","extractResponse","h","ResponseOpenApi","Context","CTX","rt","_tag","matchFor","rsc","filtered","typedKeysOf","reduce","acc","cur","Predicate","isObject","matchWithServices","action","services","f","req","ctx","andThen","allLower","svc2","controllers","handlers","m","meta","Error","moduleName","mapped","determineMethod","split","Object","assign","Auto","fromIterable","values","r","prev","svcOrFnOrEffect","fnOrNone","slice","join","isEffect","resourceRequest","res","r2","defaultErrorHandler","catchTag","die","failure","matchAll","concat","empty","exports"],"sources":["../src/router.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -8,5 +8,5 @@ import type { HttpServerRequest, HttpServerResponse } from "effect-app/http";
8
8
  import type { RequestHandler } from "./base.js";
9
9
  import type { Middleware } from "./makeRequestHandler.js";
10
10
  export declare const RouteDescriptors: Context.Tag<Ref<RouteDescriptorAny[]>, Ref<RouteDescriptorAny[]>>;
11
- export declare function match<R, M, PathA extends Struct.Fields, CookieA extends Struct.Fields, QueryA extends Struct.Fields, BodyA extends Struct.Fields, HeaderA extends Struct.Fields, ReqA extends PathA & QueryA & BodyA, ResA extends Struct.Fields, ResE, MiddlewareE, PPath extends `/${string}`, R2, PR, RErr, CTX, Context, Config>(requestHandler: RequestHandler<R, M, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, ResA, ResE, PPath, CTX, Context, Config>, errorHandler: <R>(req: HttpServerRequest.HttpServerRequest, res: HttpServerResponse.HttpServerResponse, r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | MiddlewareE | ResE, R>) => Effect<HttpServerResponse.HttpServerResponse, never, Exclude<RErr | R, HttpServerRequest.HttpServerRequest | HttpRouter.RouteContext | Scope>>, middleware?: Middleware<R, M, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, ResA, ResE, MiddlewareE, PPath, R2, PR, CTX, Context, Config>): Effect.Effect<HttpRouter.Route<import("@effect/platform/HttpServerError").RequestError, import("../../services/RequestContextContainer.js").RequestContextContainer | import("@effect-app/infra-adapters/RequestFiberSet").RequestFiberSet | import("../../services/Store/ContextMapContainer.js").ContextMapContainer | Exclude<R2, HttpRouter.HttpRouter.Provided> | Exclude<RErr, HttpRouter.HttpRouter.Provided> | Exclude<Exclude<Exclude<R, import("effect-app/utils").EnforceNonEmptyRecord<M>>, PR>, HttpRouter.HttpRouter.Provided>>, never, never>;
11
+ export declare function match<R, M, PathA extends Struct.Fields, CookieA extends Struct.Fields, QueryA extends Struct.Fields, BodyA extends Struct.Fields, HeaderA extends Struct.Fields, ReqA extends PathA & QueryA & BodyA, ResA extends Struct.Fields, ResE, MiddlewareE, PPath extends `/${string}`, R2, PR, RErr, CTX, Context, Config>(requestHandler: RequestHandler<R, M, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, ResA, ResE, PPath, CTX, Context, Config>, errorHandler: <R>(req: HttpServerRequest.HttpServerRequest, res: HttpServerResponse.HttpServerResponse, r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | MiddlewareE | ResE, R>) => Effect<HttpServerResponse.HttpServerResponse, never, Exclude<RErr | R, HttpServerRequest.HttpServerRequest | HttpRouter.RouteContext | Scope>>, middleware?: Middleware<R, M, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, ResA, ResE, MiddlewareE, PPath, R2, PR, CTX, Context, Config>): Effect.Effect<HttpRouter.Route<import("@effect/platform/HttpServerError").RequestError, import("../../services/RequestContextContainer.js").RequestContextContainer | import("../../services/Store/ContextMapContainer.js").ContextMapContainer | import("@effect-app/infra-adapters/RequestFiberSet").RequestFiberSet | Exclude<R2, HttpRouter.HttpRouter.Provided> | Exclude<RErr, HttpRouter.HttpRouter.Provided> | Exclude<Exclude<Exclude<R, import("effect-app/utils").EnforceNonEmptyRecord<M>>, PR>, HttpRouter.HttpRouter.Provided>>, never, never>;
12
12
  //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1,106 @@
1
+ import type { EffectUnunified, LowerServices } from "@effect-app/core/Effect";
2
+ import type { EnforceNonEmptyRecord } from "@effect-app/core/utils";
3
+ import type { EffectDeps, Extr } from "@effect-app/infra/api/routing";
4
+ import { Effect, S } from "effect-app";
5
+ import type { ValidationError } from "effect-app/client/errors";
6
+ import { HttpRouter } from "effect-app/http";
7
+ import { REST } from "effect-app/schema";
8
+ export type RouteMatch<R, M, PR = never> = HttpRouter.Route<never, Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>>;
9
+ export interface Hint<Err extends string> {
10
+ Err: Err;
11
+ }
12
+ export declare const makeRouter: <CTX, CTXMap extends Record<string, [string, any, boolean]>>(handleRequestEnv: any) => {
13
+ matchFor: <Rsc extends Record<string, any>>(rsc: Rsc) => {
14
+ controllers: <THandlers extends { [K in keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
15
+ Response: any;
16
+ } ? K_1 : never]: Rsc[K_1] extends {
17
+ Response: any;
18
+ } ? Rsc[K_1] : never; }]: {
19
+ _tag: "raw";
20
+ handler: (req: Rsc[K]["Request"], ctx: Rsc[K]["Context"]) => Effect<S.Schema.Encoded<Extr<REST.GetResponse<Rsc[K]>>>, import("effect-app/client/errors").OptimisticConcurrencyException | S.ParseResult.ParseError | ValidationError | import("effect-app/client/errors").InvalidStateError | import("effect-app/client/errors").NotFoundError<ItemType> | import("effect-app/client/errors").NotLoggedInError | import("effect-app/client/errors").LoginError | import("effect-app/client/errors").UnauthorizedError | import("effect-app/client/errors").ServiceUnavailableError | S.Schema.Type<Rsc[K]["failure"]>, any>;
21
+ } | {
22
+ _tag: "d";
23
+ handler: (req: Rsc[K]["Request"], ctx: Rsc[K]["Context"]) => Effect<S.Schema.Type<Extr<REST.GetResponse<Rsc[K]>>>, import("effect-app/client/errors").OptimisticConcurrencyException | S.ParseResult.ParseError | ValidationError | import("effect-app/client/errors").InvalidStateError | import("effect-app/client/errors").NotFoundError<ItemType> | import("effect-app/client/errors").NotLoggedInError | import("effect-app/client/errors").LoginError | import("effect-app/client/errors").UnauthorizedError | import("effect-app/client/errors").ServiceUnavailableError | S.Schema.Type<Rsc[K]["failure"]>, any>;
24
+ }; }>(controllers: THandlers) => HttpRouter.HttpRouter<[(keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
25
+ Response: any;
26
+ } ? K_1 : never]: Rsc[K_1] extends {
27
+ Response: any;
28
+ } ? Rsc[K_1] : never; } extends infer T extends keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
29
+ Response: any;
30
+ } ? K_1 : never]: Rsc[K_1] extends {
31
+ Response: any;
32
+ } ? Rsc[K_1] : never; } ? { [K in T]: HttpRouter.Route<never, Exclude<Exclude<_R<ReturnType<THandlers[K]["handler"]>>, EnforceNonEmptyRecord<ReqFromSchema<REST.GetRequest<Rsc[K]>>>>, { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[K]> ? REST.GetRequest<Rsc[K]>[key] extends true ? never : CTXMap[key][0] : CTXMap[key][0]]: CTXMap[key][1]; }[keyof { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[K]> ? REST.GetRequest<Rsc[K]>[key] extends true ? never : CTXMap[key][0] : CTXMap[key][0]]: CTXMap[key][1]; }]>>; } : never)[keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
33
+ Response: any;
34
+ } ? K_1 : never]: Rsc[K_1] extends {
35
+ Response: any;
36
+ } ? Rsc[K_1] : never; }]] extends [HttpRouter.Route<infer E, any>] ? E : never, [(keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
37
+ Response: any;
38
+ } ? K_1 : never]: Rsc[K_1] extends {
39
+ Response: any;
40
+ } ? Rsc[K_1] : never; } extends infer T extends keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
41
+ Response: any;
42
+ } ? K_1 : never]: Rsc[K_1] extends {
43
+ Response: any;
44
+ } ? Rsc[K_1] : never; } ? { [K in T]: HttpRouter.Route<never, Exclude<Exclude<_R<ReturnType<THandlers[K]["handler"]>>, EnforceNonEmptyRecord<ReqFromSchema<REST.GetRequest<Rsc[K]>>>>, { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[K]> ? REST.GetRequest<Rsc[K]>[key] extends true ? never : CTXMap[key][0] : CTXMap[key][0]]: CTXMap[key][1]; }[keyof { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[K]> ? REST.GetRequest<Rsc[K]>[key] extends true ? never : CTXMap[key][0] : CTXMap[key][0]]: CTXMap[key][1]; }]>>; } : never)[keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
45
+ Response: any;
46
+ } ? K_1 : never]: Rsc[K_1] extends {
47
+ Response: any;
48
+ } ? Rsc[K_1] : never; }]] extends [HttpRouter.Route<any, infer R>] ? R : never>;
49
+ } & { [Key in keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
50
+ Response: any;
51
+ } ? K_1 : never]: Rsc[K_1] extends {
52
+ Response: any;
53
+ } ? Rsc[K_1] : never; }]: {
54
+ <R2, E, A>(f: Effect<A, E, R2>): S.Schema.Type<REST.GetResponse<Rsc[Key]>> extends infer T ? T extends S.Schema.Type<REST.GetResponse<Rsc[Key]>> ? T extends void ? A extends void ? {
55
+ _tag: "d";
56
+ handler: (req: Rsc[Key]["Request"], ctx: Rsc[Key]["Context"]) => Effect<A, E, R2>;
57
+ } : Hint<"You're returning non void for a void Response, please fix"> : {
58
+ _tag: "d";
59
+ handler: (req: Rsc[Key]["Request"], ctx: Rsc[Key]["Context"]) => Effect<A, E, R2>;
60
+ } : never : never;
61
+ <R2, E_1, A_1>(f: (req: S.Schema.Type<REST.GetRequest<Rsc[Key]>>, ctx: CTX & { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[Key]> ? REST.GetRequest<Rsc[Key]>[key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as key_1 extends keyof REST.GetRequest<Rsc[Key]> ? REST.GetRequest<Rsc[Key]>[key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & Pick<Rsc[Key], "Response">) => Effect<A_1, E_1, R2>): S.Schema.Type<REST.GetResponse<Rsc[Key]>> extends infer T ? T extends S.Schema.Type<REST.GetResponse<Rsc[Key]>> ? T extends void ? A_1 extends void ? {
62
+ _tag: "d";
63
+ handler: (req: Rsc[Key]["Request"], ctx: Rsc[Key]["Context"]) => Effect<A_1, E_1, R2>;
64
+ } : Hint<"You're returning non void for a void Response, please fix"> : {
65
+ _tag: "d";
66
+ handler: (req: Rsc[Key]["Request"], ctx: Rsc[Key]["Context"]) => Effect<A_1, E_1, R2>;
67
+ } : never : never;
68
+ <SVC extends Record<string, EffectUnunified<any, any, any>>, R2, E_2, A_2>(services: SVC, f: (req: S.Schema.Type<REST.GetRequest<Rsc[Key]>>, ctx: import("@effect-app/core/utils").ComputeFlat<LowerServices<EffectDeps<SVC>> & CTX & { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[Key]> ? REST.GetRequest<Rsc[Key]>[key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as key_1 extends keyof REST.GetRequest<Rsc[Key]> ? REST.GetRequest<Rsc[Key]>[key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & Pick<Rsc[Key], "Response">>) => Effect<A_2, E_2, R2>): S.Schema.Type<REST.GetResponse<Rsc[Key]>> extends infer T ? T extends S.Schema.Type<REST.GetResponse<Rsc[Key]>> ? T extends void ? A_2 extends void ? {
69
+ _tag: "d";
70
+ handler: (req: Rsc[Key]["Request"], ctx: Rsc[Key]["Context"]) => Effect<A_2, E_2, R2>;
71
+ } : Hint<"You're returning non void for a void Response, please fix"> : {
72
+ _tag: "d";
73
+ handler: (req: Rsc[Key]["Request"], ctx: Rsc[Key]["Context"]) => Effect<A_2, E_2, R2>;
74
+ } : never : never;
75
+ }; } & { [Key_1 in keyof { [K_1 in keyof Rsc as Rsc[K_1] extends {
76
+ Response: any;
77
+ } ? K_1 : never]: Rsc[K_1] extends {
78
+ Response: any;
79
+ } ? Rsc[K_1] : never; } as Key_1 extends string ? `${Key_1}Raw` : never]: {
80
+ <R2_1, E, A>(f: Effect<A, E, R2_1>): S.Schema.Type<REST.GetResponse<Rsc[Key_1]>> extends infer T ? T extends S.Schema.Type<REST.GetResponse<Rsc[Key_1]>> ? T extends void ? A extends void ? {
81
+ _tag: "raw";
82
+ handler: (req: Rsc[Key_1]["Request"], ctx: Rsc[Key_1]["Context"]) => Effect<A, E, R2_1>;
83
+ } : Hint<"You're returning non void for a void Response, please fix"> : {
84
+ _tag: "raw";
85
+ handler: (req: Rsc[Key_1]["Request"], ctx: Rsc[Key_1]["Context"]) => Effect<A, E, R2_1>;
86
+ } : never : never;
87
+ <R2_1, E_1, A_1>(f: (req: S.Schema.Type<REST.GetRequest<Rsc[Key_1]>>, ctx: CTX & { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[Key_1]> ? REST.GetRequest<Rsc[Key_1]>[key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as key_1 extends keyof REST.GetRequest<Rsc[Key_1]> ? REST.GetRequest<Rsc[Key_1]>[key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & Pick<Rsc[Key_1], "Response">) => Effect<A_1, E_1, R2_1>): S.Schema.Type<REST.GetResponse<Rsc[Key_1]>> extends infer T ? T extends S.Schema.Type<REST.GetResponse<Rsc[Key_1]>> ? T extends void ? A_1 extends void ? {
88
+ _tag: "raw";
89
+ handler: (req: Rsc[Key_1]["Request"], ctx: Rsc[Key_1]["Context"]) => Effect<A_1, E_1, R2_1>;
90
+ } : Hint<"You're returning non void for a void Response, please fix"> : {
91
+ _tag: "raw";
92
+ handler: (req: Rsc[Key_1]["Request"], ctx: Rsc[Key_1]["Context"]) => Effect<A_1, E_1, R2_1>;
93
+ } : never : never;
94
+ <SVC extends Record<string, EffectUnunified<any, any, any>>, R2, E_2, A_2>(services: SVC, f: (req: S.Schema.Type<REST.GetRequest<Rsc[Key_1]>>, ctx: import("@effect-app/core/utils").ComputeFlat<LowerServices<EffectDeps<SVC>> & CTX & { [key in keyof CTXMap as key extends keyof REST.GetRequest<Rsc[Key_1]> ? REST.GetRequest<Rsc[Key_1]>[key] extends true ? CTXMap[key][0] : never : never]?: CTXMap[key][1]; } & { [key_1 in keyof CTXMap as key_1 extends keyof REST.GetRequest<Rsc[Key_1]> ? REST.GetRequest<Rsc[Key_1]>[key_1] extends false ? CTXMap[key_1][0] : never : CTXMap[key_1][0]]: CTXMap[key_1][1]; } & Pick<Rsc[Key_1], "Response">>) => Effect<A_2, E_2, R2>): S.Schema.Type<REST.GetResponse<Rsc[Key_1]>> extends infer T ? T extends S.Schema.Type<REST.GetResponse<Rsc[Key_1]>> ? T extends void ? A_2 extends void ? {
95
+ _tag: "raw";
96
+ handler: (req: Rsc[Key_1]["Request"], ctx: Rsc[Key_1]["Context"]) => Effect<A_2, E_2, R2>;
97
+ } : Hint<"You're returning non void for a void Response, please fix"> : {
98
+ _tag: "raw";
99
+ handler: (req: Rsc[Key_1]["Request"], ctx: Rsc[Key_1]["Context"]) => Effect<A_2, E_2, R2>;
100
+ } : never : never;
101
+ }; };
102
+ matchAll: <T extends {
103
+ [key: string]: HttpRouter.HttpRouter<any, any>;
104
+ }>(handlers: T) => HttpRouter.HttpRouter<[T[keyof T]] extends [HttpRouter.HttpRouter<any, infer E_3>] ? E_3 : never, [T[keyof T]] extends [HttpRouter.HttpRouter<infer R, any>] ? R : never>;
105
+ };
106
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAG7E,OAAO,KAAK,EAAW,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAC5E,OAAO,KAAK,EAGV,UAAU,EACV,IAAI,EAOL,MAAM,+BAA+B,CAAA;AAGtC,OAAO,EAAE,MAAM,EAAa,CAAC,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAGxC,MAAM,MAAM,UAAU,CACpB,CAAC,EACD,CAAC,EAGD,EAAE,GAAG,KAAK,IAET,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE7E,MAAM,WAAW,IAAI,CAAC,GAAG,SAAS,MAAM;IACtC,GAAG,EAAE,GAAG,CAAA;CACT;AAKD,eAAO,MAAM,UAAU,GAAI,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,oBACjE,GAAG;eAiMH,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,OAC1C,GAAG;sBAiIN,SAAS,SAAS,GAEf,CAAS;sBAhIkC,GAAG;;sBAA4C,GAAG;+BAgIpF;;;;;;YACX,eAEY,SAAS,KAoEmC,UAAU,CAAC,UAAU;sBAvMhC,GAAG;;sBAA4C,GAAG;;sBAAlD,GAAG;;sBAA4C,GAAG;qCAqL7F,CAAC,4JAzWH,GAAG,iLAAH,GAAG;sBAoL0C,GAAG;;sBAA4C,GAAG;kEAmMvE,CAAC;sBAnMoB,GAAG;;sBAA4C,GAAG;;sBAAlD,GAAG;;sBAA4C,GAAG;qCAqL7F,CAAC,4JAzWH,GAAG,iLAAH,GAAG;sBAoL0C,GAAG;;sBAA4C,GAAG;uEA8LlE,CAAC,eAY9B;WAsDM,GAAG;kBAhQoC,GAAG;;kBAA4C,GAAG;;SAmC/F,EAAE,EAAE,CAAC,EAAE,CAAC;;;;;;;SAcR,EAAE,6EAjPF,GAAG;;;;;;;SAmQF,GAAG,SAAS,MAAM,CAChB,MAAM,EACN,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAC/B,EACD,EAAE,0KAvQH,GAAG;;;;;;;;kBAgM0C,GAAG;;kBAA4C,GAAG;;eAmC3F,CAAC,EAAE,CAAC;;;;;;;4FAnOR,GAAG;;;;;;;SAmQF,GAAG,SAAS,MAAM,CAChB,MAAM,EACN,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAC/B,EACD,EAAE,4KAvQH,GAAG;;;;;;;;eAwdU,CAAC;;iBAAwC,CAAC,KAe9C,UAAU,CAAC,UAAU,+HATH,CAAC,oBAY9B;CA0BJ,CAAA"}
package/dist/router.js ADDED
@@ -0,0 +1,149 @@
1
+ import { allLower } from "@effect-app/core/Effect";
2
+ import { typedKeysOf } from "@effect-app/core/utils";
3
+ import { defaultErrorHandler, makeRequestHandler } from "@effect-app/infra/api/routing";
4
+ import { Effect, Predicate, S } from "effect-app";
5
+ import { HttpRouter } from "effect-app/http";
6
+ import { REST } from "effect-app/schema";
7
+ // TODO: support FLIP
8
+ export const makeRouter = (handleRequestEnv /* Middleware */) => {
9
+ function match(requestHandler, errorHandler, middleware) {
10
+ let middlewareLayer = undefined;
11
+ if (middleware) {
12
+ const { handler, makeRequestLayer } = middleware(requestHandler);
13
+ requestHandler = handler; // todo
14
+ middlewareLayer = makeRequestLayer;
15
+ }
16
+ // const rdesc = yield* RouteDescriptors.flatMap((_) => _.get)
17
+ const handler = makeRequestHandler(requestHandler, // one argument if no middleware, 2 if has middleware. TODO: clean this shit up
18
+ errorHandler, middlewareLayer);
19
+ const route = HttpRouter.makeRoute(requestHandler.Request.method, requestHandler.Request.path, handler.pipe(Effect.withSpan("Request." + requestHandler.name, { captureStackTrace: () => requestHandler.stack })));
20
+ // TODO
21
+ // rdesc.push(makeRouteDescriptor(
22
+ // requestHandler.Request.path,
23
+ // requestHandler.Request.method,
24
+ // requestHandler
25
+ // ))
26
+ return route;
27
+ }
28
+ function handle(_, name, adaptResponse) {
29
+ const Request = S.REST.extractRequest(_);
30
+ const Response = S.REST.extractResponse(_);
31
+ return (h) => ({
32
+ adaptResponse,
33
+ stack: h.stack,
34
+ h: h.handler,
35
+ name,
36
+ Request,
37
+ Response,
38
+ ResponseOpenApi: _.ResponseOpenApi ?? Response,
39
+ Context: null,
40
+ CTX: null,
41
+ rt: h._tag
42
+ });
43
+ }
44
+ function matchFor(rsc) {
45
+ const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
46
+ if (Predicate.isObject(rsc[cur]) && rsc[cur].Request) {
47
+ acc[cur] = rsc[cur];
48
+ }
49
+ return acc;
50
+ }, {});
51
+ const matchWithServices = (action) => {
52
+ return (services, f) => (req, ctx) => Effect.andThen(allLower(services), (svc2) => f(req, { ...ctx, ...svc2, Response: rsc[action].Response }));
53
+ };
54
+ const controllers = (controllers) => {
55
+ const handlers = typedKeysOf(filtered).reduce((acc, cur) => {
56
+ if (cur === "meta")
57
+ return acc;
58
+ const m = rsc.meta;
59
+ if (!m)
60
+ throw new Error("Resource has no meta specified");
61
+ acc[cur] = handle(rsc[cur], m.moduleName + "." + cur)(controllers[cur]);
62
+ return acc;
63
+ }, {});
64
+ const mapped = typedKeysOf(handlers).reduce((acc, cur) => {
65
+ const handler = handlers[cur];
66
+ const req = handler.Request;
67
+ class Request extends req {
68
+ static path = "/" + handler.name + (req.path === "/" ? "" : req.path);
69
+ static method = req.method === "AUTO"
70
+ ? REST.determineMethod(handler.name.split(".")[1], req)
71
+ : req.method;
72
+ }
73
+ if (req.method === "AUTO") {
74
+ Object.assign(Request, {
75
+ [Request.method === "GET" || Request.method === "DELETE" ? "Query" : "Body"]: req.Auto
76
+ });
77
+ }
78
+ Object.assign(handler, { Request });
79
+ acc[cur] = match(handler, errorHandler(req), handleRequestEnv // TODO
80
+ );
81
+ return acc;
82
+ }, {});
83
+ return HttpRouter.fromIterable(Object.values(mapped));
84
+ };
85
+ const r = {
86
+ controllers,
87
+ ...typedKeysOf(filtered).reduce((prev, cur) => {
88
+ ;
89
+ prev[cur] = (svcOrFnOrEffect, fnOrNone) => {
90
+ const stack = new Error().stack?.split("\n").slice(2).join("\n");
91
+ return Effect.isEffect(svcOrFnOrEffect)
92
+ ? class {
93
+ static stack = stack;
94
+ static _tag = "d";
95
+ static handler = () => svcOrFnOrEffect;
96
+ }
97
+ : typeof svcOrFnOrEffect === "function"
98
+ ? class {
99
+ static stack = stack;
100
+ static _tag = "d";
101
+ static handler = (req, ctx) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].Response });
102
+ }
103
+ : class {
104
+ static stack = stack;
105
+ static _tag = "d";
106
+ static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
107
+ };
108
+ };
109
+ prev[cur + "Raw"] = (svcOrFnOrEffect, fnOrNone) => {
110
+ const stack = new Error().stack?.split("\n").slice(2).join("\n");
111
+ return Effect.isEffect(svcOrFnOrEffect)
112
+ ? class {
113
+ static stack = stack;
114
+ static _tag = "raw";
115
+ static handler = () => svcOrFnOrEffect;
116
+ }
117
+ : typeof svcOrFnOrEffect === "function"
118
+ ? class {
119
+ static stack = stack;
120
+ static _tag = "raw";
121
+ static handler = (req, ctx) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].Response });
122
+ }
123
+ : class {
124
+ static stack = stack;
125
+ static _tag = "raw";
126
+ static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone);
127
+ };
128
+ };
129
+ return prev;
130
+ }, {})
131
+ };
132
+ return r;
133
+ }
134
+ const errorHandler = (resourceRequest) => {
135
+ return (req, res, r2) => defaultErrorHandler(req, res, Effect.catchTag(r2, "ParseError", (_) => Effect.die(_)), resourceRequest.failure);
136
+ };
137
+ /**
138
+ * Gather all handlers of a module and attach them to the Server.
139
+ * If no `allowAnonymous` flag is on the Request, will require a valid authenticated user.
140
+ */
141
+ function matchAll(handlers) {
142
+ const r = typedKeysOf(handlers).reduce((acc, cur) => {
143
+ return HttpRouter.concat(acc, handlers[cur]);
144
+ }, HttpRouter.empty);
145
+ return r;
146
+ }
147
+ return { matchFor, matchAll };
148
+ };
149
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0seUJBQXlCLENBQUE7QUFDbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFBO0FBY3BELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLCtCQUErQixDQUFBO0FBRXZGLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUVqRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFHNUMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBa0J4QyxxQkFBcUI7QUFDckIsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLENBQ3hCLGdCQUFxQixDQUFDLGdCQUFnQixFQUN0QyxFQUFFO0lBcUJGLFNBQVMsS0FBSyxDQW9CWixjQWVDLEVBQ0QsWUFRQyxFQUNELFVBa0JDO1FBRUQsSUFBSSxlQUFlLEdBQTJDLFNBQVMsQ0FBQTtRQUN2RSxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2YsTUFBTSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFVBQVUsQ0FBQyxjQUFjLENBQUMsQ0FBQTtZQUNoRSxjQUFjLEdBQUcsT0FBYyxDQUFBLENBQUMsT0FBTztZQUN2QyxlQUFlLEdBQUcsZ0JBQWdCLENBQUE7UUFDcEMsQ0FBQztRQUNELDhEQUE4RDtRQUU5RCxNQUFNLE9BQU8sR0FBRyxrQkFBa0IsQ0FrQmhDLGNBQXFCLEVBQUUsK0VBQStFO1FBQ3RHLFlBQVksRUFDWixlQUFlLENBQ2hCLENBQUE7UUFFRCxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsU0FBUyxDQUNoQyxjQUFjLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFDN0IsY0FBYyxDQUFDLE9B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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "1.15.0",
3
+ "version": "1.16.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -18,10 +18,10 @@
18
18
  "proper-lockfile": "^4.1.2",
19
19
  "pure-rand": "6.1.0",
20
20
  "redlock": "^4.2.0",
21
+ "@effect-app/infra-adapters": "1.10.1",
21
22
  "@effect-app/core": "1.9.0",
22
- "@effect-app/infra-adapters": "1.10.0",
23
- "effect-app": "1.14.0",
24
- "@effect-app/schema": "1.11.0"
23
+ "@effect-app/schema": "1.11.0",
24
+ "effect-app": "1.15.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@babel/cli": "^7.25.6",
@@ -334,6 +334,16 @@
334
334
  "default": "./_cjs/rateLimit.cjs"
335
335
  }
336
336
  },
337
+ "./router": {
338
+ "import": {
339
+ "types": "./dist/router.d.ts",
340
+ "default": "./dist/router.js"
341
+ },
342
+ "require": {
343
+ "types": "./dist/router.d.ts",
344
+ "default": "./_cjs/router.cjs"
345
+ }
346
+ },
337
347
  "./services/Emailer": {
338
348
  "import": {
339
349
  "types": "./dist/services/Emailer.d.ts",
package/src/router.ts ADDED
@@ -0,0 +1,567 @@
1
+ /* eslint-disable @typescript-eslint/no-empty-object-type */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import type { EffectUnunified, LowerServices } from "@effect-app/core/Effect"
4
+ import { allLower } from "@effect-app/core/Effect"
5
+ import { typedKeysOf } from "@effect-app/core/utils"
6
+ import type { Compute, EnforceNonEmptyRecord } from "@effect-app/core/utils"
7
+ import type {
8
+ _E,
9
+ _R,
10
+ EffectDeps,
11
+ Extr,
12
+ JWTError,
13
+ Middleware,
14
+ ReqFromSchema,
15
+ ReqHandler,
16
+ RequestHandler,
17
+ ResFromSchema
18
+ } from "@effect-app/infra/api/routing"
19
+ import { defaultErrorHandler, makeRequestHandler } from "@effect-app/infra/api/routing"
20
+ import type { Layer, Scope } from "effect-app"
21
+ import { Effect, Predicate, S } from "effect-app"
22
+ import type { SupportedErrors, ValidationError } from "effect-app/client/errors"
23
+ import { HttpRouter } from "effect-app/http"
24
+ import type { HttpServerRequest, HttpServerResponse } from "effect-app/http"
25
+ import type { Struct } from "effect-app/schema"
26
+ import { REST } from "effect-app/schema"
27
+ import type {} from "@effect/schema/ParseResult"
28
+
29
+ export type RouteMatch<
30
+ R,
31
+ M,
32
+ // TODO: specific errors
33
+ // Err extends SupportedErrors | S.ParseResult.ParseError,
34
+ PR = never
35
+ > // RErr = never,
36
+ = HttpRouter.Route<never, Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>>
37
+
38
+ export interface Hint<Err extends string> {
39
+ Err: Err
40
+ }
41
+
42
+ type AnyRequestModule = { Request: any; Context: any; Response: any; failure: any }
43
+
44
+ // TODO: support FLIP
45
+ export const makeRouter = <CTX, CTXMap extends Record<string, [string, any, boolean]>>(
46
+ handleRequestEnv: any /* Middleware */
47
+ ) => {
48
+ type GetCTX<T> =
49
+ & CTX
50
+ & {
51
+ [key in keyof CTXMap as key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never : never]?:
52
+ CTXMap[key][1]
53
+ }
54
+ & {
55
+ [key in keyof CTXMap as key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never : CTXMap[key][0]]:
56
+ CTXMap[key][1]
57
+ }
58
+
59
+ type Values<T extends Record<any, any>> = T[keyof T]
60
+
61
+ type GetContext<T> = Values<
62
+ {
63
+ [key in keyof CTXMap as key extends keyof T ? T[key] extends true ? never : CTXMap[key][0] : CTXMap[key][0]]: // TODO: or as an Optional available?
64
+ CTXMap[key][1]
65
+ }
66
+ >
67
+
68
+ function match<
69
+ R,
70
+ M,
71
+ PathA extends Struct.Fields,
72
+ CookieA extends Struct.Fields,
73
+ QueryA extends Struct.Fields,
74
+ BodyA extends Struct.Fields,
75
+ HeaderA extends Struct.Fields,
76
+ ReqA extends PathA & QueryA & BodyA,
77
+ ResA extends Struct.Fields,
78
+ ResE,
79
+ MiddlewareE,
80
+ PPath extends `/${string}`,
81
+ R2,
82
+ PR,
83
+ RErr,
84
+ CTX,
85
+ Context,
86
+ Config
87
+ >(
88
+ requestHandler: RequestHandler<
89
+ R,
90
+ M,
91
+ PathA,
92
+ CookieA,
93
+ QueryA,
94
+ BodyA,
95
+ HeaderA,
96
+ ReqA,
97
+ ResA,
98
+ ResE,
99
+ PPath,
100
+ CTX,
101
+ Context,
102
+ Config
103
+ >,
104
+ errorHandler: <R>(
105
+ req: HttpServerRequest.HttpServerRequest,
106
+ res: HttpServerResponse.HttpServerResponse,
107
+ r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | MiddlewareE | ResE, R>
108
+ ) => Effect<
109
+ HttpServerResponse.HttpServerResponse,
110
+ never,
111
+ Exclude<RErr | R, HttpServerRequest.HttpServerRequest | HttpRouter.RouteContext | Scope>
112
+ >,
113
+ middleware?: Middleware<
114
+ R,
115
+ M,
116
+ PathA,
117
+ CookieA,
118
+ QueryA,
119
+ BodyA,
120
+ HeaderA,
121
+ ReqA,
122
+ ResA,
123
+ ResE,
124
+ MiddlewareE,
125
+ PPath,
126
+ R2,
127
+ PR,
128
+ CTX,
129
+ Context,
130
+ Config
131
+ >
132
+ ) {
133
+ let middlewareLayer: Layer<PR, MiddlewareE, R2> | undefined = undefined
134
+ if (middleware) {
135
+ const { handler, makeRequestLayer } = middleware(requestHandler)
136
+ requestHandler = handler as any // todo
137
+ middlewareLayer = makeRequestLayer
138
+ }
139
+ // const rdesc = yield* RouteDescriptors.flatMap((_) => _.get)
140
+
141
+ const handler = makeRequestHandler<
142
+ R,
143
+ M,
144
+ PathA,
145
+ CookieA,
146
+ QueryA,
147
+ BodyA,
148
+ HeaderA,
149
+ ReqA,
150
+ ResA,
151
+ ResE,
152
+ MiddlewareE,
153
+ R2,
154
+ PR,
155
+ RErr,
156
+ PPath,
157
+ Config
158
+ >(
159
+ requestHandler as any, // one argument if no middleware, 2 if has middleware. TODO: clean this shit up
160
+ errorHandler,
161
+ middlewareLayer
162
+ )
163
+
164
+ const route = HttpRouter.makeRoute(
165
+ requestHandler.Request.method,
166
+ requestHandler.Request.path,
167
+ handler.pipe(
168
+ Effect.withSpan("Request." + requestHandler.name, { captureStackTrace: () => (requestHandler as any).stack })
169
+ )
170
+ )
171
+ // TODO
172
+ // rdesc.push(makeRouteDescriptor(
173
+ // requestHandler.Request.path,
174
+ // requestHandler.Request.method,
175
+ // requestHandler
176
+ // ))
177
+ return route
178
+ }
179
+
180
+ function handle<
181
+ TModule extends Record<
182
+ string,
183
+ any
184
+ >
185
+ >(
186
+ _: TModule & { ResponseOpenApi?: any },
187
+ name: string,
188
+ adaptResponse?: any
189
+ ) {
190
+ const Request = S.REST.extractRequest(_)
191
+ const Response = S.REST.extractResponse(_)
192
+
193
+ type ReqSchema = S.REST.GetRequest<TModule>
194
+ type ResSchema = S.REST.GetResponse<TModule>
195
+ type Req = InstanceType<
196
+ ReqSchema extends { new(...args: any[]): any } ? ReqSchema
197
+ : never
198
+ >
199
+ type Res = S.Schema.Type<Extr<ResSchema>>
200
+
201
+ return <R, E>(
202
+ h: { _tag: "raw" | "d"; handler: (r: Req) => Effect<Res, E, R>; stack?: string }
203
+ ) => ({
204
+ adaptResponse,
205
+ stack: h.stack,
206
+ h: h.handler,
207
+ name,
208
+ Request,
209
+ Response,
210
+ ResponseOpenApi: _.ResponseOpenApi ?? Response,
211
+ Context: null as any,
212
+ CTX: null as any,
213
+ rt: h._tag
214
+ } as ReqHandler<
215
+ Req,
216
+ R,
217
+ E,
218
+ Res,
219
+ ReqSchema,
220
+ ResSchema,
221
+ GetCTX<Req>,
222
+ GetContext<Req>
223
+ >)
224
+ }
225
+
226
+ type RouteMatch<
227
+ R,
228
+ M,
229
+ // TODO: specific failure
230
+ // Err extends SupportedErrors | S.ParseResult.ParseError,
231
+ PR = never
232
+ > // RErr = never,
233
+ = HttpRouter.Route<never, Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>>
234
+
235
+ type HandleVoid<Expected, Actual, Result> = Expected extends void
236
+ ? Actual extends void ? Result : Hint<"You're returning non void for a void Response, please fix">
237
+ : Result
238
+
239
+ function matchFor<Rsc extends Record<string, any>>(
240
+ rsc: Rsc
241
+ ) {
242
+ type Filtered = {
243
+ [K in keyof Rsc as Rsc[K] extends { Response: any } ? K : never]: Rsc[K] extends { Response: any } ? Rsc[K]
244
+ : never
245
+ }
246
+ const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
247
+ if (Predicate.isObject(rsc[cur]) && rsc[cur].Request) {
248
+ acc[cur as keyof Filtered] = rsc[cur]
249
+ }
250
+ return acc
251
+ }, {} as Filtered)
252
+
253
+ const matchWithServices = <Key extends keyof Filtered>(action: Key) => {
254
+ type Req = ReqFromSchema<REST.GetRequest<Rsc[Key]>>
255
+ return <
256
+ SVC extends Record<
257
+ string,
258
+ Effect<any, any, any>
259
+ >,
260
+ R2,
261
+ E,
262
+ A
263
+ >(
264
+ services: SVC,
265
+ f: (
266
+ req: Req,
267
+ ctx: Compute<
268
+ LowerServices<EffectDeps<SVC>> & GetCTX<Req>,
269
+ "flat"
270
+ >
271
+ ) => Effect<A, E, R2>
272
+ ) =>
273
+ (req: any, ctx: any) =>
274
+ Effect.andThen(allLower(services), (svc2) => f(req, { ...ctx, ...svc2, Response: rsc[action].Response }))
275
+ }
276
+
277
+ type MatchWithServicesNew<RT extends "raw" | "d", Key extends keyof Rsc> = {
278
+ <R2, E, A>(
279
+ f: Effect<A, E, R2>
280
+ ): HandleVoid<
281
+ S.Schema.Type<REST.GetResponse<Rsc[Key]>>,
282
+ A,
283
+ Handler<
284
+ Rsc[Key],
285
+ RT,
286
+ A,
287
+ E,
288
+ R2
289
+ >
290
+ >
291
+
292
+ <R2, E, A>(
293
+ f: (
294
+ req: ReqFromSchema<REST.GetRequest<Rsc[Key]>>,
295
+ ctx: GetCTX<REST.GetRequest<Rsc[Key]>> & Pick<Rsc[Key], "Response">
296
+ ) => Effect<A, E, R2>
297
+ ): HandleVoid<
298
+ S.Schema.Type<REST.GetResponse<Rsc[Key]>>,
299
+ A,
300
+ Handler<
301
+ Rsc[Key],
302
+ RT,
303
+ A,
304
+ E,
305
+ R2
306
+ >
307
+ >
308
+
309
+ <
310
+ SVC extends Record<
311
+ string,
312
+ EffectUnunified<any, any, any>
313
+ >,
314
+ R2,
315
+ E,
316
+ A
317
+ >(
318
+ services: SVC,
319
+ f: (
320
+ req: ReqFromSchema<REST.GetRequest<Rsc[Key]>>,
321
+ ctx: Compute<
322
+ LowerServices<EffectDeps<SVC>> & GetCTX<REST.GetRequest<Rsc[Key]>> & Pick<Rsc[Key], "Response">,
323
+ "flat"
324
+ >
325
+ ) => Effect<A, E, R2>
326
+ ): HandleVoid<
327
+ S.Schema.Type<REST.GetResponse<Rsc[Key]>>,
328
+ A,
329
+ Handler<
330
+ Rsc[Key],
331
+ RT,
332
+ A,
333
+ E,
334
+ R2
335
+ >
336
+ >
337
+ }
338
+
339
+ type Keys = keyof Filtered
340
+ type Handler<Action extends AnyRequestModule, RT extends "raw" | "d", A, E, R> = {
341
+ _tag: RT
342
+ handler: (
343
+ req: Action["Request"],
344
+ ctx: Action["Context"]
345
+ ) => Effect<
346
+ A,
347
+ E,
348
+ R
349
+ >
350
+ }
351
+
352
+ type AHandler<Action extends AnyRequestModule> =
353
+ | Handler<
354
+ Action,
355
+ "raw",
356
+ ResRawFromSchema<REST.GetResponse<Action>>,
357
+ SupportedErrors | S.ParseResult.ParseError | S.Schema.Type<Action["failure"]>,
358
+ any
359
+ >
360
+ | Handler<
361
+ Action,
362
+ "d",
363
+ ResFromSchema<REST.GetResponse<Action>>,
364
+ SupportedErrors | S.ParseResult.ParseError | S.Schema.Type<Action["failure"]>,
365
+ any
366
+ >
367
+
368
+ const controllers = <
369
+ THandlers extends {
370
+ // import to keep them separate via | for type checking!!
371
+ [K in Keys]: AHandler<Rsc[K]>
372
+ }
373
+ >(
374
+ controllers: THandlers
375
+ ) => {
376
+ const handlers = typedKeysOf(filtered).reduce(
377
+ (acc, cur) => {
378
+ if (cur === "meta") return acc
379
+ const m = (rsc as any).meta as { moduleName: string }
380
+ if (!m) throw new Error("Resource has no meta specified")
381
+ ;(acc as any)[cur] = handle(
382
+ rsc[cur],
383
+ m.moduleName + "." + (cur as string)
384
+ )(controllers[cur as keyof typeof controllers] as any)
385
+ return acc
386
+ },
387
+ {} as {
388
+ [K in Keys]: ReqHandler<
389
+ ReqFromSchema<REST.GetRequest<Rsc[K]>>,
390
+ _R<ReturnType<THandlers[K]["handler"]>>,
391
+ _E<ReturnType<THandlers[K]["handler"]>>,
392
+ ResFromSchema<REST.GetResponse<Rsc[K]>>,
393
+ REST.GetRequest<Rsc[K]>,
394
+ REST.GetResponse<Rsc[K]>,
395
+ GetCTX<REST.GetRequest<Rsc[K]>>,
396
+ GetContext<REST.GetRequest<Rsc[K]>>
397
+ >
398
+ }
399
+ )
400
+
401
+ const mapped = typedKeysOf(handlers).reduce((acc, cur) => {
402
+ const handler = handlers[cur]
403
+ const req = handler.Request
404
+
405
+ class Request extends (req as any) {
406
+ static path = "/" + handler.name + (req.path === "/" ? "" : req.path)
407
+ static method = req.method === "AUTO"
408
+ ? REST.determineMethod(handler.name.split(".")[1]!, req)
409
+ : req.method
410
+ }
411
+ if (req.method === "AUTO") {
412
+ Object.assign(Request, {
413
+ [Request.method === "GET" || Request.method === "DELETE" ? "Query" : "Body"]: req.Auto
414
+ })
415
+ }
416
+ Object.assign(handler, { Request })
417
+ acc[cur] = match(
418
+ handler as any,
419
+ errorHandler(req),
420
+ handleRequestEnv // TODO
421
+ )
422
+ return acc
423
+ }, {} as any) as {
424
+ [K in Keys]: RouteMatch<
425
+ _R<ReturnType<THandlers[K]["handler"]>>,
426
+ ReqFromSchema<REST.GetRequest<Rsc[K]>>,
427
+ // _E<ReturnType<THandlers[K]["handler"]>>,
428
+ GetContext<REST.GetRequest<Rsc[K]>>
429
+ >
430
+ }
431
+
432
+ type _RRoute<T extends HttpRouter.Route<any, any>> = [T] extends [
433
+ HttpRouter.Route<any, infer R>
434
+ ] ? R
435
+ : never
436
+
437
+ type _ERoute<T extends HttpRouter.Route<any, any>> = [T] extends [
438
+ HttpRouter.Route<infer E, any>
439
+ ] ? E
440
+ : never
441
+
442
+ return HttpRouter.fromIterable(Object.values(mapped)) as HttpRouter.HttpRouter<
443
+ _ERoute<typeof mapped[keyof typeof mapped]>,
444
+ _RRoute<typeof mapped[keyof typeof mapped]>
445
+ >
446
+ }
447
+
448
+ type ResRawFromSchema<ResSchema> = S.Schema.Encoded<Extr<ResSchema>>
449
+
450
+ const r = {
451
+ controllers,
452
+ ...typedKeysOf(filtered).reduce(
453
+ (prev, cur) => {
454
+ ;(prev as any)[cur] = (svcOrFnOrEffect: any, fnOrNone: any) => {
455
+ const stack = new Error().stack?.split("\n").slice(2).join("\n")
456
+ return Effect.isEffect(svcOrFnOrEffect)
457
+ ? class {
458
+ static stack = stack
459
+ static _tag = "d"
460
+ static handler = () => svcOrFnOrEffect
461
+ }
462
+ : typeof svcOrFnOrEffect === "function"
463
+ ? class {
464
+ static stack = stack
465
+ static _tag = "d"
466
+ static handler = (req: any, ctx: any) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].Response })
467
+ }
468
+ : class {
469
+ static stack = stack
470
+ static _tag = "d"
471
+ static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
472
+ }
473
+ }
474
+ ;(prev as any)[(cur as any) + "Raw"] = (svcOrFnOrEffect: any, fnOrNone: any) => {
475
+ const stack = new Error().stack?.split("\n").slice(2).join("\n")
476
+ return Effect.isEffect(svcOrFnOrEffect)
477
+ ? class {
478
+ static stack = stack
479
+ static _tag = "raw"
480
+ static handler = () => svcOrFnOrEffect
481
+ }
482
+ : typeof svcOrFnOrEffect === "function"
483
+ ? class {
484
+ static stack = stack
485
+ static _tag = "raw"
486
+ static handler = (req: any, ctx: any) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].Response })
487
+ }
488
+ : class {
489
+ static stack = stack
490
+ static _tag = "raw"
491
+ static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
492
+ }
493
+ }
494
+ return prev
495
+ },
496
+ {} as
497
+ & {
498
+ // use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
499
+ [Key in keyof Filtered]: MatchWithServicesNew<"d", Key>
500
+ }
501
+ & {
502
+ // use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
503
+ [Key in keyof Filtered as Key extends string ? `${Key}Raw` : never]: MatchWithServicesNew<"raw", Key>
504
+ }
505
+ )
506
+ }
507
+ return r
508
+ }
509
+
510
+ const errorHandler = (resourceRequest: { failure?: S.Schema.AnyNoContext }) => {
511
+ return <R>(
512
+ req: HttpServerRequest.HttpServerRequest,
513
+ res: HttpServerResponse.HttpServerResponse,
514
+ r2: Effect<HttpServerResponse.HttpServerResponse, SupportedErrors | JWTError | S.ParseResult.ParseError, R>
515
+ ) => defaultErrorHandler(req, res, Effect.catchTag(r2, "ParseError", (_) => Effect.die(_)), resourceRequest.failure)
516
+ }
517
+
518
+ /**
519
+ * Gather all handlers of a module and attach them to the Server.
520
+ * If no `allowAnonymous` flag is on the Request, will require a valid authenticated user.
521
+ */
522
+
523
+ function matchAll<T extends RequestHandlersTest>(handlers: T) {
524
+ const r = typedKeysOf(handlers).reduce((acc, cur) => {
525
+ return HttpRouter.concat(acc, handlers[cur] as any)
526
+ }, HttpRouter.empty)
527
+
528
+ type _RRouter<T extends HttpRouter.HttpRouter<any, any>> = [T] extends [
529
+ HttpRouter.HttpRouter<infer R, any>
530
+ ] ? R
531
+ : never
532
+
533
+ type _ERouter<T extends HttpRouter.HttpRouter<any, any>> = [T] extends [
534
+ HttpRouter.HttpRouter<any, infer E>
535
+ ] ? E
536
+ : never
537
+
538
+ return r as HttpRouter.HttpRouter<
539
+ _ERouter<typeof handlers[keyof typeof handlers]>,
540
+ _RRouter<typeof handlers[keyof typeof handlers]>
541
+ >
542
+ }
543
+
544
+ // type SupportedRequestHandler = RequestHandler<
545
+ // any,
546
+ // any,
547
+ // any,
548
+ // any,
549
+ // any,
550
+ // any,
551
+ // any,
552
+ // any,
553
+ // any,
554
+ // SupportedErrors | S.ParseResult.ParseError,
555
+ // any,
556
+ // any,
557
+ // any,
558
+ // any
559
+ // >
560
+
561
+ // type RequestHandlers = { [key: string]: SupportedRequestHandler }
562
+ type RequestHandlersTest = {
563
+ [key: string]: HttpRouter.HttpRouter<any, any>
564
+ }
565
+
566
+ return { matchFor, matchAll }
567
+ }
@@ -0,0 +1,37 @@
1
+ // packages/infra/vitest.config.ts
2
+ import { defineConfig } from "file:///Users/patrickroza/pj/effect-app/libs/node_modules/.pnpm/vite@5.2.6_@types+node@20.11.30/node_modules/vite/dist/node/index.js";
3
+
4
+ // vite.config.base.ts
5
+ import path from "path";
6
+ import fs from "fs";
7
+ var __vite_injected_original_dirname = "/Users/patrickroza/pj/effect-app/libs";
8
+ function makeConfig(dirName) {
9
+ const prefix = path.resolve(__vite_injected_original_dirname, "packages");
10
+ const packages = fs.readdirSync(prefix).map((f) => prefix + "/" + f).filter((f) => fs.lstatSync(f).isDirectory());
11
+ const cfg = {
12
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
13
+ //plugins: [autoImport],
14
+ test: {
15
+ include: ["./test/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
16
+ reporters: "verbose",
17
+ globals: true
18
+ },
19
+ resolve: {
20
+ alias: packages.reduce((acc, cur) => {
21
+ acc[JSON.parse(fs.readFileSync(cur + "/package.json", "utf-8")).name] = path.resolve(cur, cur.endsWith("core") ? "dist" : "src");
22
+ return acc;
23
+ }, {})
24
+ // "@effect-app/core/Prelude": path.join(__dirname, "packages/core/src/Prelude.code.ts")
25
+ }
26
+ };
27
+ console.log(cfg);
28
+ return cfg;
29
+ }
30
+
31
+ // packages/infra/vitest.config.ts
32
+ var __vite_injected_original_dirname2 = "/Users/patrickroza/pj/effect-app/libs/packages/infra";
33
+ var vitest_config_default = defineConfig(makeConfig(__vite_injected_original_dirname2));
34
+ export {
35
+ vitest_config_default as default
36
+ };
37
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50cyIsICJ2aXRlLmNvbmZpZy5iYXNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYS92aXRlc3QuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvcGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gXCJ2aXRlXCJcbmltcG9ydCBtYWtlQ29uZmlnIGZyb20gXCIuLi8uLi92aXRlLmNvbmZpZy5iYXNlXCJcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKG1ha2VDb25maWcoX19kaXJuYW1lKSlcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlic1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy92aXRlLmNvbmZpZy5iYXNlLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvdml0ZS5jb25maWcuYmFzZS50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCJcbmltcG9ydCBmcyBmcm9tIFwiZnNcIlxuaW1wb3J0IEF1dG9JbXBvcnQgZnJvbSBcInVucGx1Z2luLWF1dG8taW1wb3J0L3ZpdGVcIlxuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVzdC9jb25maWdcIlxuXG4vLyBjb25zdCBhdXRvSW1wb3J0ID0gQXV0b0ltcG9ydCh7XG4vLyAgIGR0czogXCIuL3Rlc3QvYXV0by1pbXBvcnRzLmQudHNcIixcbi8vICAgLy8gaW5jbHVkZTogW1xuLy8gICAvLyAgIC9cXC50ZXN0XFwuW3RqXXN4PyQvIC8vIC50cywgLnRzeCwgLmpzLCAuanN4XG4vLyAgIC8vIF0sXG4vLyAgIGltcG9ydHM6IFtcbi8vICAgICBcInZpdGVzdFwiXG4vLyAgIF1cbi8vIH0pXG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG1ha2VDb25maWcoZGlyTmFtZT86IHN0cmluZykge1xuICBjb25zdCBwcmVmaXggPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcInBhY2thZ2VzXCIpXG4gIGNvbnN0IHBhY2thZ2VzID0gZnMucmVhZGRpclN5bmMocHJlZml4KS5tYXAoZiA9PiBwcmVmaXggKyBcIi9cIiArIGYpLmZpbHRlcihmID0+IGZzLmxzdGF0U3luYyhmKS5pc0RpcmVjdG9yeSgpIClcbiAgY29uc3QgY2ZnID0ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzXG4gICAgLy9wbHVnaW5zOiBbYXV0b0ltcG9ydF0sXG4gICAgdGVzdDoge1xuICAgICAgaW5jbHVkZTogIFtcIi4vdGVzdC8qKi8qLnRlc3Que2pzLG1qcyxjanMsdHMsbXRzLGN0cyxqc3gsdHN4fVwiXSxcbiAgICAgIHJlcG9ydGVyczogXCJ2ZXJib3NlXCIsXG4gICAgICBnbG9iYWxzOiB0cnVlXG4gICAgfSxcbiAgICByZXNvbHZlOiB7XG4gICAgICBhbGlhczogcGFja2FnZXMucmVkdWNlKChhY2MsIGN1cikgPT4geyAvLyB3b3JrYXJvdW5kIGZvciAvUHJlbHVkZSBpc3N1ZVxuICAgICAgYWNjW0pTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGN1ciArIFwiL3BhY2thZ2UuanNvblwiLCBcInV0Zi04XCIpKS5uYW1lXSA9IHBhdGgucmVzb2x2ZShjdXIsIGN1ci5lbmRzV2l0aChcImNvcmVcIikgPyBcImRpc3RcIiA6IFwic3JjXCIpXG4gICAgICByZXR1cm4gYWNjXG4gICAgfSwgeyB9KSAvLyBcIkBlZmZlY3QtYXBwL2NvcmUvUHJlbHVkZVwiOiBwYXRoLmpvaW4oX19kaXJuYW1lLCBcInBhY2thZ2VzL2NvcmUvc3JjL1ByZWx1ZGUuY29kZS50c1wiKVxuICB9XG4gIH1cbiAgY29uc29sZS5sb2coY2ZnKVxuICByZXR1cm4gY2ZnXG59XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQ0EsU0FBUyxvQkFBb0I7OztBQ0E3QixPQUFPLFVBQVU7QUFDakIsT0FBTyxRQUFRO0FBRmYsSUFBTSxtQ0FBbUM7QUFnQjFCLFNBQVIsV0FBNEIsU0FBa0I7QUFDbkQsUUFBTSxTQUFTLEtBQUssUUFBUSxrQ0FBVyxVQUFVO0FBQ2pELFFBQU0sV0FBVyxHQUFHLFlBQVksTUFBTSxFQUFFLElBQUksT0FBSyxTQUFTLE1BQU0sQ0FBQyxFQUFFLE9BQU8sT0FBSyxHQUFHLFVBQVUsQ0FBQyxFQUFFLFlBQVksQ0FBRTtBQUM3RyxRQUFNLE1BQU07QUFBQTtBQUFBO0FBQUEsSUFHVixNQUFNO0FBQUEsTUFDSixTQUFVLENBQUMsa0RBQWtEO0FBQUEsTUFDN0QsV0FBVztBQUFBLE1BQ1gsU0FBUztBQUFBLElBQ1g7QUFBQSxJQUNBLFNBQVM7QUFBQSxNQUNQLE9BQU8sU0FBUyxPQUFPLENBQUMsS0FBSyxRQUFRO0FBQ3JDLFlBQUksS0FBSyxNQUFNLEdBQUcsYUFBYSxNQUFNLGlCQUFpQixPQUFPLENBQUMsRUFBRSxJQUFJLElBQUksS0FBSyxRQUFRLEtBQUssSUFBSSxTQUFTLE1BQU0sSUFBSSxTQUFTLEtBQUs7QUFDL0gsZUFBTztBQUFBLE1BQ1QsR0FBRyxDQUFFLENBQUM7QUFBQTtBQUFBLElBQ1I7QUFBQSxFQUNBO0FBQ0EsVUFBUSxJQUFJLEdBQUc7QUFDZixTQUFPO0FBQ1Q7OztBRHBDQSxJQUFNQSxvQ0FBbUM7QUFJekMsSUFBTyx3QkFBUSxhQUFhLFdBQVdDLGlDQUFTLENBQUM7IiwKICAibmFtZXMiOiBbIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIiwgIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIl0KfQo=