@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.
Files changed (229) hide show
  1. package/HttpApiMiddleware/package.json +6 -0
  2. package/README.md +306 -233
  3. package/dist/cjs/Headers.js +7 -2
  4. package/dist/cjs/Headers.js.map +1 -1
  5. package/dist/cjs/HttpApi.js +90 -78
  6. package/dist/cjs/HttpApi.js.map +1 -1
  7. package/dist/cjs/HttpApiBuilder.js +245 -255
  8. package/dist/cjs/HttpApiBuilder.js.map +1 -1
  9. package/dist/cjs/HttpApiClient.js +64 -59
  10. package/dist/cjs/HttpApiClient.js.map +1 -1
  11. package/dist/cjs/HttpApiEndpoint.js +74 -109
  12. package/dist/cjs/HttpApiEndpoint.js.map +1 -1
  13. package/dist/cjs/HttpApiError.js +3 -4
  14. package/dist/cjs/HttpApiError.js.map +1 -1
  15. package/dist/cjs/HttpApiGroup.js +103 -100
  16. package/dist/cjs/HttpApiGroup.js.map +1 -1
  17. package/dist/cjs/HttpApiMiddleware.js +67 -0
  18. package/dist/cjs/HttpApiMiddleware.js.map +1 -0
  19. package/dist/cjs/HttpApiSchema.js +33 -7
  20. package/dist/cjs/HttpApiSchema.js.map +1 -1
  21. package/dist/cjs/HttpApiSecurity.js +2 -2
  22. package/dist/cjs/HttpApiSecurity.js.map +1 -1
  23. package/dist/cjs/HttpApiSwagger.js +3 -1
  24. package/dist/cjs/HttpApiSwagger.js.map +1 -1
  25. package/dist/cjs/HttpBody.js.map +1 -1
  26. package/dist/cjs/HttpIncomingMessage.js +5 -1
  27. package/dist/cjs/HttpIncomingMessage.js.map +1 -1
  28. package/dist/cjs/HttpServer.js +12 -1
  29. package/dist/cjs/HttpServer.js.map +1 -1
  30. package/dist/cjs/HttpServerRespondable.js +1 -1
  31. package/dist/cjs/HttpServerRespondable.js.map +1 -1
  32. package/dist/cjs/OpenApi.js +102 -63
  33. package/dist/cjs/OpenApi.js.map +1 -1
  34. package/dist/cjs/OpenApiJsonSchema.js +58 -47
  35. package/dist/cjs/OpenApiJsonSchema.js.map +1 -1
  36. package/dist/cjs/Transferable.js +2 -2
  37. package/dist/cjs/Transferable.js.map +1 -1
  38. package/dist/cjs/UrlParams.js +5 -1
  39. package/dist/cjs/UrlParams.js.map +1 -1
  40. package/dist/cjs/Worker.js.map +1 -1
  41. package/dist/cjs/WorkerError.js +1 -5
  42. package/dist/cjs/WorkerError.js.map +1 -1
  43. package/dist/cjs/WorkerRunner.js.map +1 -1
  44. package/dist/cjs/index.js +3 -1
  45. package/dist/cjs/internal/httpBody.js +1 -1
  46. package/dist/cjs/internal/httpBody.js.map +1 -1
  47. package/dist/cjs/internal/httpClientRequest.js.map +1 -1
  48. package/dist/cjs/internal/httpClientResponse.js +1 -1
  49. package/dist/cjs/internal/httpClientResponse.js.map +1 -1
  50. package/dist/cjs/internal/httpRouter.js +1 -1
  51. package/dist/cjs/internal/httpRouter.js.map +1 -1
  52. package/dist/cjs/internal/httpServer.js +7 -1
  53. package/dist/cjs/internal/httpServer.js.map +1 -1
  54. package/dist/cjs/internal/httpServerRequest.js +1 -1
  55. package/dist/cjs/internal/httpServerRequest.js.map +1 -1
  56. package/dist/cjs/internal/httpServerResponse.js.map +1 -1
  57. package/dist/cjs/internal/keyValueStore.js +1 -1
  58. package/dist/cjs/internal/keyValueStore.js.map +1 -1
  59. package/dist/cjs/internal/multipart.js +1 -1
  60. package/dist/cjs/internal/multipart.js.map +1 -1
  61. package/dist/cjs/internal/worker.js +6 -7
  62. package/dist/cjs/internal/worker.js.map +1 -1
  63. package/dist/cjs/internal/workerRunner.js +3 -4
  64. package/dist/cjs/internal/workerRunner.js.map +1 -1
  65. package/dist/dts/Headers.d.ts +4 -6
  66. package/dist/dts/Headers.d.ts.map +1 -1
  67. package/dist/dts/HttpApi.d.ts +64 -140
  68. package/dist/dts/HttpApi.d.ts.map +1 -1
  69. package/dist/dts/HttpApiBuilder.d.ts +86 -167
  70. package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
  71. package/dist/dts/HttpApiClient.d.ts +34 -11
  72. package/dist/dts/HttpApiClient.d.ts.map +1 -1
  73. package/dist/dts/HttpApiEndpoint.d.ts +119 -273
  74. package/dist/dts/HttpApiEndpoint.d.ts.map +1 -1
  75. package/dist/dts/HttpApiError.d.ts +5 -2
  76. package/dist/dts/HttpApiError.d.ts.map +1 -1
  77. package/dist/dts/HttpApiGroup.d.ts +96 -194
  78. package/dist/dts/HttpApiGroup.d.ts.map +1 -1
  79. package/dist/dts/HttpApiMiddleware.d.ts +228 -0
  80. package/dist/dts/HttpApiMiddleware.d.ts.map +1 -0
  81. package/dist/dts/HttpApiSchema.d.ts +6 -2
  82. package/dist/dts/HttpApiSchema.d.ts.map +1 -1
  83. package/dist/dts/HttpApiSecurity.d.ts +1 -1
  84. package/dist/dts/HttpApiSecurity.d.ts.map +1 -1
  85. package/dist/dts/HttpApiSwagger.d.ts +2 -2
  86. package/dist/dts/HttpApiSwagger.d.ts.map +1 -1
  87. package/dist/dts/HttpBody.d.ts +2 -2
  88. package/dist/dts/HttpBody.d.ts.map +1 -1
  89. package/dist/dts/HttpClientRequest.d.ts +2 -2
  90. package/dist/dts/HttpClientRequest.d.ts.map +1 -1
  91. package/dist/dts/HttpClientResponse.d.ts +3 -3
  92. package/dist/dts/HttpClientResponse.d.ts.map +1 -1
  93. package/dist/dts/HttpIncomingMessage.d.ts +3 -3
  94. package/dist/dts/HttpIncomingMessage.d.ts.map +1 -1
  95. package/dist/dts/HttpRouter.d.ts +3 -3
  96. package/dist/dts/HttpRouter.d.ts.map +1 -1
  97. package/dist/dts/HttpServer.d.ts +15 -0
  98. package/dist/dts/HttpServer.d.ts.map +1 -1
  99. package/dist/dts/HttpServerRequest.d.ts +3 -3
  100. package/dist/dts/HttpServerRequest.d.ts.map +1 -1
  101. package/dist/dts/HttpServerRespondable.d.ts.map +1 -1
  102. package/dist/dts/HttpServerResponse.d.ts +2 -2
  103. package/dist/dts/HttpServerResponse.d.ts.map +1 -1
  104. package/dist/dts/KeyValueStore.d.ts +2 -2
  105. package/dist/dts/KeyValueStore.d.ts.map +1 -1
  106. package/dist/dts/Multipart.d.ts +3 -3
  107. package/dist/dts/Multipart.d.ts.map +1 -1
  108. package/dist/dts/OpenApi.d.ts +17 -39
  109. package/dist/dts/OpenApi.d.ts.map +1 -1
  110. package/dist/dts/OpenApiJsonSchema.d.ts +10 -5
  111. package/dist/dts/OpenApiJsonSchema.d.ts.map +1 -1
  112. package/dist/dts/Transferable.d.ts +4 -1
  113. package/dist/dts/Transferable.d.ts.map +1 -1
  114. package/dist/dts/UrlParams.d.ts +3 -6
  115. package/dist/dts/UrlParams.d.ts.map +1 -1
  116. package/dist/dts/Worker.d.ts +7 -8
  117. package/dist/dts/Worker.d.ts.map +1 -1
  118. package/dist/dts/WorkerError.d.ts +1 -1
  119. package/dist/dts/WorkerError.d.ts.map +1 -1
  120. package/dist/dts/WorkerRunner.d.ts +2 -3
  121. package/dist/dts/WorkerRunner.d.ts.map +1 -1
  122. package/dist/dts/index.d.ts +4 -0
  123. package/dist/dts/index.d.ts.map +1 -1
  124. package/dist/dts/internal/httpRouter.d.ts.map +1 -1
  125. package/dist/esm/Headers.js +7 -2
  126. package/dist/esm/Headers.js.map +1 -1
  127. package/dist/esm/HttpApi.js +88 -77
  128. package/dist/esm/HttpApi.js.map +1 -1
  129. package/dist/esm/HttpApiBuilder.js +238 -244
  130. package/dist/esm/HttpApiBuilder.js.map +1 -1
  131. package/dist/esm/HttpApiClient.js +64 -59
  132. package/dist/esm/HttpApiClient.js.map +1 -1
  133. package/dist/esm/HttpApiEndpoint.js +73 -106
  134. package/dist/esm/HttpApiEndpoint.js.map +1 -1
  135. package/dist/esm/HttpApiError.js +3 -4
  136. package/dist/esm/HttpApiError.js.map +1 -1
  137. package/dist/esm/HttpApiGroup.js +102 -99
  138. package/dist/esm/HttpApiGroup.js.map +1 -1
  139. package/dist/esm/HttpApiMiddleware.js +56 -0
  140. package/dist/esm/HttpApiMiddleware.js.map +1 -0
  141. package/dist/esm/HttpApiSchema.js +31 -5
  142. package/dist/esm/HttpApiSchema.js.map +1 -1
  143. package/dist/esm/HttpApiSecurity.js +1 -1
  144. package/dist/esm/HttpApiSecurity.js.map +1 -1
  145. package/dist/esm/HttpApiSwagger.js +4 -2
  146. package/dist/esm/HttpApiSwagger.js.map +1 -1
  147. package/dist/esm/HttpBody.js.map +1 -1
  148. package/dist/esm/HttpIncomingMessage.js +4 -1
  149. package/dist/esm/HttpIncomingMessage.js.map +1 -1
  150. package/dist/esm/HttpServer.js +11 -0
  151. package/dist/esm/HttpServer.js.map +1 -1
  152. package/dist/esm/HttpServerRespondable.js +1 -1
  153. package/dist/esm/HttpServerRespondable.js.map +1 -1
  154. package/dist/esm/OpenApi.js +97 -59
  155. package/dist/esm/OpenApi.js.map +1 -1
  156. package/dist/esm/OpenApiJsonSchema.js +56 -46
  157. package/dist/esm/OpenApiJsonSchema.js.map +1 -1
  158. package/dist/esm/Transferable.js +2 -2
  159. package/dist/esm/Transferable.js.map +1 -1
  160. package/dist/esm/UrlParams.js +4 -1
  161. package/dist/esm/UrlParams.js.map +1 -1
  162. package/dist/esm/Worker.js.map +1 -1
  163. package/dist/esm/WorkerError.js +1 -4
  164. package/dist/esm/WorkerError.js.map +1 -1
  165. package/dist/esm/WorkerRunner.js.map +1 -1
  166. package/dist/esm/index.js +4 -0
  167. package/dist/esm/index.js.map +1 -1
  168. package/dist/esm/internal/httpBody.js +1 -1
  169. package/dist/esm/internal/httpBody.js.map +1 -1
  170. package/dist/esm/internal/httpClientRequest.js.map +1 -1
  171. package/dist/esm/internal/httpClientResponse.js +1 -1
  172. package/dist/esm/internal/httpClientResponse.js.map +1 -1
  173. package/dist/esm/internal/httpRouter.js +1 -1
  174. package/dist/esm/internal/httpRouter.js.map +1 -1
  175. package/dist/esm/internal/httpServer.js +6 -0
  176. package/dist/esm/internal/httpServer.js.map +1 -1
  177. package/dist/esm/internal/httpServerRequest.js +1 -1
  178. package/dist/esm/internal/httpServerRequest.js.map +1 -1
  179. package/dist/esm/internal/httpServerResponse.js.map +1 -1
  180. package/dist/esm/internal/keyValueStore.js +1 -1
  181. package/dist/esm/internal/keyValueStore.js.map +1 -1
  182. package/dist/esm/internal/multipart.js +1 -1
  183. package/dist/esm/internal/multipart.js.map +1 -1
  184. package/dist/esm/internal/worker.js +6 -7
  185. package/dist/esm/internal/worker.js.map +1 -1
  186. package/dist/esm/internal/workerRunner.js +3 -4
  187. package/dist/esm/internal/workerRunner.js.map +1 -1
  188. package/package.json +10 -3
  189. package/src/Headers.ts +12 -4
  190. package/src/HttpApi.ts +183 -258
  191. package/src/HttpApiBuilder.ts +534 -481
  192. package/src/HttpApiClient.ts +163 -112
  193. package/src/HttpApiEndpoint.ts +443 -564
  194. package/src/HttpApiError.ts +4 -6
  195. package/src/HttpApiGroup.ts +277 -325
  196. package/src/HttpApiMiddleware.ts +317 -0
  197. package/src/HttpApiSchema.ts +39 -2
  198. package/src/HttpApiSecurity.ts +1 -1
  199. package/src/HttpApiSwagger.ts +3 -3
  200. package/src/HttpBody.ts +2 -2
  201. package/src/HttpClientRequest.ts +2 -2
  202. package/src/HttpClientResponse.ts +3 -3
  203. package/src/HttpIncomingMessage.ts +3 -3
  204. package/src/HttpRouter.ts +3 -3
  205. package/src/HttpServer.ts +21 -0
  206. package/src/HttpServerRequest.ts +3 -3
  207. package/src/HttpServerRespondable.ts +1 -1
  208. package/src/HttpServerResponse.ts +2 -2
  209. package/src/KeyValueStore.ts +2 -2
  210. package/src/Multipart.ts +3 -3
  211. package/src/OpenApi.ts +113 -104
  212. package/src/OpenApiJsonSchema.ts +67 -53
  213. package/src/Transferable.ts +2 -2
  214. package/src/UrlParams.ts +3 -3
  215. package/src/Worker.ts +7 -8
  216. package/src/WorkerError.ts +1 -1
  217. package/src/WorkerRunner.ts +2 -3
  218. package/src/index.ts +5 -0
  219. package/src/internal/httpBody.ts +2 -2
  220. package/src/internal/httpClientRequest.ts +2 -2
  221. package/src/internal/httpClientResponse.ts +3 -3
  222. package/src/internal/httpRouter.ts +2 -2
  223. package/src/internal/httpServer.ts +13 -0
  224. package/src/internal/httpServerRequest.ts +3 -3
  225. package/src/internal/httpServerResponse.ts +2 -2
  226. package/src/internal/keyValueStore.ts +1 -1
  227. package/src/internal/multipart.ts +3 -3
  228. package/src/internal/worker.ts +6 -7
  229. package/src/internal/workerRunner.ts +3 -4
