@effect/platform 0.87.1 → 0.87.2

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.
Files changed (43) hide show
  1. package/HttpLayerRouter/package.json +6 -0
  2. package/README.md +271 -0
  3. package/dist/cjs/HttpApiBuilder.js +15 -1
  4. package/dist/cjs/HttpApiBuilder.js.map +1 -1
  5. package/dist/cjs/HttpApiScalar.js +29 -11
  6. package/dist/cjs/HttpApiScalar.js.map +1 -1
  7. package/dist/cjs/HttpApiSwagger.js +32 -15
  8. package/dist/cjs/HttpApiSwagger.js.map +1 -1
  9. package/dist/cjs/HttpLayerRouter.js +494 -0
  10. package/dist/cjs/HttpLayerRouter.js.map +1 -0
  11. package/dist/cjs/index.js +3 -1
  12. package/dist/cjs/internal/httpRouter.js +3 -1
  13. package/dist/cjs/internal/httpRouter.js.map +1 -1
  14. package/dist/dts/HttpApiBuilder.d.ts +6 -0
  15. package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
  16. package/dist/dts/HttpApiScalar.d.ts +14 -2
  17. package/dist/dts/HttpApiScalar.d.ts.map +1 -1
  18. package/dist/dts/HttpApiSwagger.d.ts +12 -2
  19. package/dist/dts/HttpApiSwagger.d.ts.map +1 -1
  20. package/dist/dts/HttpLayerRouter.d.ts +481 -0
  21. package/dist/dts/HttpLayerRouter.d.ts.map +1 -0
  22. package/dist/dts/index.d.ts +4 -0
  23. package/dist/dts/index.d.ts.map +1 -1
  24. package/dist/dts/internal/httpRouter.d.ts.map +1 -1
  25. package/dist/esm/HttpApiBuilder.js +14 -0
  26. package/dist/esm/HttpApiBuilder.js.map +1 -1
  27. package/dist/esm/HttpApiScalar.js +28 -10
  28. package/dist/esm/HttpApiScalar.js.map +1 -1
  29. package/dist/esm/HttpApiSwagger.js +31 -14
  30. package/dist/esm/HttpApiSwagger.js.map +1 -1
  31. package/dist/esm/HttpLayerRouter.js +468 -0
  32. package/dist/esm/HttpLayerRouter.js.map +1 -0
  33. package/dist/esm/index.js +4 -0
  34. package/dist/esm/index.js.map +1 -1
  35. package/dist/esm/internal/httpRouter.js +3 -1
  36. package/dist/esm/internal/httpRouter.js.map +1 -1
  37. package/package.json +10 -2
  38. package/src/HttpApiBuilder.ts +30 -0
  39. package/src/HttpApiScalar.ts +79 -41
  40. package/src/HttpApiSwagger.ts +49 -18
  41. package/src/HttpLayerRouter.ts +920 -0
  42. package/src/index.ts +5 -0
  43. package/src/internal/httpRouter.ts +4 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/platform",
3
- "version": "0.87.1",
3
+ "version": "0.87.2",
4
4
  "description": "Unified interfaces for common platform-specific services",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,7 +16,7 @@
16
16
  "multipasta": "^0.2.5"
17
17
  },
18
18
  "peerDependencies": {
19
- "effect": "^3.16.10"
19
+ "effect": "^3.16.11"
20
20
  },
21
21
  "publishConfig": {
22
22
  "provenance": true
@@ -171,6 +171,11 @@
171
171
  "import": "./dist/esm/HttpIncomingMessage.js",
172
172
  "default": "./dist/cjs/HttpIncomingMessage.js"
173
173
  },
