@effect/platform 0.70.7 → 0.71.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.
Files changed (47) hide show
  1. package/README.md +22 -34
  2. package/dist/cjs/HttpApi.js +15 -6
  3. package/dist/cjs/HttpApi.js.map +1 -1
  4. package/dist/cjs/HttpApiBuilder.js +1 -1
  5. package/dist/cjs/HttpApiBuilder.js.map +1 -1
  6. package/dist/cjs/HttpApiClient.js.map +1 -1
  7. package/dist/cjs/HttpApiError.js +109 -1
  8. package/dist/cjs/HttpApiError.js.map +1 -1
  9. package/dist/cjs/HttpApiGroup.js.map +1 -1
  10. package/dist/cjs/HttpApiSchema.js +46 -2
  11. package/dist/cjs/HttpApiSchema.js.map +1 -1
  12. package/dist/cjs/OpenApi.js +19 -2
  13. package/dist/cjs/OpenApi.js.map +1 -1
  14. package/dist/dts/HttpApi.d.ts +13 -12
  15. package/dist/dts/HttpApi.d.ts.map +1 -1
  16. package/dist/dts/HttpApiBuilder.d.ts +8 -8
  17. package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
  18. package/dist/dts/HttpApiClient.d.ts +3 -3
  19. package/dist/dts/HttpApiClient.d.ts.map +1 -1
  20. package/dist/dts/HttpApiError.d.ts +85 -0
  21. package/dist/dts/HttpApiError.d.ts.map +1 -1
  22. package/dist/dts/HttpApiGroup.d.ts +3 -2
  23. package/dist/dts/HttpApiGroup.d.ts.map +1 -1
  24. package/dist/dts/HttpApiSchema.d.ts +19 -1
  25. package/dist/dts/HttpApiSchema.d.ts.map +1 -1
  26. package/dist/dts/OpenApi.d.ts +8 -0
  27. package/dist/dts/OpenApi.d.ts.map +1 -1
  28. package/dist/esm/HttpApi.js +13 -5
  29. package/dist/esm/HttpApi.js.map +1 -1
  30. package/dist/esm/HttpApiBuilder.js +1 -1
  31. package/dist/esm/HttpApiBuilder.js.map +1 -1
  32. package/dist/esm/HttpApiClient.js.map +1 -1
  33. package/dist/esm/HttpApiError.js +96 -0
  34. package/dist/esm/HttpApiError.js.map +1 -1
  35. package/dist/esm/HttpApiGroup.js.map +1 -1
  36. package/dist/esm/HttpApiSchema.js +45 -2
  37. package/dist/esm/HttpApiSchema.js.map +1 -1
  38. package/dist/esm/OpenApi.js +16 -0
  39. package/dist/esm/OpenApi.js.map +1 -1
  40. package/package.json +2 -2
  41. package/src/HttpApi.ts +35 -19
  42. package/src/HttpApiBuilder.ts +17 -15
  43. package/src/HttpApiClient.ts +8 -6
  44. package/src/HttpApiError.ts +108 -0
  45. package/src/HttpApiGroup.ts +4 -3
  46. package/src/HttpApiSchema.ts +63 -5
  47. package/src/OpenApi.ts +18 -1
package/src/HttpApi.ts CHANGED
@@ -45,12 +45,14 @@ export const isHttpApi = (u: unknown): u is HttpApi.Any => Predicate.hasProperty
45
45
  * @category models
46
46
  */
47
47
  export interface HttpApi<
48
+ out Id extends string,
48
49
  out Groups extends HttpApiGroup.HttpApiGroup.Any = never,
49
50
  in out E = never,
50
51
  out R = never