package/src/HttpApi.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  /**
2
2
  * @since 1.0.0
3
3
  */
4
- import * as AST from "@effect/schema/AST"
5
- import type * as Schema from "@effect/schema/Schema"
6
- import * as Chunk from "effect/Chunk"
7
4
  import * as Context from "effect/Context"
8
- import { dual } from "effect/Function"
5
+ import * as HashMap from "effect/HashMap"
6
+ import * as HashSet from "effect/HashSet"
9
7
  import * as Option from "effect/Option"
10
- import type { Pipeable } from "effect/Pipeable"
11
- import { pipeArguments } from "effect/Pipeable"
8
+ import { type Pipeable, pipeArguments } from "effect/Pipeable"
12
9
  import * as Predicate from "effect/Predicate"
13
- import * as HttpApiEndpoint from "./HttpApiEndpoint.js"
10
+ import type * as Schema from "effect/Schema"
11
+ import * as AST from "effect/SchemaAST"
12
+ import type * as HttpApiEndpoint from "./HttpApiEndpoint.js"
14
13
  import { HttpApiDecodeError } from "./HttpApiError.js"
15
- import * as HttpApiGroup from "./HttpApiGroup.js"
14
+ import type * as HttpApiGroup from "./HttpApiGroup.js"
15
+ import type * as HttpApiMiddleware from "./HttpApiMiddleware.js"
16
16
  import * as HttpApiSchema from "./HttpApiSchema.js"