174
+ "./HttpLayerRouter": {
175
+ "types": "./dist/dts/HttpLayerRouter.d.ts",
176
+ "import": "./dist/esm/HttpLayerRouter.js",
177
+ "default": "./dist/cjs/HttpLayerRouter.js"
178
+ },
174
179
  "./HttpMethod": {
175
180
  "types": "./dist/dts/HttpMethod.d.ts",
176
181
  "import": "./dist/esm/HttpMethod.js",
@@ -418,6 +423,9 @@
418
423
  "HttpIncomingMessage": [
419
424
  "./dist/dts/HttpIncomingMessage.d.ts"
420
425
  ],
426
+ "HttpLayerRouter": [
427
+ "./dist/dts/HttpLayerRouter.d.ts"
428
+ ],
421
429
  "HttpMethod": [
422
430
  "./dist/dts/HttpMethod.d.ts"
423
431
  ],
@@ -123,6 +123,36 @@ export const httpApp: Effect.Effect<
123
123
  ) as any
124
124
  })
125
125
 
126
+ /**
127
+ * @since 1.0.0
128
+ * @category constructors
129
+ */
130
+ export const buildMiddleware: <Id extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, E, R>(
131
+ api: HttpApi.HttpApi<Id, Groups, E, R>
132
+ ) => Effect.Effect<
133
+ (
134
+ effect: Effect.Effect<HttpServerResponse.HttpServerResponse, unknown>
135
+ ) => Effect.Effect<HttpServerResponse.HttpServerResponse, unknown, never>
136
+ > = Effect.fnUntraced(
137
+ function*<Id extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, E, R>(
138
+ api: HttpApi.HttpApi<Id, Groups, E, R>
139
+ ) {
140
+ const context = yield* Effect.context<never>()
141
+ const middlewareMap = makeMiddlewareMap(api.middlewares, context)
142
+ const errorSchema = makeErrorSchema(api as any)
143
+ const encodeError = Schema.encodeUnknown(errorSchema)
144
+ return (effect: Effect.Effect<HttpServerResponse.HttpServerResponse, unknown>) =>
145
+ Effect.catchAllCause(
146
+ applyMiddleware(middlewareMap, effect),
147
+ (cause) =>
148
+ Effect.matchEffect(Effect.provide(encodeError(Cause.squash(cause)), context), {
149
+ onFailure: () => Effect.failCause(cause),
150
+ onSuccess: Effect.succeed
151
+ })
152
+ )
153
+ }
154
+ )
155
+
126
156
  /**
127
157
  * Construct an http web handler from an `HttpApi` instance.
128
158
  *
@@ -2,9 +2,11 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import * as Effect from "effect/Effect"
5
- import type { Layer } from "effect/Layer"
5
+ import * as Layer from "effect/Layer"
6
6
  import { Api } from "./HttpApi.js"
7
+ import type * as HttpApi from "./HttpApi.js"
7
8
  import { Router } from "./HttpApiBuilder.js"
9
+ import * as HttpLayerRouter from "./HttpLayerRouter.js"
8
10
  import * as HttpServerResponse from "./HttpServerResponse.js"
9
11
  import * as Html from "./internal/html.js"
10
12
  import * as internal from "./internal/httpApiScalar.js"
@@ -120,52 +122,45 @@ export type ScalarConfig = {
120
122
  defaultOpenAllTags?: boolean
121
123
  }
122
124
 
123
- /**
124
- * @since 1.0.0
125
- * @category layers
126
- */
127
- export const layer = (options?: {
128
- readonly path?: `/${string}` | undefined
125
+ const makeHandler = (options: {
126
+ readonly api: HttpApi.HttpApi.Any
129
127
  readonly source?: ScalarScriptSource
130
128
  readonly scalar?: ScalarConfig
131
- }): Layer<never, never, Api> =>
132
- Router.use((router) =>
133
- Effect.gen(function*() {
134
- const { api } = yield* Api
135
- const spec = OpenApi.fromApi(api)
129
+ }) => {
130
+ const spec = OpenApi.fromApi(options.api as any)
136
131
 
137
- const source = options?.source
138
- const defaultScript = internal.javascript
139
- const src: string | null = source
140
- ? typeof source === "string"
141
- ? source
142
- : source.type === "cdn"
143
- ? `https://cdn.jsdelivr.net/npm/@scalar/api-reference@${
144
- source.version ?? "latest"
145
- }/dist/browser/standalone.min.js`
146
- : null
147
- : null
132
+ const source = options?.source
133
+ const defaultScript = internal.javascript
134
+ const src: string | null = source
135
+ ? typeof source === "string"
136
+ ? source
137
+ : source.type === "cdn"
138
+ ? `https://cdn.jsdelivr.net/npm/@scalar/api-reference@${
139
+ source.version ?? "latest"
140
+ }/dist/browser/standalone.min.js`
141
+ : null
142
+ : null
148
143
 
149
- const scalarConfig = {
150
- _integration: "http",
151
- ...options?.scalar
152
- }
144
+ const scalarConfig = {
145
+ _integration: "http",
146
+ ...options?.scalar
147
+ }
153
148
 
154
- const response = HttpServerResponse.html(`<!doctype html>
149
+ const response = HttpServerResponse.html(`<!doctype html>
155
150
  <html>
156
151
  <head>
157
152
  <meta charset="utf-8" />
158
153
  <title>${Html.escape(spec.info.title)}</title>
159
154
  ${
160
- !spec.info.description
161
- ? ""
162
- : `<meta name="description" content="${Html.escape(spec.info.description)}"/>`
163
- }
155
+ !spec.info.description
156
+ ? ""
157
+ : `<meta name="description" content="${Html.escape(spec.info.description)}"/>`
158
+ }
164
159
  ${
165
- !spec.info.description
166
- ? ""
167
- : `<meta name="og:description" content="${Html.escape(spec.info.description)}"/>`
168
- }
160
+ !spec.info.description
161
+ ? ""
162
+ : `<meta name="og:description" content="${Html.escape(spec.info.description)}"/>`
163
+ }
169
164
  <meta
170
165
  name="viewport"
171
166
  content="width=device-width, initial-scale=1" />
@@ -178,12 +173,55 @@ export const layer = (options?: {
178
173
  document.getElementById('api-reference').dataset.configuration = JSON.stringify(${Html.escapeJson(scalarConfig)})
179
174
  </script>
180
175
  ${
181
- src
182
- ? `<script src="${src}" crossorigin></script>`
183
- : `<script>${defaultScript}</script>`
184
- }
176
+ src
177
+ ? `<script src="${src}" crossorigin></script>`
178
+ : `<script>${defaultScript}</script>`
179
+ }
185
180
  </body>
186
181
  </html>`)
187
- yield* router.get(options?.path ?? "/docs", Effect.succeed(response))
182
+
183
+ return Effect.succeed(response)
184
+ }
185
+
186
+ /**
187
+ * @since 1.0.0
188
+ * @category layers
189
+ */
190
+ export const layer = (options?: {
191
+ readonly path?: `/${string}` | undefined
192
+ readonly source?: ScalarScriptSource
193
+ readonly scalar?: ScalarConfig
194
+ }): Layer.Layer<never, never, Api> =>
195
+ Router.use((router) =>
196
+ Effect.gen(function*() {
197
+ const { api } = yield* Api
198
+ const handler = makeHandler({ ...options, api })
199
+ yield* router.get(options?.path ?? "/docs", handler)
188
200
  })
189
201
  )
202
+
203
+ /**
204
+ * @since 1.0.0
205
+ * @category layers
206
+ */
207
+ export const layerHttpLayerRouter: (
208
+ options: {
209
+ readonly api: HttpApi.HttpApi.Any
210
+ readonly path: `/${string}`
211
+ readonly source?: ScalarScriptSource
212
+ readonly scalar?: ScalarConfig
213
+ }
214
+ ) => Layer.Layer<
215
+ never,
216
+ never,
217
+ HttpLayerRouter.HttpRouter
218
+ > = Effect.fnUntraced(function*(options: {
219
+ readonly api: HttpApi.HttpApi.Any
220
+ readonly path: `/${string}`
221
+ readonly source?: ScalarScriptSource
222
+ readonly scalar?: ScalarConfig
223
+ }) {
224
+ const router = yield* HttpLayerRouter.HttpRouter
225
+ const handler = makeHandler(options)
226
+ yield* router.add("GET", options.path, handler)
227
+ }, Layer.effectDiscard)
@@ -2,30 +2,21 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import * as Effect from "effect/Effect"
5
- import type { Layer } from "effect/Layer"
5
+ import * as Layer from "effect/Layer"
6
6
  import { Api } from "./HttpApi.js"
7
+ import type * as HttpApi from "./HttpApi.js"
7
8
  import { Router } from "./HttpApiBuilder.js"
9
+ import * as HttpLayerRouter from "./HttpLayerRouter.js"
8
10
  import * as HttpServerResponse from "./HttpServerResponse.js"
9
11
  import * as Html from "./internal/html.js"
10
12
  import * as internal from "./internal/httpApiSwagger.js"
11
13
  import * as OpenApi from "./OpenApi.js"
12
14
 
13
- /**
14
- * Exported layer mounting Swagger/OpenAPI documentation UI.
15
- *
16
- * @param options.path Optional mount path (default "/docs").
17
- *
18
- * @since 1.0.0
19
- * @category layers
20
- */
21
- export const layer = (options?: {
22
- readonly path?: `/${string}` | undefined
23
- }): Layer<never, never, Api> =>
24
- Router.use((router) =>
25
- Effect.gen(function*() {
26
- const { api } = yield* Api
27
- const spec = OpenApi.fromApi(api)
28
- const response = HttpServerResponse.html(`<!DOCTYPE html>
15
+ const makeHandler = (options: {
16
+ readonly api: HttpApi.HttpApi.Any
17
+ }) => {
18
+ const spec = OpenApi.fromApi(options.api as any)
19
+ const response = HttpServerResponse.html(`<!DOCTYPE html>
29
20
  <html lang="en">
30
21
  <head>
31
22
  <meta charset="utf-8" />
@@ -49,6 +40,46 @@ export const layer = (options?: {
49
40
  </script>
50
41
  </body>
51
42
  </html>`)
52
- yield* router.get(options?.path ?? "/docs", Effect.succeed(response))
43
+ return Effect.succeed(response)
44
+ }
45
+
46
+ /**
47
+ * Exported layer mounting Swagger/OpenAPI documentation UI.
48
+ *
49
+ * @param options.path Optional mount path (default "/docs").
50
+ *
51
+ * @since 1.0.0
52
+ * @category layers
53
+ */
54
+ export const layer = (options?: {
55
+ readonly path?: `/${string}` | undefined
56
+ }): Layer.Layer<never, never, Api> =>
57
+ Router.use((router) =>
58
+ Effect.gen(function*() {
59
+ const { api } = yield* Api
60
+ const handler = makeHandler({ api })
61
+ yield* router.get(options?.path ?? "/docs", handler)
53
62
  })
54
63
  )
64
+
65
+ /**
66
+ * @since 1.0.0
67
+ * @category layers
68
+ */
69
+ export const layerHttpLayerRouter: (
70
+ options: {
71
+ readonly api: HttpApi.HttpApi.Any
72
+ readonly path: `/${string}`
73
+ }
74
+ ) => Layer.Layer<
75
+ never,
76
+ never,
77
+ HttpLayerRouter.HttpRouter
78
+ > = Effect.fnUntraced(function*(options: {
79
+ readonly api: HttpApi.HttpApi.Any
80
+ readonly path: `/${string}`
81
+ }) {
82
+ const router = yield* HttpLayerRouter.HttpRouter
83
+ const handler = makeHandler(options)
84
+ yield* router.add("GET", options.path, handler)
85
+ }, Layer.effectDiscard)