51
52
  > extends Pipeable {
52
53
  new(_: never): {}
53
54
  readonly [TypeId]: TypeId
55
+ readonly identifier: Id
54
56
  readonly groups: Record.ReadonlyRecord<string, Groups>
55
57
  readonly annotations: Context.Context<never>
56
58
  readonly errorSchema: Schema.Schema<E, unknown, R>
@@ -59,11 +61,14 @@ export interface HttpApi<
59
61
  /**
60
62
  * Add a `HttpApiGroup` to the `HttpApi`.
61
63
  */
62
- add<A extends HttpApiGroup.HttpApiGroup.Any>(group: A): HttpApi<Groups | A, E, R>
64
+ add<A extends HttpApiGroup.HttpApiGroup.Any>(group: A): HttpApi<Id, Groups | A, E, R>
63
65
  /**
64
66
  * Add another `HttpApi` to the `HttpApi`.
65
67
  */
66
- addHttpApi<Groups2 extends HttpApiGroup.HttpApiGroup.Any, E2, R2>(api: HttpApi<Groups2, E2, R2>): HttpApi<
68
+ addHttpApi<Id2 extends string, Groups2 extends HttpApiGroup.HttpApiGroup.Any, E2, R2>(
69
+ api: HttpApi<Id2, Groups2, E2, R2>
70
+ ): HttpApi<
71
+ Id,
67
72
  Groups | HttpApiGroup.HttpApiGroup.AddContext<Groups2, R2>,
68
73
  E | E2,
69
74
  R
@@ -76,11 +81,11 @@ export interface HttpApi<
76
81
  annotations?: {
77
82
  readonly status?: number | undefined
78
83
  }
79
- ): HttpApi<Groups, E | A, R | RX>
84
+ ): HttpApi<Id, Groups, E | A, R | RX>
80
85
  /**
81
86
  * Prefix all endpoints in the `HttpApi`.
82
87
  */
83
- prefix(prefix: PathInput): HttpApi<Groups, E, R>
88
+ prefix(prefix: PathInput): HttpApi<Id, Groups, E, R>
84
89
  /**
85
90
  * Add a middleware to a `HttpApi`. It will be applied to all endpoints in the
86
91
  * `HttpApi`.
@@ -88,6 +93,7 @@ export interface HttpApi<
88
93
  middleware<I extends HttpApiMiddleware.HttpApiMiddleware.AnyId, S>(
89
94
  middleware: Context.Tag<I, S>
90
95
  ): HttpApi<
96
+ Id,
91
97
  Groups,
92
98
  E | HttpApiMiddleware.HttpApiMiddleware.Error<I>,
93
99
  R | I | HttpApiMiddleware.HttpApiMiddleware.ErrorContext<I>
@@ -95,11 +101,11 @@ export interface HttpApi<
95
101
  /**
96
102
  * Annotate the `HttpApi`.
97
103
  */
98
- annotate<I, S>(tag: Context.Tag<I, S>, value: S): HttpApi<Groups, E, R>
104
+ annotate<I, S>(tag: Context.Tag<I, S>, value: S): HttpApi<Id, Groups, E, R>
99
105
  /**
100
106
  * Annotate the `HttpApi` with a Context.
101
107
  */
102
- annotateContext<I>(context: Context.Context<I>): HttpApi<Groups, E, R>
108
+ annotateContext<I>(context: Context.Context<I>): HttpApi<Id, Groups, E, R>
103
109
  }
104
110
 
105
111
  /**
@@ -109,7 +115,7 @@ export interface HttpApi<
109
115
  export class Api extends Context.Tag("@effect/platform/HttpApi/Api")<
110
116
  Api,
111
117
  {
112
- readonly api: HttpApi<HttpApiGroup.HttpApiGroup.AnyWithProps>
118
+ readonly api: HttpApi<string, HttpApiGroup.HttpApiGroup.AnyWithProps>
113
119
  readonly context: Context.Context<never>
114
120
  }
115
121
  >() {}
@@ -131,7 +137,7 @@ export declare namespace HttpApi {
131
137
  * @since 1.0.0
132
138
  * @category models
133
139
  */
134
- export type AnyWithProps = HttpApi<HttpApiGroup.HttpApiGroup.AnyWithProps, any, any>
140
+ export type AnyWithProps = HttpApi<string, HttpApiGroup.HttpApiGroup.AnyWithProps, any, any>
135
141
  }
136
142
 