17
17
  import type { HttpMethod } from "./HttpMethod.js"
18
- import type * as HttpRouter from "./HttpRouter.js"
18
+ import type { PathInput } from "./HttpRouter.js"
19
19
 
20
20
  /**
21
21
  * @since 1.0.0
@@ -33,34 +33,78 @@ export type TypeId = typeof TypeId
33
33
  * @since 1.0.0
34
34
  * @category guards
35
35
  */
36
- export const isHttpApi = (u: unknown): u is HttpApi<any, any> => Predicate.hasProperty(u, TypeId)
36
+ export const isHttpApi = (u: unknown): u is HttpApi.Any => Predicate.hasProperty(u, TypeId)
37
37
 
38
38
  /**
39
- * An `HttpApi` represents a collection of `HttpApiGroup`s. You can use an `HttpApi` to
40
- * represent your entire domain.
39
+ * An `HttpApi` is a collection of `HttpApiEndpoint`s. You can use an `HttpApi` to
40
+ * represent a portion of your domain.
41
+ *
42
+ * The endpoints can be implemented later using the `HttpApiBuilder.make` api.
41
43
  *
42
44
  * @since 1.0.0
43
45
  * @category models
44
46
  */
45
47
  export interface HttpApi<
46
48
  out Groups extends HttpApiGroup.HttpApiGroup.Any = never,
