@effect/platform 0.68.6 → 0.69.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/HttpApiMiddleware/package.json +6 -0
- package/README.md +306 -233
- package/dist/cjs/Headers.js +7 -2
- package/dist/cjs/Headers.js.map +1 -1
- package/dist/cjs/HttpApi.js +90 -78
- package/dist/cjs/HttpApi.js.map +1 -1
- package/dist/cjs/HttpApiBuilder.js +245 -255
- package/dist/cjs/HttpApiBuilder.js.map +1 -1
- package/dist/cjs/HttpApiClient.js +64 -59
- package/dist/cjs/HttpApiClient.js.map +1 -1
- package/dist/cjs/HttpApiEndpoint.js +74 -109
- package/dist/cjs/HttpApiEndpoint.js.map +1 -1
- package/dist/cjs/HttpApiError.js +3 -4
- package/dist/cjs/HttpApiError.js.map +1 -1
- package/dist/cjs/HttpApiGroup.js +103 -100
- package/dist/cjs/HttpApiGroup.js.map +1 -1
- package/dist/cjs/HttpApiMiddleware.js +67 -0
- package/dist/cjs/HttpApiMiddleware.js.map +1 -0
- package/dist/cjs/HttpApiSchema.js +33 -7
- package/dist/cjs/HttpApiSchema.js.map +1 -1
- package/dist/cjs/HttpApiSecurity.js +2 -2
- package/dist/cjs/HttpApiSecurity.js.map +1 -1
- package/dist/cjs/HttpApiSwagger.js +3 -1
- package/dist/cjs/HttpApiSwagger.js.map +1 -1
- package/dist/cjs/HttpBody.js.map +1 -1
- package/dist/cjs/HttpIncomingMessage.js +5 -1
- package/dist/cjs/HttpIncomingMessage.js.map +1 -1
- package/dist/cjs/HttpServer.js +12 -1
- package/dist/cjs/HttpServer.js.map +1 -1
- package/dist/cjs/HttpServerRespondable.js +1 -1
- package/dist/cjs/HttpServerRespondable.js.map +1 -1
- package/dist/cjs/OpenApi.js +102 -63
- package/dist/cjs/OpenApi.js.map +1 -1
- package/dist/cjs/OpenApiJsonSchema.js +58 -47
- package/dist/cjs/OpenApiJsonSchema.js.map +1 -1
- package/dist/cjs/Transferable.js +2 -2
- package/dist/cjs/Transferable.js.map +1 -1
- package/dist/cjs/UrlParams.js +5 -1
- package/dist/cjs/UrlParams.js.map +1 -1
- package/dist/cjs/Worker.js.map +1 -1
- package/dist/cjs/WorkerError.js +1 -5
- package/dist/cjs/WorkerError.js.map +1 -1
- package/dist/cjs/WorkerRunner.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internal/httpBody.js +1 -1
- package/dist/cjs/internal/httpBody.js.map +1 -1
- package/dist/cjs/internal/httpClientRequest.js.map +1 -1
- package/dist/cjs/internal/httpClientResponse.js +1 -1
- package/dist/cjs/internal/httpClientResponse.js.map +1 -1
- package/dist/cjs/internal/httpRouter.js +1 -1
- package/dist/cjs/internal/httpRouter.js.map +1 -1
- package/dist/cjs/internal/httpServer.js +7 -1
- package/dist/cjs/internal/httpServer.js.map +1 -1
- package/dist/cjs/internal/httpServerRequest.js +1 -1
- package/dist/cjs/internal/httpServerRequest.js.map +1 -1
- package/dist/cjs/internal/httpServerResponse.js.map +1 -1
- package/dist/cjs/internal/keyValueStore.js +1 -1
- package/dist/cjs/internal/keyValueStore.js.map +1 -1
- package/dist/cjs/internal/multipart.js +1 -1
- package/dist/cjs/internal/multipart.js.map +1 -1
- package/dist/cjs/internal/worker.js +6 -7
- package/dist/cjs/internal/worker.js.map +1 -1
- package/dist/cjs/internal/workerRunner.js +3 -4
- package/dist/cjs/internal/workerRunner.js.map +1 -1
- package/dist/dts/Headers.d.ts +4 -6
- package/dist/dts/Headers.d.ts.map +1 -1
- package/dist/dts/HttpApi.d.ts +64 -140
- package/dist/dts/HttpApi.d.ts.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts +86 -167
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/HttpApiClient.d.ts +34 -11
- package/dist/dts/HttpApiClient.d.ts.map +1 -1
- package/dist/dts/HttpApiEndpoint.d.ts +119 -273
- package/dist/dts/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/dts/HttpApiError.d.ts +5 -2
- package/dist/dts/HttpApiError.d.ts.map +1 -1
- package/dist/dts/HttpApiGroup.d.ts +96 -194
- package/dist/dts/HttpApiGroup.d.ts.map +1 -1
- package/dist/dts/HttpApiMiddleware.d.ts +228 -0
- package/dist/dts/HttpApiMiddleware.d.ts.map +1 -0
- package/dist/dts/HttpApiSchema.d.ts +6 -2
- package/dist/dts/HttpApiSchema.d.ts.map +1 -1
- package/dist/dts/HttpApiSecurity.d.ts +1 -1
- package/dist/dts/HttpApiSecurity.d.ts.map +1 -1
- package/dist/dts/HttpApiSwagger.d.ts +2 -2
- package/dist/dts/HttpApiSwagger.d.ts.map +1 -1
- package/dist/dts/HttpBody.d.ts +2 -2
- package/dist/dts/HttpBody.d.ts.map +1 -1
- package/dist/dts/HttpClientRequest.d.ts +2 -2
- package/dist/dts/HttpClientRequest.d.ts.map +1 -1
- package/dist/dts/HttpClientResponse.d.ts +3 -3
- package/dist/dts/HttpClientResponse.d.ts.map +1 -1
- package/dist/dts/HttpIncomingMessage.d.ts +3 -3
- package/dist/dts/HttpIncomingMessage.d.ts.map +1 -1
- package/dist/dts/HttpRouter.d.ts +3 -3
- package/dist/dts/HttpRouter.d.ts.map +1 -1
- package/dist/dts/HttpServer.d.ts +15 -0
- package/dist/dts/HttpServer.d.ts.map +1 -1
- package/dist/dts/HttpServerRequest.d.ts +3 -3
- package/dist/dts/HttpServerRequest.d.ts.map +1 -1
- package/dist/dts/HttpServerRespondable.d.ts.map +1 -1
- package/dist/dts/HttpServerResponse.d.ts +2 -2
- package/dist/dts/HttpServerResponse.d.ts.map +1 -1
- package/dist/dts/KeyValueStore.d.ts +2 -2
- package/dist/dts/KeyValueStore.d.ts.map +1 -1
- package/dist/dts/Multipart.d.ts +3 -3
- package/dist/dts/Multipart.d.ts.map +1 -1
- package/dist/dts/OpenApi.d.ts +17 -39
- package/dist/dts/OpenApi.d.ts.map +1 -1
- package/dist/dts/OpenApiJsonSchema.d.ts +10 -5
- package/dist/dts/OpenApiJsonSchema.d.ts.map +1 -1
- package/dist/dts/Transferable.d.ts +4 -1
- package/dist/dts/Transferable.d.ts.map +1 -1
- package/dist/dts/UrlParams.d.ts +3 -6
- package/dist/dts/UrlParams.d.ts.map +1 -1
- package/dist/dts/Worker.d.ts +7 -8
- package/dist/dts/Worker.d.ts.map +1 -1
- package/dist/dts/WorkerError.d.ts +1 -1
- package/dist/dts/WorkerError.d.ts.map +1 -1
- package/dist/dts/WorkerRunner.d.ts +2 -3
- package/dist/dts/WorkerRunner.d.ts.map +1 -1
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/httpRouter.d.ts.map +1 -1
- package/dist/esm/Headers.js +7 -2
- package/dist/esm/Headers.js.map +1 -1
- package/dist/esm/HttpApi.js +88 -77
- package/dist/esm/HttpApi.js.map +1 -1
- package/dist/esm/HttpApiBuilder.js +238 -244
- package/dist/esm/HttpApiBuilder.js.map +1 -1
- package/dist/esm/HttpApiClient.js +64 -59
- package/dist/esm/HttpApiClient.js.map +1 -1
- package/dist/esm/HttpApiEndpoint.js +73 -106
- package/dist/esm/HttpApiEndpoint.js.map +1 -1
- package/dist/esm/HttpApiError.js +3 -4
- package/dist/esm/HttpApiError.js.map +1 -1
- package/dist/esm/HttpApiGroup.js +102 -99
- package/dist/esm/HttpApiGroup.js.map +1 -1
- package/dist/esm/HttpApiMiddleware.js +56 -0
- package/dist/esm/HttpApiMiddleware.js.map +1 -0
- package/dist/esm/HttpApiSchema.js +31 -5
- package/dist/esm/HttpApiSchema.js.map +1 -1
- package/dist/esm/HttpApiSecurity.js +1 -1
- package/dist/esm/HttpApiSecurity.js.map +1 -1
- package/dist/esm/HttpApiSwagger.js +4 -2
- package/dist/esm/HttpApiSwagger.js.map +1 -1
- package/dist/esm/HttpBody.js.map +1 -1
- package/dist/esm/HttpIncomingMessage.js +4 -1
- package/dist/esm/HttpIncomingMessage.js.map +1 -1
- package/dist/esm/HttpServer.js +11 -0
- package/dist/esm/HttpServer.js.map +1 -1
- package/dist/esm/HttpServerRespondable.js +1 -1
- package/dist/esm/HttpServerRespondable.js.map +1 -1
- package/dist/esm/OpenApi.js +97 -59
- package/dist/esm/OpenApi.js.map +1 -1
- package/dist/esm/OpenApiJsonSchema.js +56 -46
- package/dist/esm/OpenApiJsonSchema.js.map +1 -1
- package/dist/esm/Transferable.js +2 -2
- package/dist/esm/Transferable.js.map +1 -1
- package/dist/esm/UrlParams.js +4 -1
- package/dist/esm/UrlParams.js.map +1 -1
- package/dist/esm/Worker.js.map +1 -1
- package/dist/esm/WorkerError.js +1 -4
- package/dist/esm/WorkerError.js.map +1 -1
- package/dist/esm/WorkerRunner.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/httpBody.js +1 -1
- package/dist/esm/internal/httpBody.js.map +1 -1
- package/dist/esm/internal/httpClientRequest.js.map +1 -1
- package/dist/esm/internal/httpClientResponse.js +1 -1
- package/dist/esm/internal/httpClientResponse.js.map +1 -1
- package/dist/esm/internal/httpRouter.js +1 -1
- package/dist/esm/internal/httpRouter.js.map +1 -1
- package/dist/esm/internal/httpServer.js +6 -0
- package/dist/esm/internal/httpServer.js.map +1 -1
- package/dist/esm/internal/httpServerRequest.js +1 -1
- package/dist/esm/internal/httpServerRequest.js.map +1 -1
- package/dist/esm/internal/httpServerResponse.js.map +1 -1
- package/dist/esm/internal/keyValueStore.js +1 -1
- package/dist/esm/internal/keyValueStore.js.map +1 -1
- package/dist/esm/internal/multipart.js +1 -1
- package/dist/esm/internal/multipart.js.map +1 -1
- package/dist/esm/internal/worker.js +6 -7
- package/dist/esm/internal/worker.js.map +1 -1
- package/dist/esm/internal/workerRunner.js +3 -4
- package/dist/esm/internal/workerRunner.js.map +1 -1
- package/package.json +10 -3
- package/src/Headers.ts +12 -4
- package/src/HttpApi.ts +183 -258
- package/src/HttpApiBuilder.ts +534 -481
- package/src/HttpApiClient.ts +163 -112
- package/src/HttpApiEndpoint.ts +443 -564
- package/src/HttpApiError.ts +4 -6
- package/src/HttpApiGroup.ts +277 -325
- package/src/HttpApiMiddleware.ts +317 -0
- package/src/HttpApiSchema.ts +39 -2
- package/src/HttpApiSecurity.ts +1 -1
- package/src/HttpApiSwagger.ts +3 -3
- package/src/HttpBody.ts +2 -2
- package/src/HttpClientRequest.ts +2 -2
- package/src/HttpClientResponse.ts +3 -3
- package/src/HttpIncomingMessage.ts +3 -3
- package/src/HttpRouter.ts +3 -3
- package/src/HttpServer.ts +21 -0
- package/src/HttpServerRequest.ts +3 -3
- package/src/HttpServerRespondable.ts +1 -1
- package/src/HttpServerResponse.ts +2 -2
- package/src/KeyValueStore.ts +2 -2
- package/src/Multipart.ts +3 -3
- package/src/OpenApi.ts +113 -104
- package/src/OpenApiJsonSchema.ts +67 -53
- package/src/Transferable.ts +2 -2
- package/src/UrlParams.ts +3 -3
- package/src/Worker.ts +7 -8
- package/src/WorkerError.ts +1 -1
- package/src/WorkerRunner.ts +2 -3
- package/src/index.ts +5 -0
- package/src/internal/httpBody.ts +2 -2
- package/src/internal/httpClientRequest.ts +2 -2
- package/src/internal/httpClientResponse.ts +3 -3
- package/src/internal/httpRouter.ts +2 -2
- package/src/internal/httpServer.ts +13 -0
- package/src/internal/httpServerRequest.ts +3 -3
- package/src/internal/httpServerResponse.ts +2 -2
- package/src/internal/keyValueStore.ts +1 -1
- package/src/internal/multipart.ts +3 -3
- package/src/internal/worker.ts +6 -7
- package/src/internal/workerRunner.ts +3 -4
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import * as AST from "@effect/schema/AST";
|
|
5
|
-
import * as ParseResult from "@effect/schema/ParseResult";
|
|
6
|
-
import * as Schema from "@effect/schema/Schema";
|
|
7
4
|
import * as Chunk from "effect/Chunk";
|
|
8
5
|
import * as Context from "effect/Context";
|
|
9
6
|
import * as Effect from "effect/Effect";
|
|
@@ -11,14 +8,19 @@ import * as Encoding from "effect/Encoding";
|
|
|
11
8
|
import * as FiberRef from "effect/FiberRef";
|
|
12
9
|
import { identity } from "effect/Function";
|
|
13
10
|
import { globalValue } from "effect/GlobalValue";
|
|
11
|
+
import * as HashMap from "effect/HashMap";
|
|
12
|
+
import * as HashSet from "effect/HashSet";
|
|
14
13
|
import * as Layer from "effect/Layer";
|
|
14
|
+
import * as ManagedRuntime from "effect/ManagedRuntime";
|
|
15
15
|
import * as Option from "effect/Option";
|
|
16
|
+
import * as ParseResult from "effect/ParseResult";
|
|
16
17
|
import { pipeArguments } from "effect/Pipeable";
|
|
17
18
|
import * as Redacted from "effect/Redacted";
|
|
19
|
+
import * as Schema from "effect/Schema";
|
|
18
20
|
import { unify } from "effect/Unify";
|
|
19
21
|
import * as HttpApi from "./HttpApi.js";
|
|
20
|
-
import * as HttpApiEndpoint from "./HttpApiEndpoint.js";
|
|
21
22
|
import { HttpApiDecodeError } from "./HttpApiError.js";
|
|
23
|
+
import * as HttpApiMiddleware from "./HttpApiMiddleware.js";
|
|
22
24
|
import * as HttpApiSchema from "./HttpApiSchema.js";
|
|
23
25
|
import * as HttpApp from "./HttpApp.js";
|
|
24
26
|
import * as HttpMethod from "./HttpMethod.js";
|
|
@@ -35,6 +37,16 @@ import * as OpenApi from "./OpenApi.js";
|
|
|
35
37
|
* @category router
|
|
36
38
|
*/
|
|
37
39
|
export class Router extends /*#__PURE__*/HttpRouter.Tag("@effect/platform/HttpApiBuilder/Router")() {}
|
|
40
|
+
/**
|
|
41
|
+
* Create a top-level `HttpApi` layer.
|
|
42
|
+
*
|
|
43
|
+
* @since 1.0.0
|
|
44
|
+
* @category constructors
|
|
45
|
+
*/
|
|
46
|
+
export const api = api => Layer.effect(HttpApi.Api, Effect.map(Effect.context(), context => ({
|
|
47
|
+
api: api,
|
|
48
|
+
context
|
|
49
|
+
})));
|
|
38
50
|
/**
|
|
39
51
|
* Build an `HttpApp` from an `HttpApi` instance, and serve it using an
|
|
40
52
|
* `HttpServer`.
|
|
@@ -45,7 +57,7 @@ export class Router extends /*#__PURE__*/HttpRouter.Tag("@effect/platform/HttpAp
|
|
|
45
57
|
* @since 1.0.0
|
|
46
58
|
* @category constructors
|
|
47
59
|
*/
|
|
48
|
-
export const serve = middleware => httpApp.pipe(Effect.map(HttpServer.serve(middleware)), Layer.unwrapEffect, Layer.provide(Router.Live));
|
|
60
|
+
export const serve = middleware => httpApp.pipe(Effect.map(app => HttpServer.serve(app, middleware)), Layer.unwrapEffect, Layer.provide(Router.Live));
|
|
49
61
|
/**
|
|
50
62
|
* Construct an `HttpApp` from an `HttpApi` instance.
|
|
51
63
|
*
|
|
@@ -53,12 +65,16 @@ export const serve = middleware => httpApp.pipe(Effect.map(HttpServer.serve(midd
|
|
|
53
65
|
* @category constructors
|
|
54
66
|
*/
|
|
55
67
|
export const httpApp = /*#__PURE__*/Effect.gen(function* () {
|
|
56
|
-
const
|
|
57
|
-
|
|
68
|
+
const {
|
|
69
|
+
api,
|
|
70
|
+
context
|
|
71
|
+
} = yield* HttpApi.Api;
|
|
72
|
+
const middleware = makeMiddlewareMap(api.middlewares, context);
|
|
73
|
+
const router = applyMiddleware(middleware, yield* Router.router);
|
|
58
74
|
const apiMiddleware = yield* Effect.serviceOption(Middleware);
|
|
59
75
|
const errorSchema = makeErrorSchema(api);
|
|
60
76
|
const encodeError = Schema.encodeUnknown(errorSchema);
|
|
61
|
-
return router.pipe(apiMiddleware._tag === "Some" ? apiMiddleware.value : identity, Effect.catchAll(error => Effect.matchEffect(encodeError(error), {
|
|
77
|
+
return router.pipe(apiMiddleware._tag === "Some" ? apiMiddleware.value : identity, Effect.catchAll(error => Effect.matchEffect(Effect.provide(encodeError(error), context), {
|
|
62
78
|
onFailure: () => Effect.die(error),
|
|
63
79
|
onSuccess: Effect.succeed
|
|
64
80
|
})));
|
|
@@ -69,45 +85,42 @@ export const httpApp = /*#__PURE__*/Effect.gen(function* () {
|
|
|
69
85
|
* @since 1.0.0
|
|
70
86
|
* @category constructors
|
|
71
87
|
* @example
|
|
72
|
-
* import { HttpApi } from "@effect/platform"
|
|
73
|
-
* import {
|
|
74
|
-
*
|
|
75
|
-
*
|
|
88
|
+
* import { HttpApi, HttpApiBuilder, HttpServer } from "@effect/platform"
|
|
89
|
+
* import { Layer } from "effect"
|
|
90
|
+
*
|
|
91
|
+
* class MyApi extends HttpApi.empty {}
|
|
76
92
|
*
|
|
77
|
-
* const
|
|
93
|
+
* const MyApiLive = HttpApiBuilder.api(MyApi)
|
|
78
94
|
*
|
|
79
|
-
* const
|
|
95
|
+
* const { dispose, handler } = HttpApiBuilder.toWebHandler(
|
|
80
96
|
* Layer.mergeAll(
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* ).pipe(
|
|
86
|
-
* Layer.provideMerge(NodeContext.layer)
|
|
97
|
+
* MyApiLive,
|
|
98
|
+
* // you could also use NodeHttpServer.layerContext, depending on your
|
|
99
|
+
* // server's platform
|
|
100
|
+
* HttpServer.layerContext
|
|
87
101
|
* )
|
|
88
102
|
* )
|
|
89
|
-
*
|
|
90
|
-
* const handler = HttpApiBuilder.toWebHandler(runtime, HttpMiddleware.logger)
|
|
91
103
|
*/
|
|
92
|
-
export const toWebHandler = (
|
|
104
|
+
export const toWebHandler = (layer, options) => {
|
|
105
|
+
const runtime = ManagedRuntime.make(Layer.merge(layer, Router.Live), options?.memoMap);
|
|
106
|
+
let handlerCached;
|
|
93
107
|
const handlerPromise = httpApp.pipe(Effect.bindTo("httpApp"), Effect.bind("runtime", () => runtime.runtimeEffect), Effect.map(({
|
|
94
108
|
httpApp,
|
|
95
109
|
runtime
|
|
96
|
-
}) => HttpApp.toWebHandlerRuntime(runtime)(middleware ? middleware(httpApp) : httpApp)),
|
|
97
|
-
|
|
110
|
+
}) => HttpApp.toWebHandlerRuntime(runtime)(options?.middleware ? options.middleware(httpApp) : httpApp)), Effect.tap(handler => {
|
|
111
|
+
handlerCached = handler;
|
|
112
|
+
}), runtime.runPromise);
|
|
113
|
+
function handler(request) {
|
|
114
|
+
if (handlerCached !== undefined) {
|
|
115
|
+
return handlerCached(request);
|
|
116
|
+
}
|
|
117
|
+
return handlerPromise.then(handler => handler(request));
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
handler,
|
|
121
|
+
dispose: runtime.dispose
|
|
122
|
+
};
|
|
98
123
|
};
|
|
99
|
-
/**
|
|
100
|
-
* Build a root level `Layer` from an `HttpApi` instance.
|
|
101
|
-
*
|
|
102
|
-
* The `Layer` will provide the `HttpApi` service, and will require the
|
|
103
|
-
* implementation for all the `HttpApiGroup`'s contained in the `HttpApi`.
|
|
104
|
-
*
|
|
105
|
-
* The resulting `Layer` can be provided to the `HttpApiBuilder.serve` layer.
|
|
106
|
-
*
|
|
107
|
-
* @since 1.0.0
|
|
108
|
-
* @category constructors
|
|
109
|
-
*/
|
|
110
|
-
export const api = self => Layer.succeed(HttpApi.HttpApi, self);
|
|
111
124
|
/**
|
|
112
125
|
* @since 1.0.0
|
|
113
126
|
* @category handlers
|
|
@@ -119,6 +132,28 @@ const HandlersProto = {
|
|
|
119
132
|
},
|
|
120
133
|
pipe() {
|
|
121
134
|
return pipeArguments(this, arguments);
|
|
135
|
+
},
|
|
136
|
+
handle(name, handler) {
|
|
137
|
+
const endpoint = HashMap.unsafeGet(this.group.endpoints, name);
|
|
138
|
+
return makeHandlers({
|
|
139
|
+
group: this.group,
|
|
140
|
+
handlers: Chunk.append(this.handlers, {
|
|
141
|
+
endpoint,
|
|
142
|
+
handler,
|
|
143
|
+
withFullResponse: false
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
handleRaw(name, handler) {
|
|
148
|
+
const endpoint = HashMap.unsafeGet(this.group.endpoints, name);
|
|
149
|
+
return makeHandlers({
|
|
150
|
+
group: this.group,
|
|
151
|
+
handlers: Chunk.append(this.handlers, {
|
|
152
|
+
endpoint,
|
|
153
|
+
handler,
|
|
154
|
+
withFullResponse: true
|
|
155
|
+
})
|
|
156
|
+
});
|
|
122
157
|
}
|
|
123
158
|
};
|
|
124
159
|
const makeHandlers = options => {
|
|
@@ -128,81 +163,186 @@ const makeHandlers = options => {
|
|
|
128
163
|
return self;
|
|
129
164
|
};
|
|
130
165
|
/**
|
|
131
|
-
* Create a `Layer` that will implement all the endpoints in an `
|
|
166
|
+
* Create a `Layer` that will implement all the endpoints in an `HttpApi`.
|
|
132
167
|
*
|
|
133
168
|
* An unimplemented `Handlers` instance is passed to the `build` function, which
|
|
134
169
|
* you can use to add handlers to the group.
|
|
135
170
|
*
|
|
136
|
-
* You can implement endpoints using the `
|
|
171
|
+
* You can implement endpoints using the `handlers.handle` api.
|
|
137
172
|
*
|
|
138
173
|
* @since 1.0.0
|
|
139
174
|
* @category handlers
|
|
140
175
|
*/
|
|
141
176
|
export const group = (api, groupName, build) => Router.use(router => Effect.gen(function* () {
|
|
142
177
|
const context = yield* Effect.context();
|
|
143
|
-
const group =
|
|
144
|
-
if (group._tag === "None") {
|
|
145
|
-
throw new Error(`Group "${groupName}" not found in API`);
|
|
146
|
-
}
|
|
178
|
+
const group = HashMap.unsafeGet(api.groups, groupName);
|
|
147
179
|
const result = build(makeHandlers({
|
|
148
|
-
group
|
|
180
|
+
group,
|
|
149
181
|
handlers: Chunk.empty()
|
|
150
182
|
}));
|
|
151
183
|
const handlers = Effect.isEffect(result) ? yield* result : result;
|
|
184
|
+
const groupMiddleware = makeMiddlewareMap(group.middlewares, context);
|
|
152
185
|
const routes = [];
|
|
153
186
|
for (const item of handlers.handlers) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
187
|
+
const middleware = makeMiddlewareMap(item.endpoint.middlewares, context, groupMiddleware);
|
|
188
|
+
routes.push(handlerToRoute(item.endpoint, middleware, function (request) {
|
|
189
|
+
return Effect.mapInputContext(item.handler(request), input => Context.merge(context, input));
|
|
190
|
+
}, item.withFullResponse));
|
|
191
|
+
}
|
|
192
|
+
yield* router.concat(HttpRouter.fromIterable(routes));
|
|
193
|
+
}));
|
|
194
|
+
// internal
|
|
195
|
+
const requestPayload = (request, urlParams, isMultipart) => HttpMethod.hasBody(request.method) ? isMultipart ? Effect.orDie(request.multipart) : Effect.orDie(request.json) : Effect.succeed(urlParams);
|
|
196
|
+
const makeMiddlewareMap = (middleware, context, initial) => {
|
|
197
|
+
const map = new Map(initial);
|
|
198
|
+
HashSet.forEach(middleware, tag => {
|
|
199
|
+
map.set(tag.key, {
|
|
200
|
+
tag,
|
|
201
|
+
effect: Context.unsafeGet(context, tag)
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
return map;
|
|
205
|
+
};
|
|
206
|
+
const handlerToRoute = (endpoint_, middleware, handler, isFullResponse) => {
|
|
207
|
+
const endpoint = endpoint_;
|
|
208
|
+
const decodePath = Option.map(endpoint.pathSchema, Schema.decodeUnknown);
|
|
209
|
+
const isMultipart = endpoint.payloadSchema.pipe(Option.map(schema => HttpApiSchema.getMultipart(schema.ast)), Option.getOrElse(() => false));
|
|
210
|
+
const decodePayload = Option.map(endpoint.payloadSchema, Schema.decodeUnknown);
|
|
211
|
+
const decodeHeaders = Option.map(endpoint.headersSchema, Schema.decodeUnknown);
|
|
212
|
+
const decodeUrlParams = Option.map(endpoint.urlParamsSchema, Schema.decodeUnknown);
|
|
213
|
+
const encodeSuccess = Schema.encode(makeSuccessSchema(endpoint.successSchema));
|
|
214
|
+
return HttpRouter.makeRoute(endpoint.method, endpoint.path, applyMiddleware(middleware, Effect.withFiberRuntime(fiber => {
|
|
215
|
+
const context = fiber.getFiberRef(FiberRef.currentContext);
|
|
216
|
+
const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest);
|
|
217
|
+
const routeContext = Context.unsafeGet(context, HttpRouter.RouteContext);
|
|
218
|
+
const urlParams = Context.unsafeGet(context, HttpServerRequest.ParsedSearchParams);
|
|
219
|
+
return (decodePath._tag === "Some" ? decodePath.value(routeContext.params) : Effect.succeed(routeContext.params)).pipe(Effect.bindTo("pathParams"), decodePayload._tag === "Some" ? Effect.bind("payload", _ => Effect.flatMap(requestPayload(request, urlParams, isMultipart), decodePayload.value)) : identity, decodeHeaders._tag === "Some" ? Effect.bind("headers", _ => decodeHeaders.value(request.headers)) : identity, decodeUrlParams._tag === "Some" ? Effect.bind("urlParams", _ => decodeUrlParams.value(urlParams)) : identity, Effect.flatMap(input => {
|
|
220
|
+
const request = {
|
|
221
|
+
path: input.pathParams
|
|
222
|
+
};
|
|
223
|
+
if ("payload" in input) {
|
|
224
|
+
request.payload = input.payload;
|
|
225
|
+
}
|
|
226
|
+
if ("headers" in input) {
|
|
227
|
+
request.headers = input.headers;
|
|
228
|
+
}
|
|
229
|
+
if ("urlParams" in input) {
|
|
230
|
+
request.urlParams = input.urlParams;
|
|
158
231
|
}
|
|
232
|
+
return handler(request);
|
|
233
|
+
}), isFullResponse ? identity : Effect.flatMap(encodeSuccess), Effect.catchIf(ParseResult.isParseError, HttpApiDecodeError.refailParseError));
|
|
234
|
+
})));
|
|
235
|
+
};
|
|
236
|
+
const applyMiddleware = (middleware, handler) => {
|
|
237
|
+
for (const entry of middleware.values()) {
|
|
238
|
+
const effect = HttpApiMiddleware.SecurityTypeId in entry.tag ? makeSecurityMiddleware(entry) : entry.effect;
|
|
239
|
+
if (entry.tag.optional) {
|
|
240
|
+
const previous = handler;
|
|
241
|
+
handler = Effect.matchEffect(effect, {
|
|
242
|
+
onFailure: () => previous,
|
|
243
|
+
onSuccess: entry.tag.provides !== undefined ? value => Effect.provideService(previous, entry.tag.provides, value) : _ => previous
|
|
244
|
+
});
|
|
159
245
|
} else {
|
|
160
|
-
|
|
161
|
-
return Effect.mapInputContext(item.handler(request), input => Context.merge(context, input));
|
|
162
|
-
}, item.withFullResponse));
|
|
246
|
+
handler = entry.tag.provides !== undefined ? Effect.provideServiceEffect(handler, entry.tag.provides, effect) : Effect.zipRight(effect, handler);
|
|
163
247
|
}
|
|
164
248
|
}
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
249
|
+
return handler;
|
|
250
|
+
};
|
|
251
|
+
const securityMiddlewareCache = /*#__PURE__*/globalValue("securityMiddlewareCache", () => new WeakMap());
|
|
252
|
+
const makeSecurityMiddleware = entry => {
|
|
253
|
+
if (securityMiddlewareCache.has(entry.tag)) {
|
|
254
|
+
return securityMiddlewareCache.get(entry.tag);
|
|
255
|
+
}
|
|
256
|
+
let effect;
|
|
257
|
+
for (const [key, security] of Object.entries(entry.tag.security)) {
|
|
258
|
+
const decode = securityDecode(security);
|
|
259
|
+
const handler = entry.effect[key];
|
|
260
|
+
const middleware = Effect.flatMap(decode, handler);
|
|
261
|
+
effect = effect === undefined ? middleware : Effect.catchAll(effect, () => middleware);
|
|
177
262
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
263
|
+
if (effect === undefined) {
|
|
264
|
+
effect = Effect.void;
|
|
265
|
+
}
|
|
266
|
+
securityMiddlewareCache.set(entry.tag, effect);
|
|
267
|
+
return effect;
|
|
268
|
+
};
|
|
269
|
+
const responseSchema = /*#__PURE__*/Schema.declare(HttpServerResponse.isServerResponse);
|
|
270
|
+
const makeSuccessSchema = schema => {
|
|
271
|
+
const schemas = new Set();
|
|
272
|
+
HttpApiSchema.deunionize(schemas, schema);
|
|
273
|
+
return Schema.Union(...Array.from(schemas, toResponseSuccess));
|
|
274
|
+
};
|
|
275
|
+
const makeErrorSchema = api => {
|
|
276
|
+
const schemas = new Set();
|
|
277
|
+
HttpApiSchema.deunionize(schemas, api.errorSchema);
|
|
278
|
+
HashMap.forEach(api.groups, group => {
|
|
279
|
+
HashMap.forEach(group.endpoints, endpoint => {
|
|
280
|
+
HttpApiSchema.deunionize(schemas, endpoint.errorSchema);
|
|
281
|
+
});
|
|
282
|
+
HttpApiSchema.deunionize(schemas, group.errorSchema);
|
|
187
283
|
});
|
|
284
|
+
return Schema.Union(...Array.from(schemas, toResponseError));
|
|
188
285
|
};
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
286
|
+
const decodeForbidden = (_, __, ast) => ParseResult.fail(new ParseResult.Forbidden(ast, _, "Encode only schema"));
|
|
287
|
+
const toResponseSchema = getStatus => {
|
|
288
|
+
const cache = new WeakMap();
|
|
289
|
+
const schemaToResponse = (data, _, ast) => {
|
|
290
|
+
const isEmpty = HttpApiSchema.isVoid(ast.to);
|
|
291
|
+
const status = getStatus(ast.to);
|
|
292
|
+
if (isEmpty) {
|
|
293
|
+
return HttpServerResponse.empty({
|
|
294
|
+
status
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
const encoding = HttpApiSchema.getEncoding(ast.to);
|
|
298
|
+
switch (encoding.kind) {
|
|
299
|
+
case "Json":
|
|
300
|
+
{
|
|
301
|
+
return Effect.mapError(HttpServerResponse.json(data, {
|
|
302
|
+
status,
|
|
303
|
+
contentType: encoding.contentType
|
|
304
|
+
}), error => new ParseResult.Type(ast, error, "Could not encode to JSON"));
|
|
305
|
+
}
|
|
306
|
+
case "Text":
|
|
307
|
+
{
|
|
308
|
+
return ParseResult.succeed(HttpServerResponse.text(data, {
|
|
309
|
+
status,
|
|
310
|
+
contentType: encoding.contentType
|
|
311
|
+
}));
|
|
312
|
+
}
|
|
313
|
+
case "Uint8Array":
|
|
314
|
+
{
|
|
315
|
+
return ParseResult.succeed(HttpServerResponse.uint8Array(data, {
|
|
316
|
+
status,
|
|
317
|
+
contentType: encoding.contentType
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
case "UrlParams":
|
|
321
|
+
{
|
|
322
|
+
return ParseResult.succeed(HttpServerResponse.urlParams(data, {
|
|
323
|
+
status,
|
|
324
|
+
contentType: encoding.contentType
|
|
325
|
+
}));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
return schema => {
|
|
330
|
+
if (cache.has(schema.ast)) {
|
|
331
|
+
return cache.get(schema.ast);
|
|
332
|
+
}
|
|
333
|
+
const transform = Schema.transformOrFail(responseSchema, schema, {
|
|
334
|
+
decode: decodeForbidden,
|
|
335
|
+
encode: schemaToResponse
|
|
336
|
+
});
|
|
337
|
+
cache.set(transform.ast, transform);
|
|
338
|
+
return transform;
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
const toResponseSuccess = /*#__PURE__*/toResponseSchema(HttpApiSchema.getStatusSuccessAST);
|
|
342
|
+
const toResponseError = /*#__PURE__*/toResponseSchema(HttpApiSchema.getStatusErrorAST);
|
|
343
|
+
// ----------------------------------------------------------------------------
|
|
344
|
+
// Global middleware
|
|
345
|
+
// ----------------------------------------------------------------------------
|
|
206
346
|
/**
|
|
207
347
|
* @since 1.0.0
|
|
208
348
|
* @category middleware
|
|
@@ -222,7 +362,7 @@ const middlewareAddNoContext = middleware => Effect.map(Effect.serviceOption(Mid
|
|
|
222
362
|
* @since 1.0.0
|
|
223
363
|
* @category middleware
|
|
224
364
|
*/
|
|
225
|
-
export const
|
|
365
|
+
export const middleware = (...args) => {
|
|
226
366
|
const apiFirst = HttpApi.isHttpApi(args[0]);
|
|
227
367
|
const withContext = apiFirst ? args[2]?.withContext === true : args[1]?.withContext === true;
|
|
228
368
|
const add = withContext ? middlewareAdd : middlewareAddNoContext;
|
|
@@ -236,7 +376,7 @@ export const middlewareLayer = (...args) => {
|
|
|
236
376
|
* @since 1.0.0
|
|
237
377
|
* @category middleware
|
|
238
378
|
*/
|
|
239
|
-
export const
|
|
379
|
+
export const middlewareScoped = (...args) => {
|
|
240
380
|
const apiFirst = HttpApi.isHttpApi(args[0]);
|
|
241
381
|
const withContext = apiFirst ? args[2]?.withContext === true : args[1]?.withContext === true;
|
|
242
382
|
const add = withContext ? middlewareAdd : middlewareAddNoContext;
|
|
@@ -249,7 +389,7 @@ export const middlewareLayerScoped = (...args) => {
|
|
|
249
389
|
* @since 1.0.0
|
|
250
390
|
* @category middleware
|
|
251
391
|
*/
|
|
252
|
-
export const middlewareCors = options =>
|
|
392
|
+
export const middlewareCors = options => middleware(HttpMiddleware.cors(options));
|
|
253
393
|
/**
|
|
254
394
|
* A middleware that adds an openapi.json endpoint to the API.
|
|
255
395
|
*
|
|
@@ -257,7 +397,9 @@ export const middlewareCors = options => middlewareLayer(HttpMiddleware.cors(opt
|
|
|
257
397
|
* @category middleware
|
|
258
398
|
*/
|
|
259
399
|
export const middlewareOpenApi = options => Router.use(router => Effect.gen(function* () {
|
|
260
|
-
const
|
|
400
|
+
const {
|
|
401
|
+
api
|
|
402
|
+
} = yield* HttpApi.Api;
|
|
261
403
|
const spec = OpenApi.fromApi(api);
|
|
262
404
|
const response = yield* HttpServerResponse.json(spec).pipe(Effect.orDie);
|
|
263
405
|
yield* router.get(options?.path ?? "/openapi.json", Effect.succeed(response));
|
|
@@ -265,7 +407,7 @@ export const middlewareOpenApi = options => Router.use(router => Effect.gen(func
|
|
|
265
407
|
const bearerLen = `Bearer `.length;
|
|
266
408
|
/**
|
|
267
409
|
* @since 1.0.0
|
|
268
|
-
* @category
|
|
410
|
+
* @category security
|
|
269
411
|
*/
|
|
270
412
|
export const securityDecode = self => {
|
|
271
413
|
switch (self._tag) {
|
|
@@ -312,9 +454,9 @@ export const securityDecode = self => {
|
|
|
312
454
|
* You can use this api before returning a response from an endpoint handler.
|
|
313
455
|
*
|
|
314
456
|
* ```ts
|
|
315
|
-
*
|
|
457
|
+
* handlers.handle(
|
|
316
458
|
* "authenticate",
|
|
317
|
-
* (_) =>
|
|
459
|
+
* (_) => HttpApiBuilder.securitySetCookie(security, "secret123")
|
|
318
460
|
* )
|
|
319
461
|
* ```
|
|
320
462
|
*
|
|
@@ -329,152 +471,4 @@ export const securitySetCookie = (self, value, options) => {
|
|
|
329
471
|
...options
|
|
330
472
|
})));
|
|
331
473
|
};
|
|
332
|
-
/**
|
|
333
|
-
* Make a middleware from an `HttpApiSecurity` instance, that can be used when
|
|
334
|
-
* constructing a `Handlers` group.
|
|
335
|
-
*
|
|
336
|
-
* @since 1.0.0
|
|
337
|
-
* @category middleware
|
|
338
|
-
* @example
|
|
339
|
-
* import { HttpApiBuilder, HttpApiSecurity } from "@effect/platform"
|
|
340
|
-
* import { Schema } from "@effect/schema"
|
|
341
|
-
* import { Context, Effect, Redacted } from "effect"
|
|
342
|
-
*
|
|
343
|
-
* class User extends Schema.Class<User>("User")({
|
|
344
|
-
* id: Schema.Number
|
|
345
|
-
* }) {}
|
|
346
|
-
*
|
|
347
|
-
* class CurrentUser extends Context.Tag("CurrentUser")<CurrentUser, User>() {}
|
|
348
|
-
*
|
|
349
|
-
* class Accounts extends Context.Tag("Accounts")<Accounts, {
|
|
350
|
-
* readonly findUserByAccessToken: (accessToken: string) => Effect.Effect<User>
|
|
351
|
-
* }>() {}
|
|
352
|
-
*
|
|
353
|
-
* const securityMiddleware = Effect.gen(function*() {
|
|
354
|
-
* const accounts = yield* Accounts
|
|
355
|
-
* return HttpApiBuilder.middlewareSecurity(
|
|
356
|
-
* HttpApiSecurity.bearer,
|
|
357
|
-
* CurrentUser,
|
|
358
|
-
* (token) => accounts.findUserByAccessToken(Redacted.value(token))
|
|
359
|
-
* )
|
|
360
|
-
* })
|
|
361
|
-
*/
|
|
362
|
-
export const middlewareSecurity = (self, tag, f) => middleware(Effect.provideServiceEffect(tag, Effect.flatMap(securityDecode(self), f)));
|
|
363
|
-
/**
|
|
364
|
-
* Make a middleware from an `HttpApiSecurity` instance, that can be used when
|
|
365
|
-
* constructing a `Handlers` group.
|
|
366
|
-
*
|
|
367
|
-
* This version does not supply any context to the handlers.
|
|
368
|
-
*
|
|
369
|
-
* @since 1.0.0
|
|
370
|
-
* @category middleware
|
|
371
|
-
*/
|
|
372
|
-
export const middlewareSecurityVoid = (self, f) => middleware(httpApp => securityDecode(self).pipe(Effect.flatMap(f), Effect.zipRight(httpApp)));
|
|
373
|
-
// internal
|
|
374
|
-
const requestPayload = (request, urlParams, isMultipart) => HttpMethod.hasBody(request.method) ? isMultipart ? Effect.orDie(request.multipart) : Effect.orDie(request.json) : Effect.succeed(urlParams);
|
|
375
|
-
const handlerToRoute = (endpoint, handler, isFullResponse) => {
|
|
376
|
-
const decodePath = Option.map(endpoint.pathSchema, Schema.decodeUnknown);
|
|
377
|
-
const isMultipart = endpoint.payloadSchema.pipe(Option.map(schema => HttpApiSchema.getMultipart(schema.ast)), Option.getOrElse(() => false));
|
|
378
|
-
const decodePayload = Option.map(endpoint.payloadSchema, Schema.decodeUnknown);
|
|
379
|
-
const decodeHeaders = Option.map(endpoint.headersSchema, Schema.decodeUnknown);
|
|
380
|
-
const encoding = HttpApiSchema.getEncoding(endpoint.successSchema.ast);
|
|
381
|
-
const successStatus = HttpApiSchema.getStatusSuccess(endpoint.successSchema);
|
|
382
|
-
const encodeSuccess = Option.map(HttpApiEndpoint.schemaSuccess(endpoint), schema => {
|
|
383
|
-
const encode = Schema.encodeUnknown(schema);
|
|
384
|
-
switch (encoding.kind) {
|
|
385
|
-
case "Json":
|
|
386
|
-
{
|
|
387
|
-
return body => Effect.orDie(Effect.flatMap(encode(body), json => HttpServerResponse.json(json, {
|
|
388
|
-
status: successStatus,
|
|
389
|
-
contentType: encoding.contentType
|
|
390
|
-
})));
|
|
391
|
-
}
|
|
392
|
-
case "Text":
|
|
393
|
-
{
|
|
394
|
-
return body => Effect.map(Effect.orDie(encode(body)), text => HttpServerResponse.text(text, {
|
|
395
|
-
status: successStatus,
|
|
396
|
-
contentType: encoding.contentType
|
|
397
|
-
}));
|
|
398
|
-
}
|
|
399
|
-
case "Uint8Array":
|
|
400
|
-
{
|
|
401
|
-
return body => Effect.map(Effect.orDie(encode(body)), data => HttpServerResponse.uint8Array(data, {
|
|
402
|
-
status: successStatus,
|
|
403
|
-
contentType: encoding.contentType
|
|
404
|
-
}));
|
|
405
|
-
}
|
|
406
|
-
case "UrlParams":
|
|
407
|
-
{
|
|
408
|
-
return body => Effect.map(Effect.orDie(encode(body)), params => HttpServerResponse.urlParams(params, {
|
|
409
|
-
status: successStatus,
|
|
410
|
-
contentType: encoding.contentType
|
|
411
|
-
}));
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
return HttpRouter.makeRoute(endpoint.method, endpoint.path, Effect.withFiberRuntime(fiber => {
|
|
416
|
-
const context = fiber.getFiberRef(FiberRef.currentContext);
|
|
417
|
-
const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest);
|
|
418
|
-
const routeContext = Context.unsafeGet(context, HttpRouter.RouteContext);
|
|
419
|
-
const urlParams = Context.unsafeGet(context, HttpServerRequest.ParsedSearchParams);
|
|
420
|
-
return (decodePath._tag === "Some" ? Effect.catchAll(decodePath.value(routeContext.params), HttpApiDecodeError.refailParseError) : Effect.succeed(routeContext.params)).pipe(Effect.bindTo("pathParams"), decodePayload._tag === "Some" ? Effect.bind("payload", _ => requestPayload(request, urlParams, isMultipart).pipe(Effect.orDie, Effect.flatMap(raw => Effect.catchAll(decodePayload.value(raw), HttpApiDecodeError.refailParseError)))) : identity, decodeHeaders._tag === "Some" ? Effect.bind("headers", _ => Effect.orDie(decodeHeaders.value(request.headers))) : identity, Effect.flatMap(input => {
|
|
421
|
-
const request = {
|
|
422
|
-
path: input.pathParams
|
|
423
|
-
};
|
|
424
|
-
if ("payload" in input) {
|
|
425
|
-
request.payload = input.payload;
|
|
426
|
-
}
|
|
427
|
-
if ("headers" in input) {
|
|
428
|
-
request.headers = input.headers;
|
|
429
|
-
}
|
|
430
|
-
return handler(request);
|
|
431
|
-
}), isFullResponse ? identity : encodeSuccess._tag === "Some" ? Effect.flatMap(encodeSuccess.value) : Effect.as(HttpServerResponse.empty({
|
|
432
|
-
status: successStatus
|
|
433
|
-
})));
|
|
434
|
-
}));
|
|
435
|
-
};
|
|
436
|
-
const astCache = /*#__PURE__*/globalValue("@effect/platform/HttpApiBuilder/astCache", () => new WeakMap());
|
|
437
|
-
const makeErrorSchema = api => {
|
|
438
|
-
const schemas = new Set();
|
|
439
|
-
function processSchema(schema) {
|
|
440
|
-
if (astCache.has(schema.ast)) {
|
|
441
|
-
schemas.add(astCache.get(schema.ast));
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
const ast = schema.ast;
|
|
445
|
-
if (ast._tag === "Union") {
|
|
446
|
-
for (const astType of ast.types) {
|
|
447
|
-
const errorSchema = Schema.make(astType).annotations({
|
|
448
|
-
...ast.annotations,
|
|
449
|
-
...astType.annotations
|
|
450
|
-
});
|
|
451
|
-
astCache.set(astType, errorSchema);
|
|
452
|
-
schemas.add(errorSchema);
|
|
453
|
-
}
|
|
454
|
-
} else {
|
|
455
|
-
astCache.set(ast, schema);
|
|
456
|
-
schemas.add(schema);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
processSchema(api.errorSchema);
|
|
460
|
-
for (const group of api.groups) {
|
|
461
|
-
for (const endpoint of group.endpoints) {
|
|
462
|
-
processSchema(endpoint.errorSchema);
|
|
463
|
-
}
|
|
464
|
-
processSchema(group.errorSchema);
|
|
465
|
-
}
|
|
466
|
-
return Schema.Union(...[...schemas].map(schema => {
|
|
467
|
-
const status = HttpApiSchema.getStatusError(schema);
|
|
468
|
-
const encoded = AST.encodedAST(schema.ast);
|
|
469
|
-
const isEmpty = encoded._tag === "VoidKeyword";
|
|
470
|
-
return Schema.transformOrFail(Schema.Any, schema, {
|
|
471
|
-
decode: (_, __, ast) => ParseResult.fail(new ParseResult.Forbidden(ast, _, "Encode only schema")),
|
|
472
|
-
encode: (error, _, ast) => isEmpty ? HttpServerResponse.empty({
|
|
473
|
-
status
|
|
474
|
-
}) : HttpServerResponse.json(error, {
|
|
475
|
-
status
|
|
476
|
-
}).pipe(Effect.mapError(error => new ParseResult.Type(ast, error, "Could not encode to JSON")))
|
|
477
|
-
});
|
|
478
|
-
}));
|
|
479
|
-
};
|
|
480
474
|
//# sourceMappingURL=HttpApiBuilder.js.map
|