137
143
  const Proto = {
@@ -144,6 +150,7 @@ const Proto = {
144
150
  group: HttpApiGroup.HttpApiGroup.AnyWithProps
145
151
  ) {
146
152
  return makeProto({
153
+ identifier: this.identifier,
147
154
  groups: Record.set(this.groups, group.identifier, group),
148
155
  errorSchema: this.errorSchema,
149
156
  annotations: this.annotations,
@@ -158,10 +165,11 @@ const Proto = {
158
165
  for (const key in api.groups) {
159
166
  const newGroup: Mutable<HttpApiGroup.HttpApiGroup.AnyWithProps> = api.groups[key].annotateContext(Context.empty())
160
167
  newGroup.annotations = Context.merge(api.annotations, newGroup.annotations)
161
- newGroup.middlewares = new Set([...this.middlewares, ...newGroup.middlewares])
168
+ newGroup.middlewares = new Set([...api.middlewares, ...newGroup.middlewares])
162
169
  newGroups[key] = newGroup as any
163
170
  }
164
171
  return makeProto({
172
+ identifier: this.identifier,
165
173
  groups: newGroups,
166
174
  errorSchema: HttpApiSchema.UnionUnify(this.errorSchema, api.errorSchema),
167
175
  annotations: this.annotations,
@@ -174,6 +182,7 @@ const Proto = {
174
182
  annotations?: { readonly status?: number }
175
183
  ) {
176
184
  return makeProto({
185
+ identifier: this.identifier,
177
186
  groups: this.groups,
178
187
  errorSchema: HttpApiSchema.UnionUnify(
179
188
  this.errorSchema,
@@ -187,6 +196,7 @@ const Proto = {
187
196
  },
188
197
  prefix(this: HttpApi.AnyWithProps, prefix: PathInput) {
189
198
  return makeProto({
199
+ identifier: this.identifier,
190
200
  groups: Record.map(this.groups, (group) => group.prefix(prefix)),
191
201
  errorSchema: this.errorSchema,
192
202
  annotations: this.annotations,
@@ -195,6 +205,7 @@ const Proto = {
195
205
  },
196
206
  middleware(this: HttpApi.AnyWithProps, tag: HttpApiMiddleware.TagClassAny) {
197
207
  return makeProto({
208
+ identifier: this.identifier,
198
209
  groups: this.groups,
199
210
  errorSchema: HttpApiSchema.UnionUnify(
200
211
  this.errorSchema,
@@ -208,6 +219,7 @@ const Proto = {
208
219
  },
209
220
  annotate(this: HttpApi.AnyWithProps, tag: Context.Tag<any, any>, value: any) {
210
221
  return makeProto({
222
+ identifier: this.identifier,
211
223
  groups: this.groups,
212
224
  errorSchema: this.errorSchema,
213
225
  annotations: Context.add(this.annotations, tag, value),
@@ -216,6 +228,7 @@ const Proto = {
216
228
  },
217
229
  annotateContext(this: HttpApi.AnyWithProps, context: Context.Context<any>) {
218
230
  return makeProto({
231
+ identifier: this.identifier,
219
232
  groups: this.groups,
220
233
  errorSchema: this.errorSchema,
221
234
  annotations: Context.merge(this.annotations, context),
@@ -224,14 +237,15 @@ const Proto = {
224
237
  }
225
238
  }
226
239
 
227
- const makeProto = <Groups extends HttpApiGroup.HttpApiGroup.Any, E, I, R>(
240
+ const makeProto = <Id extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, E, I, R>(
228
241
  options: {
242
+ readonly identifier: Id
229
243
  readonly groups: Record.ReadonlyRecord<string, Groups>
230
244
  readonly errorSchema: Schema.Schema<E, I, R>
231
245
  readonly annotations: Context.Context<never>
232
246
  readonly middlewares: ReadonlySet<HttpApiMiddleware.TagClassAny>
233
247
  }
234
- ): HttpApi<Groups, E, R> => {
248
+ ): HttpApi<Id, Groups, E, R> => {
235
249
  function HttpApi() {}
236
250
  Object.setPrototypeOf(HttpApi, Proto)
237
251
  HttpApi.groups = options.groups
@@ -250,12 +264,14 @@ const makeProto = <Groups extends HttpApiGroup.HttpApiGroup.Any, E, I, R>(
250
264
  * @since 1.0.0
251
265
  * @category constructors
252
266
  */
253
- export const empty: HttpApi<never, HttpApiDecodeError> = makeProto({
254
- groups: new Map() as any,
255
- errorSchema: HttpApiDecodeError,
256
- annotations: Context.empty(),
257
- middlewares: new Set()
258
- })
267
+ export const make = <const Id extends string>(identifier: Id): HttpApi<Id, never, HttpApiDecodeError> =>
268
+ makeProto({
269
+ identifier,
270
+ groups: new Map() as any,
271
+ errorSchema: HttpApiDecodeError,
272
+ annotations: Context.empty(),
273
+ middlewares: new Set()
274
+ })
259
275
 
260
276
  /**
261
277
  * Extract metadata from an `HttpApi`, which can be used to generate documentation
@@ -266,8 +282,8 @@ export const empty: HttpApi<never, HttpApiDecodeError> = makeProto({
266
282
  * @since 1.0.0
267
283
  * @category reflection
268
284
  */
269
- export const reflect = <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, R>(
270
- self: HttpApi<Groups, Error, R>,
285
+ export const reflect = <Id extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, Error, R>(
286
+ self: HttpApi<Id, Groups, Error, R>,
271
287
  options: {
272
288
  readonly predicate?: Predicate.Predicate<{
273
289
  readonly endpoint: HttpApiEndpoint.HttpApiEndpoint.AnyWithProps
@@ -55,12 +55,12 @@ export class Router extends HttpRouter.Tag("@effect/platform/HttpApiBuilder/Rout
55
55
  * @since 1.0.0
56
56
  * @category constructors
57
57
  */
58
- export const api = <Groups extends HttpApiGroup.HttpApiGroup.Any, E, R>(
59
- api: HttpApi.HttpApi<Groups, E, R>
58
+ export const api = <Id extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, E, R>(
59
+ api: HttpApi.HttpApi<Id, Groups, E, R>
60
60
  ): Layer.Layer<
61
61
  HttpApi.Api,
62
62
  never,
63
- HttpApiGroup.HttpApiGroup.ToService<Groups> | R | HttpApiGroup.HttpApiGroup.ErrorContext<Groups>
63
+ HttpApiGroup.HttpApiGroup.ToService<Id, Groups> | R | HttpApiGroup.HttpApiGroup.ErrorContext<Groups>
64
64
  > =>
65
65
  Layer.effect(
66
66
  HttpApi.Api,
@@ -132,7 +132,7 @@ export const httpApp: Effect.Effect<
132
132
  * import { HttpApi, HttpApiBuilder, HttpServer } from "@effect/platform"
133
133
  * import { Layer } from "effect"
134
134
  *
135
- * class MyApi extends HttpApi.empty {}
135
+ * class MyApi extends HttpApi.make("api") {}
136
136
  *
137
137
  * const MyApiLive = HttpApiBuilder.api(MyApi)
138
138
  *
@@ -429,19 +429,20 @@ const makeHandlers = <E, Provides, R, Endpoints extends HttpApiEndpoint.HttpApiE
429
429
  * @category handlers
430
430
  */
431
431
  export const group = <
432
+ ApiId extends string,
432
433
  Groups extends HttpApiGroup.HttpApiGroup.Any,
433
434
  ApiError,
434
435
  ApiR,
435
436
  const Name extends HttpApiGroup.HttpApiGroup.Name<Groups>,
436
437
  Return
437
438
  >(
438
- api: HttpApi.HttpApi<Groups, ApiError, ApiR>,
439
+ api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
439
440
  groupName: Name,
440
441
  build: (
441
442
  handlers: Handlers.FromGroup<ApiError, ApiR, HttpApiGroup.HttpApiGroup.WithName<Groups, Name>>
442
443
  ) => Handlers.ValidateReturn<Return>
443
444
  ): Layer.Layer<
444
- HttpApiGroup.ApiGroup<Name>,
445
+ HttpApiGroup.ApiGroup<ApiId, Name>,
445
446
  Handlers.Error<Return>,
446
447
  | Handlers.Context<Return>
447
448
  | HttpApiGroup.HttpApiGroup.MiddlewareWithName<Groups, Name>
@@ -481,6 +482,7 @@ export const group = <
481
482
  * @category handlers
482
483
  */
483
484
  export const handler = <
485
+ ApiId extends string,
484
486
  Groups extends HttpApiGroup.HttpApiGroup.Any,
485
487
  ApiError,
486
488
  ApiR,
@@ -488,7 +490,7 @@ export const handler = <
488
490
  const Name extends HttpApiGroup.HttpApiGroup.EndpointsWithName<Groups, GroupName>["name"],
489
491
  R
490
492
  >(
491
- _api: HttpApi.HttpApi<Groups, ApiError, ApiR>,
493
+ _api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
492
494
  _groupName: GroupName,
493
495
  _name: Name,
494
496
  f: HttpApiEndpoint.HttpApiEndpoint.HandlerWithName<
@@ -842,8 +844,8 @@ export const middleware: {
842
844
  * @since 1.0.0
843
845
  * @category middleware
844
846
  */
845
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, EX = never, RX = never>(
846
- api: HttpApi.HttpApi<Groups, Error, ErrorR>,
847
+ <ApiId extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, EX = never, RX = never>(
848
+ api: HttpApi.HttpApi<ApiId, Groups, Error, ErrorR>,
847
849
  middleware: MiddlewareFn<NoInfer<Error>> | Effect.Effect<MiddlewareFn<NoInfer<Error>>, EX, RX>,
848
850
  options?: {
849
851
  readonly withContext?: false | undefined
@@ -855,8 +857,8 @@ export const middleware: {
855
857
  * @since 1.0.0
856
858
  * @category middleware
857
859
  */
858
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, R, EX = never, RX = never>(
859
- api: HttpApi.HttpApi<Groups, Error, ErrorR>,
860
+ <ApiId extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, R, EX = never, RX = never>(
861
+ api: HttpApi.HttpApi<ApiId, Groups, Error, ErrorR>,
860
862
  middleware: MiddlewareFn<NoInfer<Error>, R> | Effect.Effect<MiddlewareFn<NoInfer<Error>, R>, EX, RX>,
861
863
  options: {
862
864
  readonly withContext: true
@@ -926,8 +928,8 @@ export const middlewareScoped: {
926
928
  * @since 1.0.0
927
929
  * @category middleware
928
930
  */
929
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, EX, RX>(
930
- api: HttpApi.HttpApi<Groups, Error, ErrorR>,
931
+ <ApiId extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, EX, RX>(
932
+ api: HttpApi.HttpApi<ApiId, Groups, Error, ErrorR>,
931
933
  middleware: Effect.Effect<MiddlewareFn<NoInfer<Error>>, EX, RX>,
932
934
  options?: {
933
935
  readonly withContext?: false | undefined
@@ -940,8 +942,8 @@ export const middlewareScoped: {
940
942
  * @since 1.0.0
941
943
  * @category middleware
942
944
  */
943
- <Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, R, EX, RX>(
944
- api: HttpApi.HttpApi<Groups, Error, ErrorR>,
945
+ <ApiId extends string, Groups extends HttpApiGroup.HttpApiGroup.Any, Error, ErrorR, R, EX, RX>(
946
+ api: HttpApi.HttpApi<ApiId, Groups, Error, ErrorR>,
945
947
  middleware: Effect.Effect<MiddlewareFn<NoInfer<Error>, R>, EX, RX>,
946
948
  options: {
947
949
  readonly withContext: true
@@ -102,8 +102,8 @@ export declare namespace Client {
102
102
  /**
103
103
  * @internal
104
104
  */
105
- const makeClient = <Groups extends HttpApiGroup.Any, ApiError, ApiR>(
106
- api: HttpApi.HttpApi<Groups, ApiError, ApiR>,
105
+ const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, ApiError, ApiR>(
106
+ api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
107
107
  options: {
108
108
  readonly predicate?: Predicate.Predicate<{
109
109
  readonly endpoint: HttpApiEndpoint.AnyWithProps
@@ -240,8 +240,8 @@ const makeClient = <Groups extends HttpApiGroup.Any, ApiError, ApiR>(
240
240
  * @since 1.0.0
241
241
  * @category constructors
242
242
  */
243
- export const make = <Groups extends HttpApiGroup.Any, ApiError, ApiR>(
244
- api: HttpApi.HttpApi<Groups, ApiError, ApiR>,
243
+ export const make = <ApiId extends string, Groups extends HttpApiGroup.Any, ApiError, ApiR>(
244
+ api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
245
245
  options?: {
246
246
  readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
247
247
  readonly transformResponse?:
@@ -272,12 +272,13 @@ export const make = <Groups extends HttpApiGroup.Any, ApiError, ApiR>(
272
272
  * @category constructors
273
273
  */
274
274
  export const group = <
275
+ ApiId extends string,
275
276
  Groups extends HttpApiGroup.Any,
276
277
  ApiError,
277
278
  ApiR,
278
279
  const GroupName extends Groups["identifier"]
279
280
  >(
280
- api: HttpApi.HttpApi<Groups, ApiError, ApiR>,
281
+ api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
281
282
  groupId: GroupName,
282
283
  options?: {
283
284
  readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
@@ -311,13 +312,14 @@ export const group = <
311
312
  * @category constructors
312
313
  */
313
314
  export const endpoint = <
315
+ ApiId extends string,
314
316
  Groups extends HttpApiGroup.Any,
315
317
  ApiError,
316
318
  ApiR,
317
319
  const GroupName extends HttpApiGroup.Name<Groups>,
318
320
  const EndpointName extends HttpApiEndpoint.Name<HttpApiGroup.EndpointsWithName<Groups, GroupName>>
319
321
  >(
320
- api: HttpApi.HttpApi<Groups, ApiError, ApiR>,
322
+ api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
321
323
  groupName: GroupName,
322
324
  endpointName: EndpointName,
323
325
  options?: {
@@ -109,3 +109,111 @@ export class HttpApiDecodeError extends Schema.TaggedError<HttpApiDecodeError>()
109
109
  return Effect.flatMap(HttpApiDecodeError.fromParseError(error), Effect.fail)
110
110
  }
111
111
  }
112
+
113
+ /**
114
+ * @since 1.0.0
115
+ * @category empty errors
116
+ */
117
+ export class BadRequest extends HttpApiSchema.EmptyError<BadRequest>()({
118
+ tag: "BadRequest",
119
+ status: 400
120
+ }) {}
121
+
122
+ /**
123
+ * @since 1.0.0
124
+ * @category empty errors
125
+ */
126
+ export class Unauthorized extends HttpApiSchema.EmptyError<Unauthorized>()({
127
+ tag: "Unauthorized",
128
+ status: 401
129
+ }) {}
130
+
131
+ /**
132
+ * @since 1.0.0
133
+ * @category empty errors
134
+ */
135
+ export class Forbidden extends HttpApiSchema.EmptyError<Forbidden>()({
136
+ tag: "Forbidden",
137
+ status: 403
138
+ }) {}
139
+
140
+ /**
141
+ * @since 1.0.0
142
+ * @category empty errors
143
+ */
144
+ export class NotFound extends HttpApiSchema.EmptyError<NotFound>()({
145
+ tag: "NotFound",
146
+ status: 404
147
+ }) {}
148
+
149
+ /**
150
+ * @since 1.0.0
151
+ * @category empty errors
152
+ */
153
+ export class MethodNotAllowed extends HttpApiSchema.EmptyError<MethodNotAllowed>()({
154
+ tag: "MethodNotAllowed",
155
+ status: 405
156
+ }) {}
157
+
158
+ /**
159
+ * @since 1.0.0
160
+ * @category empty errors
161
+ */
162
+ export class NotAcceptable extends HttpApiSchema.EmptyError<NotAcceptable>()({
163
+ tag: "NotAcceptable",
164
+ status: 406
165
+ }) {}
166
+
167
+ /**
168
+ * @since 1.0.0
169
+ * @category empty errors
170
+ */
171
+ export class RequestTimeout extends HttpApiSchema.EmptyError<RequestTimeout>()({
172
+ tag: "RequestTimeout",
173
+ status: 408
174
+ }) {}
175
+
176
+ /**
177
+ * @since 1.0.0
178
+ * @category empty errors
179
+ */
180
+ export class Conflict extends HttpApiSchema.EmptyError<Conflict>()({
181
+ tag: "Conflict",
182
+ status: 409
183
+ }) {}
184
+
185
+ /**
186
+ * @since 1.0.0
187
+ * @category empty errors
188
+ */
189
+ export class Gone extends HttpApiSchema.EmptyError<Gone>()({
190
+ tag: "Gone",
191
+ status: 410
192
+ }) {}
193
+
194
+ /**
195
+ * @since 1.0.0
196
+ * @category empty errors
197
+ */
198
+ export class InternalServerError extends HttpApiSchema.EmptyError<InternalServerError>()({
199
+ tag: "InternalServerError",
200
+ status: 500
201
+ }) {}
202
+
203
+ /**
204
+ * @since 1.0.0
205
+ * @category empty errors
206
+ */
207
+ export class NotImplemented extends HttpApiSchema.EmptyError<NotImplemented>()({
208
+ tag: "NotImplemented",
209
+ status: 501
210
+ }) {}
211
+
212
+ /**
213
+ * @since 1.0.0
214
+ * @category empty errors
215
+ */
216
+ export class ServiceUnavailable extends HttpApiSchema.EmptyError<ServiceUnavailable>()({
217
+ tag: "ServiceUnavailable",
218
+ status: 503
219
+ }) {}
@@ -139,8 +139,9 @@ export interface HttpApiGroup<
139
139
  * @since 1.0.0
140
140
  * @category models
141
141
  */
142
- export interface ApiGroup<Name extends string> {
142
+ export interface ApiGroup<ApiId extends string, Name extends string> {
143
143
  readonly _: unique symbol
144
+ readonly apiId: ApiId
144
145
  readonly name: Name
145
146
  }
146
147
 
@@ -168,8 +169,8 @@ export declare namespace HttpApiGroup {
168
169
  * @since 1.0.0
169
170
  * @category models
170
171
  */
171
- export type ToService<A> = A extends
172
- HttpApiGroup<infer Name, infer _Endpoints, infer _Error, infer _R, infer _TopLevel> ? ApiGroup<Name>
172
+ export type ToService<ApiId extends string, A> = A extends
173
+ HttpApiGroup<infer Name, infer _Endpoints, infer _Error, infer _R, infer _TopLevel> ? ApiGroup<ApiId, Name>
173
174
  : never
174
175
 
175
176
  /**
@@ -2,9 +2,12 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import type { Brand } from "effect/Brand"
5
+ import * as Effect from "effect/Effect"
6
+ import * as Effectable from "effect/Effectable"
5
7
  import type { LazyArg } from "effect/Function"
6
- import { constVoid, dual } from "effect/Function"
8
+ import { constant, constVoid, dual } from "effect/Function"
7
9
  import { globalValue } from "effect/GlobalValue"
10
+ import { hasProperty } from "effect/Predicate"
8
11
  import * as Schema from "effect/Schema"
9
12
  import * as AST from "effect/SchemaAST"
10
13
  import * as Struct from "effect/Struct"
@@ -245,7 +248,7 @@ export const asEmpty: {
245
248
  self: S,
246
249
  options: {
247
250
  readonly status: number
248
- readonly decode?: LazyArg<Schema.Schema.Type<S>>
251
+ readonly decode: LazyArg<Schema.Schema.Type<S>>
249
252
  }
250
253
  ): asEmpty<S>
251
254
  } = dual(
@@ -254,14 +257,14 @@ export const asEmpty: {
254
257
  self: S,
255
258
  options: {
256
259
  readonly status: number
257
- readonly decode?: LazyArg<Schema.Schema.Type<S>>
260
+ readonly decode: LazyArg<Schema.Schema.Type<S>>
258
261
  }
259
262
  ): asEmpty<S> =>
260
263
  Schema.transform(
261
- Schema.Void,
264
+ Schema.Void.annotations(self.ast.annotations),
262
265
  Schema.typeSchema(self),
263
266
  {
264
- decode: options.decode as any,
267
+ decode: options.decode,
265
268
  encode: constVoid
266
269
  }
267
270
  ).annotations(annotations({
@@ -482,3 +485,58 @@ export const deunionize = (
482
485
  schemas.add(schema)
483
486
  }
484
487
  }
488
+
489
+ /**
490
+ * @since 1.0.0
491
+ * @category empty errors
492
+ */
493
+ export interface EmptyErrorClass<Self, Tag> extends Schema.Schema<Self, void> {
494
+ new(_: void): { readonly _tag: Tag } & Effect.Effect<never, Self>
495
+ }
496
+
497
+ /**
498
+ * @since 1.0.0
499
+ * @category empty errors
500
+ */
501
+ export const EmptyError = <Self>() =>
502
+ <const Tag extends string>(options: {
503
+ readonly tag: Tag
504
+ readonly status: number
505
+ }): EmptyErrorClass<Self, Tag> => {
506
+ const symbol = Symbol.for(`@effect/platform/HttpApiSchema/EmptyError/${options.tag}`)
507
+ class EmptyError extends Effectable.StructuralClass<never, Self> {
508
+ readonly _tag: Tag = options.tag
509
+ commit(): Effect.Effect<never, Self> {
510
+ return Effect.fail(this) as any
511
+ }
512
+ }
513
+ ;(EmptyError as any).prototype[symbol] = symbol
514
+ Object.assign(EmptyError, {
515
+ [Schema.TypeId]: Schema.Void[Schema.TypeId],
516
+ pipe: Schema.Void.pipe,
517
+ annotations(this: any, annotations: any) {
518
+ return Schema.make(this.ast).annotations(annotations)
519
+ }
520
+ })
521
+ let transform: Schema.Schema.Any | undefined
522
+ Object.defineProperty(EmptyError, "ast", {
523
+ get() {
524
+ if (transform) {
525
+ return transform.ast
526
+ }
527
+ const self = this as any
528
+ transform = asEmpty(
529
+ Schema.declare((u) => hasProperty(u, symbol), {
530
+ identifier: options.tag,
531
+ title: options.tag
532
+ }),
533
+ {
534
+ status: options.status,
535
+ decode: constant(new self())
536
+ }
537
+ )
538
+ return transform.ast
539
+ }
540
+ })
541
+ return EmptyError as any
542
+ }
package/src/OpenApi.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import * as Context from "effect/Context"
5
+ import { constFalse } from "effect/Function"
5
6
  import { globalValue } from "effect/GlobalValue"
6
7
  import * as Option from "effect/Option"
7
8
  import type { ReadonlyRecord } from "effect/Record"
@@ -84,6 +85,14 @@ export class Deprecated extends Context.Tag("@effect/platform/OpenApi/Deprecated
84
85
  */
85
86
  export class Override extends Context.Tag("@effect/platform/OpenApi/Override")<Override, Record<string, unknown>>() {}
86
87
 
88
+ /**
89
+ * @since 1.0.0
90
+ * @category annotations
91
+ */
92
+ export class Exclude extends Context.Reference<Exclude>()("@effect/platform/OpenApi/Exclude", {
93
+ defaultValue: constFalse
94
+ }) {}
95
+
87
96
  /**
88
97
  * Transforms the generated OpenAPI specification
89
98
  * @since 1.0.0
@@ -127,6 +136,7 @@ export const annotations: (
127
136
  readonly servers?: ReadonlyArray<OpenAPISpecServer> | undefined
128
137
  readonly format?: string | undefined
129
138
  readonly override?: Record<string, unknown> | undefined
139
+ readonly exclude?: boolean | undefined
130
140
  readonly transform?: ((openApiSpec: Record<string, any>) => Record<string, any>) | undefined
131
141
  }
132
142
  ) => Context.Context<never> = contextPartial({
@@ -140,6 +150,7 @@ export const annotations: (
140
150
  servers: Servers,
141
151
  format: Format,
142
152
  override: Override,
153
+ exclude: Exclude,
143
154
  transform: Transform
144
155
  })
145
156
 
@@ -213,6 +224,9 @@ export const fromApi = <A extends HttpApi.HttpApi.Any>(self: A): OpenAPISpec =>
213
224
  })
214
225
  HttpApi.reflect(api as any, {
215
226
  onGroup({ group }) {
227
+ if (Context.get(group.annotations, Exclude)) {
228
+ return
229
+ }
216
230
  let tag: Mutable<OpenAPISpecTag> = {
217
231
  name: Context.getOrElse(group.annotations, Title, () => group.identifier)
218
232
  }
@@ -230,7 +244,10 @@ export const fromApi = <A extends HttpApi.HttpApi.Any>(self: A): OpenAPISpec =>
230
244
  })
231
245
  spec.tags!.push(tag)
232
246
  },
233
- onEndpoint({ endpoint, errors, group, middleware, payloads, successes }) {
247
+ onEndpoint({ endpoint, errors, group, mergedAnnotations, middleware, payloads, successes }) {
248
+ if (Context.get(mergedAnnotations, Exclude)) {
249
+ return
250
+ }
234
251
  const path = endpoint.path.replace(/:(\w+)[^/]*/g, "{$1}")
235
252
  const method = endpoint.method.toLowerCase() as OpenAPISpecMethodName
236
253
  let op: DeepMutable<OpenAPISpecOperation> = {