47
- in out Error = never,
48
- out ErrorR = never
49
+ in out E = never,
50
+ out R = never
49
51
  > extends Pipeable {
50
52
  new(_: never): {}
51
53
  readonly [TypeId]: TypeId
52
- readonly groups: Chunk.Chunk<Groups>
53
- readonly errorSchema: Schema.Schema<Error, unknown, ErrorR>
54
+ readonly groups: HashMap.HashMap<string, Groups>
54
55
  readonly annotations: Context.Context<never>
56
+ readonly errorSchema: Schema.Schema<E, unknown, R>
57
+ readonly middlewares: HashSet.HashSet<HttpApiMiddleware.TagClassAny>
58
+
59
+ /**
60
+ * Add an endpoint to the `HttpApi`.
61
+ */
62
+ add<A extends HttpApiGroup.HttpApiGroup.Any>(group: A): HttpApi<Groups | A, E, R>
63
+ /**
64
+ * Add an global error to the `HttpApi`.
65
+ */
66
+ addError<A, I, RX>(
67
+ schema: Schema.Schema<A, I, RX>,
68
+ annotations?: {
69
+ readonly status?: number | undefined
70
+ }
71
+ ): HttpApi<Groups, E | A, R | RX>
72
+ /**
73
+ * Prefix all endpoints in the `HttpApi`.
74
+ */
75
+ prefix(prefix: PathInput): HttpApi<Groups, E, R>
76
+ /**
77
+ * Add a middleware to a `HttpApi`. It will be applied to all endpoints in the
78
+ * `HttpApi`.
79
+ */
80
+ middleware<I extends HttpApiMiddleware.HttpApiMiddleware.AnyId, S>(
81
+ middleware: Context.Tag<I, S>
82
+ ): HttpApi<
83
+ Groups,
84
+ E | HttpApiMiddleware.HttpApiMiddleware.Error<I>,
85
+ R | I | HttpApiMiddleware.HttpApiMiddleware.ErrorContext<I>
86
+ >
87
+ /**
88
+ * Annotate the `HttpApi`.
89
+ */
90
+ annotate<I, S>(tag: Context.Tag<I, S>, value: S): HttpApi<Groups, E, R>
91
+ /**
92
+ * Annotate the `HttpApi` with a Context.
93
+ */
94
+ annotateContext<I>(context: Context.Context<I>): HttpApi<Groups, E, R>
55
95
  }
