@effect/platform 0.68.5 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +243 -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 +84 -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 +231 -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 +236 -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 +532 -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 +318 -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,40 @@ 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
|
-
* HttpPlatform.layer,
|
|
84
|
-
* Etag.layerWeak
|
|
85
|
-
* ).pipe(
|
|
86
|
-
* Layer.provideMerge(NodeContext.layer)
|
|
97
|
+
* MyApiLive,
|
|
98
|
+
* HttpServer.layerContext
|
|
87
99
|
* )
|
|
88
100
|
* )
|
|
89
|
-
*
|
|
90
|
-
* const handler = HttpApiBuilder.toWebHandler(runtime, HttpMiddleware.logger)
|
|
91
101
|
*/
|
|
92
|
-
export const toWebHandler = (
|
|
102
|
+
export const toWebHandler = (layer, options) => {
|
|
103
|
+
const runtime = ManagedRuntime.make(Layer.merge(layer, Router.Live), options?.memoMap);
|
|
104
|
+
let handlerCached;
|
|
93
105
|
const handlerPromise = httpApp.pipe(Effect.bindTo("httpApp"), Effect.bind("runtime", () => runtime.runtimeEffect), Effect.map(({
|
|
94
106
|
httpApp,
|
|
95
107
|
runtime
|
|
96
|
-
}) => HttpApp.toWebHandlerRuntime(runtime)(middleware ? middleware(httpApp) : httpApp)),
|
|
97
|
-
|
|
108
|
+
}) => HttpApp.toWebHandlerRuntime(runtime)(options?.middleware ? options.middleware(httpApp) : httpApp)), Effect.tap(handler => {
|
|
109
|
+
handlerCached = handler;
|
|
110
|
+
}), runtime.runPromise);
|
|
111
|
+
function handler(request) {
|
|
112
|
+
if (handlerCached !== undefined) {
|
|
113
|
+
return handlerCached(request);
|
|
114
|
+
}
|
|
115
|
+
return handlerPromise.then(handler => handler(request));
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
handler,
|
|
119
|
+
dispose: runtime.dispose
|
|
120
|
+
};
|
|
98
121
|
};
|
|
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
122
|
/**
|
|
112
123
|
* @since 1.0.0
|
|
113
124
|
* @category handlers
|
|
@@ -119,6 +130,28 @@ const HandlersProto = {
|
|
|
119
130
|
},
|
|
120
131
|
pipe() {
|
|
121
132
|
return pipeArguments(this, arguments);
|
|
133
|
+
},
|
|
134
|
+
handle(name, handler) {
|
|
135
|
+
const endpoint = HashMap.unsafeGet(this.group.endpoints, name);
|
|
136
|
+
return makeHandlers({
|
|
137
|
+
group: this.group,
|
|
138
|
+
handlers: Chunk.append(this.handlers, {
|
|
139
|
+
endpoint,
|
|
140
|
+
handler,
|
|
141
|
+
withFullResponse: false
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
handleRaw(name, handler) {
|
|
146
|
+
const endpoint = HashMap.unsafeGet(this.group.endpoints, name);
|
|
147
|
+
return makeHandlers({
|
|
148
|
+
group: this.group,
|
|
149
|
+
handlers: Chunk.append(this.handlers, {
|
|
150
|
+
endpoint,
|
|
151
|
+
handler,
|
|
152
|
+
withFullResponse: true
|
|
153
|
+
})
|
|
154
|
+
});
|
|
122
155
|
}
|
|
123
156
|
};
|
|
124
157
|
const makeHandlers = options => {
|
|
@@ -128,81 +161,186 @@ const makeHandlers = options => {
|
|
|
128
161
|
return self;
|
|
129
162
|
};
|
|
130
163
|
/**
|
|
131
|
-
* Create a `Layer` that will implement all the endpoints in an `
|
|
164
|
+
* Create a `Layer` that will implement all the endpoints in an `HttpApi`.
|
|
132
165
|
*
|
|
133
166
|
* An unimplemented `Handlers` instance is passed to the `build` function, which
|
|
134
167
|
* you can use to add handlers to the group.
|
|
135
168
|
*
|
|
136
|
-
* You can implement endpoints using the `
|
|
169
|
+
* You can implement endpoints using the `handlers.handle` api.
|
|
137
170
|
*
|
|
138
171
|
* @since 1.0.0
|
|
139
172
|
* @category handlers
|
|
140
173
|
*/
|
|
141
174
|
export const group = (api, groupName, build) => Router.use(router => Effect.gen(function* () {
|
|
142
175
|
const context = yield* Effect.context();
|
|
143
|
-
const group =
|
|
144
|
-
if (group._tag === "None") {
|
|
145
|
-
throw new Error(`Group "${groupName}" not found in API`);
|
|
146
|
-
}
|
|
176
|
+
const group = HashMap.unsafeGet(api.groups, groupName);
|
|
147
177
|
const result = build(makeHandlers({
|
|
148
|
-
group
|
|
178
|
+
group,
|
|
149
179
|
handlers: Chunk.empty()
|
|
150
180
|
}));
|
|
151
181
|
const handlers = Effect.isEffect(result) ? yield* result : result;
|
|
182
|
+
const groupMiddleware = makeMiddlewareMap(group.middlewares, context);
|
|
152
183
|
const routes = [];
|
|
153
184
|
for (const item of handlers.handlers) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
185
|
+
const middleware = makeMiddlewareMap(item.endpoint.middlewares, context, groupMiddleware);
|
|
186
|
+
routes.push(handlerToRoute(item.endpoint, middleware, function (request) {
|
|
187
|
+
return Effect.mapInputContext(item.handler(request), input => Context.merge(context, input));
|
|
188
|
+
}, item.withFullResponse));
|
|
189
|
+
}
|
|
190
|
+
yield* router.concat(HttpRouter.fromIterable(routes));
|
|
191
|
+
}));
|
|
192
|
+
// internal
|
|
193
|
+
const requestPayload = (request, urlParams, isMultipart) => HttpMethod.hasBody(request.method) ? isMultipart ? Effect.orDie(request.multipart) : Effect.orDie(request.json) : Effect.succeed(urlParams);
|
|
194
|
+
const makeMiddlewareMap = (middleware, context, initial) => {
|
|
195
|
+
const map = new Map(initial);
|
|
196
|
+
HashSet.forEach(middleware, tag => {
|
|
197
|
+
map.set(tag.key, {
|
|
198
|
+
tag,
|
|
199
|
+
effect: Context.unsafeGet(context, tag)
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
return map;
|
|
203
|
+
};
|
|
204
|
+
const handlerToRoute = (endpoint_, middleware, handler, isFullResponse) => {
|
|
205
|
+
const endpoint = endpoint_;
|
|
206
|
+
const decodePath = Option.map(endpoint.pathSchema, Schema.decodeUnknown);
|
|
207
|
+
const isMultipart = endpoint.payloadSchema.pipe(Option.map(schema => HttpApiSchema.getMultipart(schema.ast)), Option.getOrElse(() => false));
|
|
208
|
+
const decodePayload = Option.map(endpoint.payloadSchema, Schema.decodeUnknown);
|
|
209
|
+
const decodeHeaders = Option.map(endpoint.headersSchema, Schema.decodeUnknown);
|
|
210
|
+
const decodeUrlParams = Option.map(endpoint.urlParamsSchema, Schema.decodeUnknown);
|
|
211
|
+
const encodeSuccess = Schema.encode(makeSuccessSchema(endpoint.successSchema));
|
|
212
|
+
return HttpRouter.makeRoute(endpoint.method, endpoint.path, applyMiddleware(middleware, Effect.withFiberRuntime(fiber => {
|
|
213
|
+
const context = fiber.getFiberRef(FiberRef.currentContext);
|
|
214
|
+
const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest);
|
|
215
|
+
const routeContext = Context.unsafeGet(context, HttpRouter.RouteContext);
|
|
216
|
+
const urlParams = Context.unsafeGet(context, HttpServerRequest.ParsedSearchParams);
|
|
217
|
+
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 => {
|
|
218
|
+
const request = {
|
|
219
|
+
path: input.pathParams
|
|
220
|
+
};
|
|
221
|
+
if ("payload" in input) {
|
|
222
|
+
request.payload = input.payload;
|
|
223
|
+
}
|
|
224
|
+
if ("headers" in input) {
|
|
225
|
+
request.headers = input.headers;
|
|
226
|
+
}
|
|
227
|
+
if ("urlParams" in input) {
|
|
228
|
+
request.urlParams = input.urlParams;
|
|
158
229
|
}
|
|
230
|
+
return handler(request);
|
|
231
|
+
}), isFullResponse ? identity : Effect.flatMap(encodeSuccess), Effect.catchIf(ParseResult.isParseError, HttpApiDecodeError.refailParseError));
|
|
232
|
+
})));
|
|
233
|
+
};
|
|
234
|
+
const applyMiddleware = (middleware, handler) => {
|
|
235
|
+
for (const entry of middleware.values()) {
|
|
236
|
+
const effect = HttpApiMiddleware.SecurityTypeId in entry.tag ? makeSecurityMiddleware(entry) : entry.effect;
|
|
237
|
+
if (entry.tag.optional) {
|
|
238
|
+
const previous = handler;
|
|
239
|
+
handler = Effect.matchEffect(effect, {
|
|
240
|
+
onFailure: () => previous,
|
|
241
|
+
onSuccess: entry.tag.provides !== undefined ? value => Effect.provideService(previous, entry.tag.provides, value) : _ => previous
|
|
242
|
+
});
|
|
159
243
|
} else {
|
|
160
|
-
|
|
161
|
-
return Effect.mapInputContext(item.handler(request), input => Context.merge(context, input));
|
|
162
|
-
}, item.withFullResponse));
|
|
244
|
+
handler = entry.tag.provides !== undefined ? Effect.provideServiceEffect(handler, entry.tag.provides, effect) : Effect.zipRight(effect, handler);
|
|
163
245
|
}
|
|
164
246
|
}
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
247
|
+
return handler;
|
|
248
|
+
};
|
|
249
|
+
const securityMiddlewareCache = /*#__PURE__*/globalValue("securityMiddlewareCache", () => new WeakMap());
|
|
250
|
+
const makeSecurityMiddleware = entry => {
|
|
251
|
+
if (securityMiddlewareCache.has(entry.tag)) {
|
|
252
|
+
return securityMiddlewareCache.get(entry.tag);
|
|
253
|
+
}
|
|
254
|
+
let effect;
|
|
255
|
+
for (const [key, security] of Object.entries(entry.tag.security)) {
|
|
256
|
+
const decode = securityDecode(security);
|
|
257
|
+
const handler = entry.effect[key];
|
|
258
|
+
const middleware = Effect.flatMap(decode, handler);
|
|
259
|
+
effect = effect === undefined ? middleware : Effect.catchAll(effect, () => middleware);
|
|
177
260
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
261
|
+
if (effect === undefined) {
|
|
262
|
+
effect = Effect.void;
|
|
263
|
+
}
|
|
264
|
+
securityMiddlewareCache.set(entry.tag, effect);
|
|
265
|
+
return effect;
|
|
266
|
+
};
|
|
267
|
+
const responseSchema = /*#__PURE__*/Schema.declare(HttpServerResponse.isServerResponse);
|
|
268
|
+
const makeSuccessSchema = schema => {
|
|
269
|
+
const schemas = new Set();
|
|
270
|
+
HttpApiSchema.deunionize(schemas, schema);
|
|
271
|
+
return Schema.Union(...Array.from(schemas, toResponseSuccess));
|
|
272
|
+
};
|
|
273
|
+
const makeErrorSchema = api => {
|
|
274
|
+
const schemas = new Set();
|
|
275
|
+
HttpApiSchema.deunionize(schemas, api.errorSchema);
|
|
276
|
+
HashMap.forEach(api.groups, group => {
|
|
277
|
+
HashMap.forEach(group.endpoints, endpoint => {
|
|
278
|
+
HttpApiSchema.deunionize(schemas, endpoint.errorSchema);
|
|
279
|
+
});
|
|
280
|
+
HttpApiSchema.deunionize(schemas, group.errorSchema);
|
|
187
281
|
});
|
|
282
|
+
return Schema.Union(...Array.from(schemas, toResponseError));
|
|
188
283
|
};
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
284
|
+
const decodeForbidden = (_, __, ast) => ParseResult.fail(new ParseResult.Forbidden(ast, _, "Encode only schema"));
|
|
285
|
+
const toResponseSchema = getStatus => {
|
|
286
|
+
const cache = new WeakMap();
|
|
287
|
+
const schemaToResponse = (data, _, ast) => {
|
|
288
|
+
const isEmpty = HttpApiSchema.isVoid(ast.to);
|
|
289
|
+
const status = getStatus(ast.to);
|
|
290
|
+
if (isEmpty) {
|
|
291
|
+
return HttpServerResponse.empty({
|
|
292
|
+
status
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
const encoding = HttpApiSchema.getEncoding(ast.to);
|
|
296
|
+
switch (encoding.kind) {
|
|
297
|
+
case "Json":
|
|
298
|
+
{
|
|
299
|
+
return Effect.mapError(HttpServerResponse.json(data, {
|
|
300
|
+
status,
|
|
301
|
+
contentType: encoding.contentType
|
|
302
|
+
}), error => new ParseResult.Type(ast, error, "Could not encode to JSON"));
|
|
303
|
+
}
|
|
304
|
+
case "Text":
|
|
305
|
+
{
|
|
306
|
+
return ParseResult.succeed(HttpServerResponse.text(data, {
|
|
307
|
+
status,
|
|
308
|
+
contentType: encoding.contentType
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
case "Uint8Array":
|
|
312
|
+
{
|
|
313
|
+
return ParseResult.succeed(HttpServerResponse.uint8Array(data, {
|
|
314
|
+
status,
|
|
315
|
+
contentType: encoding.contentType
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
318
|
+
case "UrlParams":
|
|
319
|
+
{
|
|
320
|
+
return ParseResult.succeed(HttpServerResponse.urlParams(data, {
|
|
321
|
+
status,
|
|
322
|
+
contentType: encoding.contentType
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
return schema => {
|
|
328
|
+
if (cache.has(schema.ast)) {
|
|
329
|
+
return cache.get(schema.ast);
|
|
330
|
+
}
|
|
331
|
+
const transform = Schema.transformOrFail(responseSchema, schema, {
|
|
332
|
+
decode: decodeForbidden,
|
|
333
|
+
encode: schemaToResponse
|
|
334
|
+
});
|
|
335
|
+
cache.set(transform.ast, transform);
|
|
336
|
+
return transform;
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
const toResponseSuccess = /*#__PURE__*/toResponseSchema(HttpApiSchema.getStatusSuccessAST);
|
|
340
|
+
const toResponseError = /*#__PURE__*/toResponseSchema(HttpApiSchema.getStatusErrorAST);
|
|
341
|
+
// ----------------------------------------------------------------------------
|
|
342
|
+
// Global middleware
|
|
343
|
+
// ----------------------------------------------------------------------------
|
|
206
344
|
/**
|
|
207
345
|
* @since 1.0.0
|
|
208
346
|
* @category middleware
|
|
@@ -222,7 +360,7 @@ const middlewareAddNoContext = middleware => Effect.map(Effect.serviceOption(Mid
|
|
|
222
360
|
* @since 1.0.0
|
|
223
361
|
* @category middleware
|
|
224
362
|
*/
|
|
225
|
-
export const
|
|
363
|
+
export const middleware = (...args) => {
|
|
226
364
|
const apiFirst = HttpApi.isHttpApi(args[0]);
|
|
227
365
|
const withContext = apiFirst ? args[2]?.withContext === true : args[1]?.withContext === true;
|
|
228
366
|
const add = withContext ? middlewareAdd : middlewareAddNoContext;
|
|
@@ -236,7 +374,7 @@ export const middlewareLayer = (...args) => {
|
|
|
236
374
|
* @since 1.0.0
|
|
237
375
|
* @category middleware
|
|
238
376
|
*/
|
|
239
|
-
export const
|
|
377
|
+
export const middlewareScoped = (...args) => {
|
|
240
378
|
const apiFirst = HttpApi.isHttpApi(args[0]);
|
|
241
379
|
const withContext = apiFirst ? args[2]?.withContext === true : args[1]?.withContext === true;
|
|
242
380
|
const add = withContext ? middlewareAdd : middlewareAddNoContext;
|
|
@@ -249,7 +387,7 @@ export const middlewareLayerScoped = (...args) => {
|
|
|
249
387
|
* @since 1.0.0
|
|
250
388
|
* @category middleware
|
|
251
389
|
*/
|
|
252
|
-
export const middlewareCors = options =>
|
|
390
|
+
export const middlewareCors = options => middleware(HttpMiddleware.cors(options));
|
|
253
391
|
/**
|
|
254
392
|
* A middleware that adds an openapi.json endpoint to the API.
|
|
255
393
|
*
|
|
@@ -257,7 +395,9 @@ export const middlewareCors = options => middlewareLayer(HttpMiddleware.cors(opt
|
|
|
257
395
|
* @category middleware
|
|
258
396
|
*/
|
|
259
397
|
export const middlewareOpenApi = options => Router.use(router => Effect.gen(function* () {
|
|
260
|
-
const
|
|
398
|
+
const {
|
|
399
|
+
api
|
|
400
|
+
} = yield* HttpApi.Api;
|
|
261
401
|
const spec = OpenApi.fromApi(api);
|
|
262
402
|
const response = yield* HttpServerResponse.json(spec).pipe(Effect.orDie);
|
|
263
403
|
yield* router.get(options?.path ?? "/openapi.json", Effect.succeed(response));
|
|
@@ -265,7 +405,7 @@ export const middlewareOpenApi = options => Router.use(router => Effect.gen(func
|
|
|
265
405
|
const bearerLen = `Bearer `.length;
|
|
266
406
|
/**
|
|
267
407
|
* @since 1.0.0
|
|
268
|
-
* @category
|
|
408
|
+
* @category security
|
|
269
409
|
*/
|
|
270
410
|
export const securityDecode = self => {
|
|
271
411
|
switch (self._tag) {
|
|
@@ -312,9 +452,9 @@ export const securityDecode = self => {
|
|
|
312
452
|
* You can use this api before returning a response from an endpoint handler.
|
|
313
453
|
*
|
|
314
454
|
* ```ts
|
|
315
|
-
*
|
|
455
|
+
* handlers.handle(
|
|
316
456
|
* "authenticate",
|
|
317
|
-
* (_) =>
|
|
457
|
+
* (_) => HttpApiBuilder.securitySetCookie(security, "secret123")
|
|
318
458
|
* )
|
|
319
459
|
* ```
|
|
320
460
|
*
|
|
@@ -329,152 +469,4 @@ export const securitySetCookie = (self, value, options) => {
|
|
|
329
469
|
...options
|
|
330
470
|
})));
|
|
331
471
|
};
|
|
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
472
|
//# sourceMappingURL=HttpApiBuilder.js.map
|