56
96
 
57
97
  /**
58
98
  * @since 1.0.0
59
99
  * @category tags
60
100
  */
61
- export const HttpApi: Context.Tag<HttpApi.Service, HttpApi.Any> = Context.GenericTag<HttpApi.Service, HttpApi.Any>(
62
- "@effect/platform/HttpApi"
63
- )
101
+ export class Api extends Context.Tag("@effect/platform/HttpApi/Api")<
102
+ Api,
103
+ {
104
+ readonly api: HttpApi<HttpApiGroup.HttpApiGroup.AnyWithProps>
105
+ readonly context: Context.Context<never>
106
+ }
107
+ >() {}
64
108
 
65
109
  /**
66
110
  * @since 1.0.0
@@ -71,241 +115,122 @@ export declare namespace HttpApi {
71
115
  * @since 1.0.0
72
116
  * @category models
73
117
  */
74
- export interface Service {
75
- readonly _: unique symbol
76
- }
77
-
78
- /**
79
- * @since 1.0.0
80
- * @category models
81
- */
82
- export interface Any extends Pipeable {
83
- new(_: never): {}
118
+ export interface Any {
84
119
  readonly [TypeId]: TypeId
85
- readonly groups: Chunk.Chunk<HttpApiGroup.HttpApiGroup.Any>
86
- readonly errorSchema: Schema.Schema.All
87
- readonly annotations: Context.Context<never>
88
120
  }
89
121
 
90
122
  /**
91
123
  * @since 1.0.0
92
124
  * @category models
93
125
  */
94
- export type Context<A> = A extends HttpApi<infer _Groups, infer _ApiError, infer _ApiErrorR>
95
- ? _ApiErrorR | HttpApiGroup.HttpApiGroup.Context<_Groups>
96
- : never
126
+ export type AnyWithProps = HttpApi<HttpApiGroup.HttpApiGroup.AnyWithProps, any, any>
97
127
  }
98
128
 
99
129
  const Proto = {
100
130
  [TypeId]: TypeId,
101
131
  pipe() {
102
132
  return pipeArguments(this, arguments)
133
+ },
134
+ add(
135
+ this: HttpApi.AnyWithProps,
136
+ group: HttpApiGroup.HttpApiGroup.AnyWithProps
137
+ ) {
138
+ return makeProto({
139
+ groups: HashMap.set(this.groups, group.identifier, group),
140
+ errorSchema: this.errorSchema,
141
+ annotations: this.annotations,
142
+ middlewares: this.middlewares
143
+ })
144
+ },
145
+ addError(
146
+ this: HttpApi.AnyWithProps,
147
+ schema: Schema.Schema.Any,
148
+ annotations?: { readonly status?: number }
149
+ ) {
150
+ return makeProto({
151
+ groups: this.groups,
152
+ errorSchema: HttpApiSchema.UnionUnify(
153
+ this.errorSchema,
154
+ schema.annotations(HttpApiSchema.annotations({
155
+ status: annotations?.status ?? HttpApiSchema.getStatusError(schema)
156
+ }))
157
+ ),
158
+ annotations: this.annotations,
159
+ middlewares: this.middlewares
160
+ })
161
+ },
162
+ prefix(this: HttpApi.AnyWithProps, prefix: PathInput) {
163
+ return makeProto({
164
+ groups: HashMap.map(this.groups, (group) => group.prefix(prefix)),
165
+ errorSchema: this.errorSchema,
166
+ annotations: this.annotations,
167
+ middlewares: this.middlewares
168
+ })
169
+ },
170
+ middleware(this: HttpApi.AnyWithProps, tag: HttpApiMiddleware.TagClassAny) {
171
+ return makeProto({
172
+ groups: this.groups,
173
+ errorSchema: HttpApiSchema.UnionUnify(
174
+ this.errorSchema,
175
+ tag.failure.annotations(HttpApiSchema.annotations({
176
+ status: HttpApiSchema.getStatusError(tag.failure)
177
+ }) as any)
178
+ ),
179
+ annotations: this.annotations,
180
+ middlewares: HashSet.add(this.middlewares, tag)
181
+ })
182
+ },
183
+ annotate(this: HttpApi.AnyWithProps, tag: Context.Tag<any, any>, value: any) {
184
+ return makeProto({
185
+ groups: this.groups,
186
+ errorSchema: this.errorSchema,
187
+ annotations: Context.add(this.annotations, tag, value),
188
+ middlewares: this.middlewares
189
+ })
190
+ },
191
+ annotateContext(this: HttpApi.AnyWithProps, context: Context.Context<any>) {
192
+ return makeProto({
193
+ groups: this.groups,
194
+ errorSchema: this.errorSchema,
195
+ annotations: Context.merge(this.annotations, context),
196
+ middlewares: this.middlewares
197
+ })
103
198
  }
104
199
  }
105
200
 
106
- const makeProto = <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR>(options: {
107
- readonly groups: Chunk.Chunk<Groups>
108
- readonly errorSchema: Schema.Schema<Error, unknown, ErrorR>
109
- readonly annotations: Context.Context<never>
110
- }): HttpApi<Groups, Error, ErrorR> => {
201
+ const makeProto = <Groups extends HttpApiGroup.HttpApiGroup.Any, E, I, R>(
202
+ options: {
203
+ readonly groups: HashMap.HashMap<string, Groups>
204
+ readonly errorSchema: Schema.Schema<E, I, R>
205
+ readonly annotations: Context.Context<never>
206
+ readonly middlewares: HashSet.HashSet<HttpApiMiddleware.TagClassAny>
207
+ }
208
+ ): HttpApi<Groups, E, R> => {
111
209
  function HttpApi() {}
112
210
  Object.setPrototypeOf(HttpApi, Proto)
113
- return Object.assign(HttpApi, options) as any
211
+ HttpApi.groups = options.groups
212
+ HttpApi.errorSchema = options.errorSchema
213
+ HttpApi.annotations = options.annotations
214
+ HttpApi.middlewares = options.middlewares
215
+ return HttpApi as any
114
216
  }
115
217
 
116
218
  /**
117
- * An empty `HttpApi`. You can use this to start building your `HttpApi`.
219
+ * An `HttpApi` is a collection of `HttpApiEndpoint`s. You can use an `HttpApi` to
220
+ * represent a portion of your domain.
118
221
  *
119
- * You can add groups to this `HttpApi` using the `addGroup` function.
222
+ * The endpoints can be implemented later using the `HttpApiBuilder.make` api.
120
223
  *
121
224
  * @since 1.0.0
122
225
  * @category constructors
123
226
  */
124
- export const empty: HttpApi = makeProto({
125
- groups: Chunk.empty(),
126
- errorSchema: HttpApiDecodeError as any,
127
- annotations: Context.empty()
227
+ export const empty: HttpApi<never, HttpApiDecodeError> = makeProto({
228
+ groups: HashMap.empty(),
229
+ errorSchema: HttpApiDecodeError,
230
+ annotations: Context.empty(),
231
+ middlewares: HashSet.empty()
128
232
  })
129
233
 
130
- /**
131
- * Add a `HttpApiGroup` to an `HttpApi`.
132
- *
133
- * @since 1.0.0
134
- * @category constructors
135
- */
136
- export const addGroup: {
137
- /**
138
- * Add a `HttpApiGroup` to an `HttpApi`.
139
- *
140
- * @since 1.0.0
141
- * @category constructors
142
- */
143
- <Group extends HttpApiGroup.HttpApiGroup.Any>(
144
- group: Group
145
- ): <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR>(
146
- self: HttpApi<Groups, Error, ErrorR>
147
- ) => HttpApi<Groups | Group, Error, ErrorR>
148
- /**
149
- * Add a `HttpApiGroup` to an `HttpApi`.
150
- *
151
- * @since 1.0.0
152
- * @category constructors
153
- */
154
- <Group extends HttpApiGroup.HttpApiGroup.Any>(
155
- path: HttpRouter.PathInput,
156
- group: Group
157
- ): <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR>(
158
- self: HttpApi<Groups, Error, ErrorR>
159
- ) => HttpApi<Groups | Group, Error, ErrorR>
160
- /**
161
- * Add a `HttpApiGroup` to an `HttpApi`.
162
- *
163
- * @since 1.0.0
164
- * @category constructors
165
- */
166
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, Group extends HttpApiGroup.HttpApiGroup.Any>(
167
- self: HttpApi<Groups, Error, ErrorR>,
168
- group: Group
169
- ): HttpApi<Groups | Group, Error, ErrorR>
170
- /**
171
- * Add a `HttpApiGroup` to an `HttpApi`.
172
- *
173
- * @since 1.0.0
174
- * @category constructors
175
- */
176
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, Group extends HttpApiGroup.HttpApiGroup.Any>(
177
- self: HttpApi<Groups, Error, ErrorR>,
178
- path: HttpRouter.PathInput,
179
- group: Group
180
- ): HttpApi<Groups | Group, Error, ErrorR>
181
- } = dual(
182
- (args) => isHttpApi(args[0]),
183
- (
184
- self: HttpApi.Any,
185
- ...args: [group: HttpApiGroup.HttpApiGroup.Any] | [path: HttpRouter.PathInput, group: HttpApiGroup.HttpApiGroup.Any]
186
- ): HttpApi.Any => {
187
- const group = args.length === 1 ? args[0] : HttpApiGroup.prefix(args[1] as any, args[0])
188
- return makeProto({
189
- errorSchema: self.errorSchema as any,
190
- annotations: self.annotations,
191
- groups: Chunk.append(self.groups, group)
192
- })
193
- }
194
- )
195
- /**
196
- * Add an error schema to an `HttpApi`, which is shared by all endpoints in the
197
- * `HttpApi`.
198
- *
199
- * Useful for adding error types from middleware or other shared error types.
200
- *
201
- * @since 1.0.0
202
- * @category errors
203
- */
204
- export const addError: {
205
- /**
206
- * Add an error schema to an `HttpApi`, which is shared by all endpoints in the
207
- * `HttpApi`.
208
- *
209
- * Useful for adding error types from middleware or other shared error types.
210
- *
211
- * @since 1.0.0
212
- * @category errors
213
- */
214
- <A, I, R>(
215
- schema: Schema.Schema<A, I, R>,
216
- annotations?: {
217
- readonly status?: number | undefined
218
- }
219
- ): <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR>(
220
- self: HttpApi<Groups, Error, ErrorR>
221
- ) => HttpApi<Groups, Error | A, ErrorR | R>
222
- /**
223
- * Add an error schema to an `HttpApi`, which is shared by all endpoints in the
224
- * `HttpApi`.
225
- *
226
- * Useful for adding error types from middleware or other shared error types.
227
- *
228
- * @since 1.0.0
229
- * @category errors
230
- */
231
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, A, I, R>(
232
- self: HttpApi<Groups, Error, ErrorR>,
233
- schema: Schema.Schema<A, I, R>,
234
- annotations?: {
235
- readonly status?: number | undefined
236
- }
237
- ): HttpApi<Groups, Error | A, ErrorR | R>
238
- } = dual(
239
- (args) => isHttpApi(args[0]),
240
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, A, I, R>(
241
- self: HttpApi<Groups, Error, ErrorR>,
242
- schema: Schema.Schema<A, I, R>,
243
- annotations?: {
244
- readonly status?: number | undefined
245
- }
246
- ): HttpApi<Groups, Error | A, ErrorR | R> =>
247
- makeProto({
248
- groups: self.groups,
249
- annotations: self.annotations,
250
- errorSchema: HttpApiSchema.UnionUnify(
251
- self.errorSchema,
252
- schema.annotations(HttpApiSchema.annotations({
253
- status: annotations?.status ?? HttpApiSchema.getStatusError(schema)
254
- }))
255
- )
256
- })
257
- )
258
-
259
- /**
260
- * @since 1.0.0
261
- * @category annotations
262
- */
263
- export const annotateMerge: {
264
- /**
265
- * @since 1.0.0
266
- * @category annotations
267
- */
268
- <I>(context: Context.Context<I>): <A extends HttpApi.Any>(self: A) => A
269
- /**
270
- * @since 1.0.0
271
- * @category annotations
272
- */
273
- <A extends HttpApi.Any, I>(self: A, context: Context.Context<I>): A
274
- } = dual(
275
- 2,
276
- <A extends HttpApi.Any, I>(self: A, context: Context.Context<I>): A =>
277
- makeProto({
278
- groups: self.groups,
279
- errorSchema: self.errorSchema as any,
280
- annotations: Context.merge(self.annotations, context)
281
- }) as A
282
- )
283
-
284
- /**
285
- * @since 1.0.0
286
- * @category annotations
287
- */
288
- export const annotate: {
289
- /**
290
- * @since 1.0.0
291
- * @category annotations
292
- */
293
- <I, S>(tag: Context.Tag<I, S>, value: S): <A extends HttpApi.Any>(self: A) => A
294
- /**
295
- * @since 1.0.0
296
- * @category annotations
297
- */
298
- <A extends HttpApi.Any, I, S>(self: A, tag: Context.Tag<I, S>, value: S): A
299
- } = dual(
300
- 3,
301
- <A extends HttpApi.Any, I, S>(self: A, tag: Context.Tag<I, S>, value: S): A =>
302
- makeProto({
303
- groups: self.groups,
304
- errorSchema: self.errorSchema as any,
305
- annotations: Context.add(self.annotations, tag, value)
306
- }) as A
307
- )
308
-
309
234
  /**
310
235
  * Extract metadata from an `HttpApi`, which can be used to generate documentation
311
236
  * or other tooling.
@@ -315,46 +240,42 @@ export const annotate: {
315
240
  * @since 1.0.0
316
241
  * @category reflection
317
242
  */
318
- export const reflect = <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR>(
319
- self: HttpApi<Groups, Error, ErrorR>,
243
+ export const reflect = <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, R>(
244
+ self: HttpApi<Groups, Error, R>,
320
245
  options: {
321
246
  readonly onGroup: (options: {
322
- readonly group: HttpApiGroup.HttpApiGroup<string, any>
247
+ readonly group: HttpApiGroup.HttpApiGroup.AnyWithProps
323
248
  readonly mergedAnnotations: Context.Context<never>
324
249
  }) => void
325
250
  readonly onEndpoint: (options: {
326
- readonly group: HttpApiGroup.HttpApiGroup<string, any>
251
+ readonly group: HttpApiGroup.HttpApiGroup.AnyWithProps
327
252
  readonly endpoint: HttpApiEndpoint.HttpApiEndpoint<string, HttpMethod>
328
253
  readonly mergedAnnotations: Context.Context<never>
329
- readonly successAST: Option.Option<AST.AST>
330
- readonly successStatus: number
331
- readonly successEncoding: HttpApiSchema.Encoding
254
+ readonly middleware: HashSet.HashSet<HttpApiMiddleware.TagClassAny>
255
+ readonly successes: ReadonlyMap<number, Option.Option<AST.AST>>
332
256
  readonly errors: ReadonlyMap<number, Option.Option<AST.AST>>
333
257
  }) => void
334
258
  }
335
259
  ) => {
336
- const apiErrors = extractErrors(self.errorSchema.ast, new Map())
337
-
338
- const groups = self.groups as Iterable<HttpApiGroup.HttpApiGroup<string, any>>
339
- for (const group of groups) {
340
- const groupErrors = extractErrors(group.errorSchema.ast, apiErrors)
260
+ const apiErrors = extractMembers(self.errorSchema.ast, new Map(), HttpApiSchema.getStatusErrorAST)
261
+ const groups = self.groups as Iterable<[string, HttpApiGroup.HttpApiGroup.AnyWithProps]>
262
+ for (const [, group] of groups) {
263
+ const groupErrors = extractMembers(group.errorSchema.ast, apiErrors, HttpApiSchema.getStatusErrorAST)
341
264
  const groupAnnotations = Context.merge(self.annotations, group.annotations)
342
265
  options.onGroup({
343
266
  group,
344
267
  mergedAnnotations: groupAnnotations
345
268
  })
346
- const endpoints = group.endpoints as Iterable<HttpApiEndpoint.HttpApiEndpoint<string, HttpMethod>>
347
- for (const endpoint of endpoints) {
269
+ const endpoints = group.endpoints as Iterable<[string, HttpApiEndpoint.HttpApiEndpoint<string, HttpMethod>]>
270
+ for (const [, endpoint] of endpoints) {
271
+ const errors = extractMembers(endpoint.errorSchema.ast, groupErrors, HttpApiSchema.getStatusErrorAST)
348
272
  options.onEndpoint({
349
273
  group,
350
274
  endpoint,
275
+ middleware: HashSet.union(group.middlewares, endpoint.middlewares),
351
276
  mergedAnnotations: Context.merge(groupAnnotations, endpoint.annotations),
352
- successAST: HttpApiEndpoint.schemaSuccess(endpoint).pipe(
353
- Option.map((schema) => schema.ast)
354
- ),
355
- successStatus: HttpApiSchema.getStatusSuccess(endpoint.successSchema),
356
- successEncoding: HttpApiSchema.getEncoding(endpoint.successSchema.ast),
357
- errors: extractErrors(endpoint.errorSchema.ast, groupErrors)
277
+ successes: extractMembers(endpoint.successSchema.ast, new Map(), HttpApiSchema.getStatusSuccessAST),
278
+ errors
358
279
  })
359
280
  }
360
281
  }
@@ -362,20 +283,24 @@ export const reflect = <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, Err
362
283
 
363
284
  // -------------------------------------------------------------------------------------
364
285
 
365
- const extractErrors = (
366
- ast: AST.AST,
367
- inherited: ReadonlyMap<number, Option.Option<AST.AST>>
286
+ const extractMembers = (
287
+ topAst: AST.AST,
288
+ inherited: ReadonlyMap<number, Option.Option<AST.AST>>,
289
+ getStatus: (ast: AST.AST) => number
368
290
  ): ReadonlyMap<number, Option.Option<AST.AST>> => {
369
- const topStatus = HttpApiSchema.getStatusErrorAST(ast)
370
- const errors = new Map(inherited)
291
+ const members = new Map(inherited)
371
292
  function process(ast: AST.AST) {
372
293
  if (ast._tag === "NeverKeyword") {
373
294
  return
374
295
  }
375
- const status = HttpApiSchema.getStatus(ast, topStatus)
296
+ ast = AST.annotations(ast, {
297
+ ...topAst.annotations,
298
+ ...ast.annotations
299
+ })
300
+ const status = getStatus(ast)
376
301
  const emptyDecodeable = HttpApiSchema.getEmptyDecodeable(ast)
377
- const current = errors.get(status) ?? Option.none()
378
- errors.set(
302
+ const current = members.get(status) ?? Option.none()
303
+ members.set(
379
304
  status,
380
305
  current.pipe(
381
306
  Option.map((current) =>
@@ -389,12 +314,12 @@ const extractErrors = (
389
314
  )
390
315
  )
391
316
  }
392
- if (ast._tag === "Union") {
393
- for (const type of ast.types) {
317
+ if (topAst._tag === "Union") {
318
+ for (const type of topAst.types) {
394
319
  process(type)
395
320
  }
396
321
  } else {
397
- process(ast)
322
+ process(topAst)
398
323
  }
399
- return errors
324
+ return members
400
325
  }