effect 4.0.0-beta.80 → 4.0.0-beta.82
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/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +5 -2
- package/dist/Config.js.map +1 -1
- package/dist/Schema.d.ts +1 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/unstable/encoding/Sse.d.ts +18 -14
- package/dist/unstable/encoding/Sse.d.ts.map +1 -1
- package/dist/unstable/encoding/Sse.js +7 -4
- package/dist/unstable/encoding/Sse.js.map +1 -1
- package/dist/unstable/httpapi/HttpApi.d.ts +1 -1
- package/dist/unstable/httpapi/HttpApi.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApi.js +1 -0
- package/dist/unstable/httpapi/HttpApi.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.js +92 -11
- package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiClient.d.ts +6 -1
- package/dist/unstable/httpapi/HttpApiClient.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiClient.js +114 -3
- package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiEndpoint.d.ts +60 -50
- package/dist/unstable/httpapi/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiEndpoint.js +116 -5
- package/dist/unstable/httpapi/HttpApiEndpoint.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiGroup.d.ts +1 -1
- package/dist/unstable/httpapi/HttpApiGroup.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiSchema.d.ts +116 -2
- package/dist/unstable/httpapi/HttpApiSchema.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiSchema.js +75 -5
- package/dist/unstable/httpapi/HttpApiSchema.js.map +1 -1
- package/dist/unstable/httpapi/OpenApi.d.ts +15 -0
- package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
- package/dist/unstable/httpapi/OpenApi.js +82 -13
- package/dist/unstable/httpapi/OpenApi.js.map +1 -1
- package/dist/unstable/reactivity/AtomHttpApi.d.ts +2 -2
- package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Config.ts +5 -2
- package/src/Schema.ts +1 -1
- package/src/unstable/encoding/Sse.ts +34 -20
- package/src/unstable/httpapi/HttpApi.ts +2 -1
- package/src/unstable/httpapi/HttpApiBuilder.ts +148 -3
- package/src/unstable/httpapi/HttpApiClient.ts +196 -5
- package/src/unstable/httpapi/HttpApiEndpoint.ts +209 -18
- package/src/unstable/httpapi/HttpApiGroup.ts +1 -1
- package/src/unstable/httpapi/HttpApiSchema.ts +249 -5
- package/src/unstable/httpapi/OpenApi.ts +130 -17
- package/src/unstable/reactivity/AtomHttpApi.ts +2 -2
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
* @since 4.0.0
|
|
11
11
|
*/
|
|
12
12
|
import { constVoid, type LazyArg } from "../../Function.ts"
|
|
13
|
+
import * as Predicate from "../../Predicate.ts"
|
|
13
14
|
import * as Schema from "../../Schema.ts"
|
|
14
15
|
import * as SchemaAST from "../../SchemaAST.ts"
|
|
15
16
|
import * as SchemaTransformation from "../../SchemaTransformation.ts"
|
|
17
|
+
import * as Stream from "../../Stream.ts"
|
|
18
|
+
import type * as Sse from "../encoding/Sse.ts"
|
|
16
19
|
import { hasBody, type HttpMethod } from "../http/HttpMethod.ts"
|
|
17
20
|
import type * as Multipart_ from "../http/Multipart.ts"
|
|
18
21
|
|
|
@@ -125,6 +128,8 @@ const statusCodeByLiteral = {
|
|
|
125
128
|
NetworkAuthenticationRequired: 511
|
|
126
129
|
} as const
|
|
127
130
|
|
|
131
|
+
const StreamSchemaTypeId = "~effect/httpapi/HttpApiSchema/Stream"
|
|
132
|
+
|
|
128
133
|
/**
|
|
129
134
|
* Common HTTP status code literals accepted by {@link status}.
|
|
130
135
|
*
|
|
@@ -145,13 +150,15 @@ export type StatusLiteral = keyof typeof statusCodeByLiteral
|
|
|
145
150
|
* @category status
|
|
146
151
|
* @since 4.0.0
|
|
147
152
|
*/
|
|
148
|
-
export function status(code: number):
|
|
149
|
-
|
|
153
|
+
export function status(code: number): {
|
|
154
|
+
<S extends Schema.Top>(self: S): S["Rebuild"]
|
|
155
|
+
}
|
|
156
|
+
export function status(code: StatusLiteral): {
|
|
157
|
+
<S extends Schema.Top>(self: S): S["Rebuild"]
|
|
158
|
+
}
|
|
150
159
|
export function status(code: number | StatusLiteral) {
|
|
151
160
|
const statusCode = typeof code === "string" ? statusCodeByLiteral[code] : code
|
|
152
|
-
return <S extends Schema.Top>(self: S): S["Rebuild"] => {
|
|
153
|
-
return self.annotate({ httpApiStatus: statusCode })
|
|
154
|
-
}
|
|
161
|
+
return <S extends Schema.Top>(self: S): S["Rebuild"] => self.annotate({ httpApiStatus: statusCode })
|
|
155
162
|
}
|
|
156
163
|
|
|
157
164
|
/**
|
|
@@ -251,6 +258,238 @@ export function asNoContent<S extends Schema.Top>(options: {
|
|
|
251
258
|
}
|
|
252
259
|
}
|
|
253
260
|
|
|
261
|
+
type StreamMode = "sse" | "uint8array"
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Mode describing whether an SSE stream emits full events or raw data values.
|
|
265
|
+
*
|
|
266
|
+
* @category models
|
|
267
|
+
* @since 4.0.0
|
|
268
|
+
*/
|
|
269
|
+
export type StreamSseMode = "events" | "data"
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Schema for a Server-Sent Events success response.
|
|
273
|
+
*
|
|
274
|
+
* **Details**
|
|
275
|
+
*
|
|
276
|
+
* `events` describes successful application events emitted by the stream, and
|
|
277
|
+
* `error` describes typed stream failures that will be encoded by later
|
|
278
|
+
* endpoint/server/client integrations using the reserved failure event. If
|
|
279
|
+
* `error` is omitted, it defaults to `Schema.Never`. When `StreamSse` is
|
|
280
|
+
* constructed from `data`, handlers and clients expose raw data values while
|
|
281
|
+
* the server and client still use an SSE event schema internally.
|
|
282
|
+
*
|
|
283
|
+
* @category models
|
|
284
|
+
* @since 4.0.0
|
|
285
|
+
*/
|
|
286
|
+
export interface StreamSse<
|
|
287
|
+
Events extends Sse.EventCodec,
|
|
288
|
+
Error extends Schema.Top,
|
|
289
|
+
Value = Events["Type"]
|
|
290
|
+
> extends
|
|
291
|
+
Schema.Bottom<
|
|
292
|
+
Stream.Stream<Value, Error["Type"], never>,
|
|
293
|
+
Stream.Stream<Value, Error["Type"], never>,
|
|
294
|
+
Events["DecodingServices"] | Error["DecodingServices"],
|
|
295
|
+
Events["EncodingServices"] | Error["EncodingServices"],
|
|
296
|
+
SchemaAST.Declaration,
|
|
297
|
+
StreamSse<Events, Error, Value>
|
|
298
|
+
>
|
|
299
|
+
{
|
|
300
|
+
readonly "Rebuild": StreamSse<Events, Error, Value>
|
|
301
|
+
readonly [StreamSchemaTypeId]: typeof StreamSchemaTypeId
|
|
302
|
+
readonly _tag: "StreamSse"
|
|
303
|
+
readonly mode: "sse"
|
|
304
|
+
readonly sseMode: StreamSseMode
|
|
305
|
+
readonly contentType: string
|
|
306
|
+
readonly events: Events
|
|
307
|
+
readonly error: Error
|
|
308
|
+
readonly "~Value"?: Value | undefined
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Event schema produced when {@link StreamSse} is constructed from a JSON data schema.
|
|
313
|
+
*
|
|
314
|
+
* @category models
|
|
315
|
+
* @since 4.0.0
|
|
316
|
+
*/
|
|
317
|
+
export interface SseEventFromData<Data extends Schema.Top> extends
|
|
318
|
+
Schema.Codec<
|
|
319
|
+
{
|
|
320
|
+
readonly id: string | undefined
|
|
321
|
+
readonly event: string
|
|
322
|
+
readonly data: Data["Type"]
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
readonly id?: string | undefined
|
|
326
|
+
readonly event?: string | undefined
|
|
327
|
+
readonly data: string
|
|
328
|
+
},
|
|
329
|
+
Data["DecodingServices"],
|
|
330
|
+
Data["EncodingServices"]
|
|
331
|
+
>
|
|
332
|
+
{}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Schema for a streaming `Uint8Array` success response.
|
|
336
|
+
*
|
|
337
|
+
* **Details**
|
|
338
|
+
*
|
|
339
|
+
* This declaration stores the response content type for later endpoint,
|
|
340
|
+
* server, client, and OpenAPI integrations. It is intentionally separate from
|
|
341
|
+
* the buffered `asUint8Array` response encoding.
|
|
342
|
+
*
|
|
343
|
+
* @category models
|
|
344
|
+
* @since 4.0.0
|
|
345
|
+
*/
|
|
346
|
+
export interface StreamUint8Array extends
|
|
347
|
+
Schema.Bottom<
|
|
348
|
+
Stream.Stream<Uint8Array, unknown, never>,
|
|
349
|
+
Stream.Stream<Uint8Array, unknown, never>,
|
|
350
|
+
never,
|
|
351
|
+
never,
|
|
352
|
+
SchemaAST.Declaration,
|
|
353
|
+
StreamUint8Array
|
|
354
|
+
>
|
|
355
|
+
{
|
|
356
|
+
readonly "Rebuild": StreamUint8Array
|
|
357
|
+
readonly [StreamSchemaTypeId]: typeof StreamSchemaTypeId
|
|
358
|
+
readonly _tag: "StreamUint8Array"
|
|
359
|
+
readonly mode: "uint8array"
|
|
360
|
+
readonly contentType: string
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** @internal */
|
|
364
|
+
export type StreamSchema = StreamSse<Sse.EventCodec, Schema.Top, unknown> | StreamUint8Array
|
|
365
|
+
|
|
366
|
+
/** @internal */
|
|
367
|
+
export type StreamMetadata =
|
|
368
|
+
| {
|
|
369
|
+
readonly mode: "sse"
|
|
370
|
+
readonly sseMode: StreamSseMode
|
|
371
|
+
readonly contentType: string
|
|
372
|
+
readonly events: Sse.EventCodec
|
|
373
|
+
readonly error: Schema.Top
|
|
374
|
+
}
|
|
375
|
+
| {
|
|
376
|
+
readonly mode: "uint8array"
|
|
377
|
+
readonly contentType: string
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const streamSchema = Schema.declare(Stream.isStream)
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Creates a Server-Sent Events streaming success response schema.
|
|
384
|
+
*
|
|
385
|
+
* @category constructors
|
|
386
|
+
* @since 4.0.0
|
|
387
|
+
*/
|
|
388
|
+
export const StreamSse: {
|
|
389
|
+
/**
|
|
390
|
+
* Creates a Server-Sent Events streaming success response schema.
|
|
391
|
+
*
|
|
392
|
+
* @category constructors
|
|
393
|
+
* @since 4.0.0
|
|
394
|
+
*/
|
|
395
|
+
<Events extends Sse.EventCodec, Error extends Schema.Top = Schema.Never>(
|
|
396
|
+
options: {
|
|
397
|
+
readonly contentType?: string | undefined
|
|
398
|
+
readonly events: Events
|
|
399
|
+
readonly error?: Error | undefined
|
|
400
|
+
}
|
|
401
|
+
): StreamSse<Events, Error, Events["Type"]>
|
|
402
|
+
/**
|
|
403
|
+
* Creates a Server-Sent Events streaming success response schema.
|
|
404
|
+
*
|
|
405
|
+
* @category constructors
|
|
406
|
+
* @since 4.0.0
|
|
407
|
+
*/
|
|
408
|
+
<Data extends Schema.Top, Error extends Schema.Top = Schema.Never>(
|
|
409
|
+
options: {
|
|
410
|
+
readonly contentType?: string | undefined
|
|
411
|
+
readonly data: Data
|
|
412
|
+
readonly error?: Error | undefined
|
|
413
|
+
}
|
|
414
|
+
): StreamSse<SseEventFromData<Data>, Error, Data["Type"]>
|
|
415
|
+
} = (options: {
|
|
416
|
+
readonly contentType?: string | undefined
|
|
417
|
+
readonly events?: Sse.EventCodec | undefined
|
|
418
|
+
readonly data?: Schema.Top | undefined
|
|
419
|
+
readonly error?: Schema.Top | undefined
|
|
420
|
+
}): StreamSse<Sse.EventCodec, Schema.Top, unknown> => {
|
|
421
|
+
const events = options.events ?? (options.data === undefined ? undefined : Schema.Struct({
|
|
422
|
+
id: Schema.UndefinedOr(Schema.String),
|
|
423
|
+
event: Schema.String,
|
|
424
|
+
data: Schema.fromJsonString(options.data)
|
|
425
|
+
}))
|
|
426
|
+
if (events === undefined) {
|
|
427
|
+
throw new Error("StreamSse requires either an events schema or a data schema")
|
|
428
|
+
}
|
|
429
|
+
return Schema.make<StreamSse<Sse.EventCodec, Schema.Top, unknown>>(streamSchema.ast, {
|
|
430
|
+
[StreamSchemaTypeId]: StreamSchemaTypeId,
|
|
431
|
+
_tag: "StreamSse",
|
|
432
|
+
mode: "sse",
|
|
433
|
+
sseMode: options.events === undefined ? "data" : "events",
|
|
434
|
+
contentType: options.contentType ?? defaultStreamContentType("sse"),
|
|
435
|
+
events,
|
|
436
|
+
error: options.error ?? Schema.Never
|
|
437
|
+
})
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Creates a streaming `Uint8Array` success response schema.
|
|
442
|
+
*
|
|
443
|
+
* @category constructors
|
|
444
|
+
* @since 4.0.0
|
|
445
|
+
*/
|
|
446
|
+
export const StreamUint8Array = (options?: {
|
|
447
|
+
readonly contentType?: string | undefined
|
|
448
|
+
}): StreamUint8Array =>
|
|
449
|
+
Schema.make<StreamUint8Array>(streamSchema.ast, {
|
|
450
|
+
[StreamSchemaTypeId]: StreamSchemaTypeId,
|
|
451
|
+
_tag: "StreamUint8Array",
|
|
452
|
+
mode: "uint8array",
|
|
453
|
+
contentType: options?.contentType ?? defaultStreamContentType("uint8array")
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
/** @internal */
|
|
457
|
+
export const isStreamSchema = (u: unknown): u is StreamSchema =>
|
|
458
|
+
Schema.isSchema(u) && Predicate.hasProperty(u, StreamSchemaTypeId)
|
|
459
|
+
|
|
460
|
+
/** @internal */
|
|
461
|
+
export const isStreamSse = (u: unknown): u is StreamSse<Sse.EventCodec, Schema.Top, unknown> =>
|
|
462
|
+
isStreamSchema(u) && u._tag === "StreamSse"
|
|
463
|
+
|
|
464
|
+
/** @internal */
|
|
465
|
+
export const isStreamUint8Array = (u: unknown): u is StreamUint8Array =>
|
|
466
|
+
isStreamSchema(u) && u._tag === "StreamUint8Array"
|
|
467
|
+
|
|
468
|
+
/** @internal */
|
|
469
|
+
export function getStreamMetadata(self: StreamSchema): StreamMetadata {
|
|
470
|
+
return self._tag === "StreamSse" ?
|
|
471
|
+
{
|
|
472
|
+
mode: self.mode,
|
|
473
|
+
sseMode: self.sseMode,
|
|
474
|
+
contentType: self.contentType,
|
|
475
|
+
events: self.events,
|
|
476
|
+
error: self.error
|
|
477
|
+
} :
|
|
478
|
+
{
|
|
479
|
+
mode: self.mode,
|
|
480
|
+
contentType: self.contentType
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function defaultStreamContentType(mode: StreamMode): string {
|
|
485
|
+
switch (mode) {
|
|
486
|
+
case "sse":
|
|
487
|
+
return "text/event-stream"
|
|
488
|
+
case "uint8array":
|
|
489
|
+
return "application/octet-stream"
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
254
493
|
/**
|
|
255
494
|
* Runtime brand key used to mark schemas as buffered multipart payloads.
|
|
256
495
|
*
|
|
@@ -487,6 +726,11 @@ export function getStatusSuccess(self: SchemaAST.AST): number {
|
|
|
487
726
|
return resolveHttpApiStatus(self) ?? 200
|
|
488
727
|
}
|
|
489
728
|
|
|
729
|
+
/** @internal */
|
|
730
|
+
export function getStatusStream(self: StreamSchema): number {
|
|
731
|
+
return getStatusSuccess(self.ast)
|
|
732
|
+
}
|
|
733
|
+
|
|
490
734
|
/** @internal */
|
|
491
735
|
export function getStatusError(self: SchemaAST.AST): number {
|
|
492
736
|
return resolveHttpApiStatus(self) ?? 500
|
|
@@ -367,7 +367,7 @@ export function fromApi<Id extends string, Groups extends HttpApiGroup.Any>(
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
function processResponseBodies(bodies: ResponseBodies, defaultDescription: () => string) {
|
|
370
|
-
for (const [status, { content, descriptions }] of bodies) {
|
|
370
|
+
for (const [status, { content, descriptions, streamContent }] of bodies) {
|
|
371
371
|
const description = descriptions.size > 0 ? Array.from(descriptions).join(" | ") : defaultDescription()
|
|
372
372
|
op.responses[status] = {
|
|
373
373
|
description
|
|
@@ -390,6 +390,67 @@ export function fromApi<Id extends string, Groups extends HttpApiGroup.Any>(
|
|
|
390
390
|
})
|
|
391
391
|
})
|
|
392
392
|
}
|
|
393
|
+
if (streamContent !== undefined) {
|
|
394
|
+
streamContent.forEach((stream, contentType) => {
|
|
395
|
+
op.responses[status].content ??= {}
|
|
396
|
+
if (HttpApiSchema.isStreamSse(stream)) {
|
|
397
|
+
pathOps.push({
|
|
398
|
+
_tag: "schema",
|
|
399
|
+
ast: SchemaAST.getAST(stream.events),
|
|
400
|
+
path: ["paths", path, method, "responses", String(status), "content", contentType, "schema"]
|
|
401
|
+
})
|
|
402
|
+
pathOps.push({
|
|
403
|
+
_tag: "schema",
|
|
404
|
+
ast: SchemaAST.getAST(Schema.toCodecJson(Schema.Cause(stream.error, Schema.Defect()))),
|
|
405
|
+
path: [
|
|
406
|
+
"paths",
|
|
407
|
+
path,
|
|
408
|
+
method,
|
|
409
|
+
"responses",
|
|
410
|
+
String(status),
|
|
411
|
+
"content",
|
|
412
|
+
contentType,
|
|
413
|
+
"x-effect-stream",
|
|
414
|
+
"causeSchema"
|
|
415
|
+
]
|
|
416
|
+
})
|
|
417
|
+
pathOps.push({
|
|
418
|
+
_tag: "schema",
|
|
419
|
+
ast: SchemaAST.getAST(stream.error),
|
|
420
|
+
path: [
|
|
421
|
+
"paths",
|
|
422
|
+
path,
|
|
423
|
+
method,
|
|
424
|
+
"responses",
|
|
425
|
+
String(status),
|
|
426
|
+
"content",
|
|
427
|
+
contentType,
|
|
428
|
+
"x-effect-stream",
|
|
429
|
+
"errorSchema"
|
|
430
|
+
]
|
|
431
|
+
})
|
|
432
|
+
op.responses[status].content[contentType] = {
|
|
433
|
+
schema: {},
|
|
434
|
+
"x-effect-stream": {
|
|
435
|
+
encoding: "sse",
|
|
436
|
+
causeSchema: {},
|
|
437
|
+
errorSchema: {},
|
|
438
|
+
failureEvent: reservedStreamFailureEvent
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
op.responses[status].content[contentType] = {
|
|
443
|
+
schema: {
|
|
444
|
+
type: "string",
|
|
445
|
+
format: "binary"
|
|
446
|
+
},
|
|
447
|
+
"x-effect-stream": {
|
|
448
|
+
encoding: "uint8array"
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
})
|
|
453
|
+
}
|
|
393
454
|
}
|
|
394
455
|
}
|
|
395
456
|
|
|
@@ -461,11 +522,7 @@ export function fromApi<Id extends string, Groups extends HttpApiGroup.Any>(
|
|
|
461
522
|
processParameters(endpoint.query, "query")
|
|
462
523
|
|
|
463
524
|
processResponseBodies(
|
|
464
|
-
|
|
465
|
-
HttpApiEndpoint.getSuccessSchemas(endpoint),
|
|
466
|
-
HttpApiSchema.getStatusSuccess,
|
|
467
|
-
resolveDescriptionOrIdentifier
|
|
468
|
-
),
|
|
525
|
+
extractSuccessResponseBodies(endpoint),
|
|
469
526
|
() => "Success"
|
|
470
527
|
)
|
|
471
528
|
processResponseBodies(
|
|
@@ -564,9 +621,20 @@ type ResponseBodies = Map<
|
|
|
564
621
|
{
|
|
565
622
|
descriptions: Set<string>
|
|
566
623
|
content: Content | undefined // undefined means no content
|
|
624
|
+
streamContent: StreamContent | undefined
|
|
567
625
|
}
|
|
568
626
|
>
|
|
569
627
|
|
|
628
|
+
const reservedStreamFailureEvent = "effect/httpapi/stream/failure"
|
|
629
|
+
|
|
630
|
+
function extractSuccessResponseBodies(endpoint: HttpApiEndpoint.AnyWithProps): ResponseBodies {
|
|
631
|
+
return extractResponseBodies(
|
|
632
|
+
HttpApiEndpoint.getSuccessSchemas(endpoint),
|
|
633
|
+
HttpApiSchema.getStatusSuccess,
|
|
634
|
+
resolveDescriptionOrIdentifier
|
|
635
|
+
)
|
|
636
|
+
}
|
|
637
|
+
|
|
570
638
|
function extractResponseBodies(
|
|
571
639
|
schemas: Array<Schema.Top>,
|
|
572
640
|
getStatus: (ast: SchemaAST.AST) => number,
|
|
@@ -575,6 +643,7 @@ function extractResponseBodies(
|
|
|
575
643
|
const map = new Map<number, {
|
|
576
644
|
descriptions: Set<string>
|
|
577
645
|
content: Content | undefined
|
|
646
|
+
streamContent: StreamContent | undefined
|
|
578
647
|
}>()
|
|
579
648
|
|
|
580
649
|
schemas.forEach(process)
|
|
@@ -582,6 +651,10 @@ function extractResponseBodies(
|
|
|
582
651
|
return map
|
|
583
652
|
|
|
584
653
|
function process(schema: Schema.Top) {
|
|
654
|
+
if (HttpApiSchema.isStreamSchema(schema)) {
|
|
655
|
+
addStreamContent(schema)
|
|
656
|
+
return
|
|
657
|
+
}
|
|
585
658
|
const ast = schema.ast
|
|
586
659
|
const status = getStatus(ast)
|
|
587
660
|
if (HttpApiSchema.isNoContent(ast)) {
|
|
@@ -596,7 +669,8 @@ function extractResponseBodies(
|
|
|
596
669
|
if (statusMap === undefined) {
|
|
597
670
|
map.set(status, {
|
|
598
671
|
descriptions: new Set([description]),
|
|
599
|
-
content: undefined
|
|
672
|
+
content: undefined,
|
|
673
|
+
streamContent: undefined
|
|
600
674
|
})
|
|
601
675
|
} else {
|
|
602
676
|
if (description !== undefined) {
|
|
@@ -612,22 +686,25 @@ function extractResponseBodies(
|
|
|
612
686
|
if (statusMap === undefined) {
|
|
613
687
|
map.set(status, {
|
|
614
688
|
descriptions: new Set(description !== undefined ? [description] : []),
|
|
615
|
-
content: new Map([[_tag, new Map([[contentType, new Set([schema])]])]])
|
|
689
|
+
content: new Map([[_tag, new Map([[contentType, new Set([schema])]])]]),
|
|
690
|
+
streamContent: undefined
|
|
616
691
|
})
|
|
617
692
|
} else {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
}
|
|
693
|
+
// concat descriptions
|
|
694
|
+
if (description !== undefined) {
|
|
695
|
+
statusMap.descriptions.add(description)
|
|
696
|
+
}
|
|
623
697
|
|
|
624
|
-
|
|
625
|
-
|
|
698
|
+
if (statusMap.content === undefined) {
|
|
699
|
+
statusMap.content = new Map([[_tag, new Map([[contentType, new Set([schema])]])]])
|
|
700
|
+
} else {
|
|
701
|
+
const schemasByContentType = statusMap.content.get(_tag)
|
|
702
|
+
if (schemasByContentType === undefined) {
|
|
626
703
|
statusMap.content.set(_tag, new Map([[contentType, new Set([schema])]]))
|
|
627
704
|
} else {
|
|
628
|
-
const set =
|
|
705
|
+
const set = schemasByContentType.get(contentType)
|
|
629
706
|
if (set === undefined) {
|
|
630
|
-
|
|
707
|
+
schemasByContentType.set(contentType, new Set([schema]))
|
|
631
708
|
} else {
|
|
632
709
|
set.add(schema)
|
|
633
710
|
}
|
|
@@ -635,6 +712,22 @@ function extractResponseBodies(
|
|
|
635
712
|
}
|
|
636
713
|
}
|
|
637
714
|
}
|
|
715
|
+
|
|
716
|
+
function addStreamContent(stream: HttpApiSchema.StreamSchema) {
|
|
717
|
+
const status = HttpApiSchema.getStatusStream(stream)
|
|
718
|
+
const statusMap = map.get(status)
|
|
719
|
+
if (statusMap === undefined) {
|
|
720
|
+
map.set(status, {
|
|
721
|
+
descriptions: new Set(),
|
|
722
|
+
content: undefined,
|
|
723
|
+
streamContent: new Map([[stream.contentType, stream]])
|
|
724
|
+
})
|
|
725
|
+
} else if (statusMap.streamContent === undefined) {
|
|
726
|
+
statusMap.streamContent = new Map([[stream.contentType, stream]])
|
|
727
|
+
} else {
|
|
728
|
+
statusMap.streamContent.set(stream.contentType, stream)
|
|
729
|
+
}
|
|
730
|
+
}
|
|
638
731
|
}
|
|
639
732
|
|
|
640
733
|
function resolveDescriptionOrIdentifier(ast: SchemaAST.AST): string | undefined {
|
|
@@ -649,6 +742,8 @@ type Content = Map<
|
|
|
649
742
|
>
|
|
650
743
|
>
|
|
651
744
|
|
|
745
|
+
type StreamContent = Map<string, HttpApiSchema.StreamSchema>
|
|
746
|
+
|
|
652
747
|
const Uint8ArrayEncoding = Schema.String.annotate({
|
|
653
748
|
format: "binary"
|
|
654
749
|
})
|
|
@@ -895,8 +990,26 @@ export interface OpenApiSpecResponse {
|
|
|
895
990
|
*/
|
|
896
991
|
export interface OpenApiSpecMediaType {
|
|
897
992
|
schema: JsonSchema.JsonSchema
|
|
993
|
+
"x-effect-stream"?: OpenApiSpecEffectStream
|
|
898
994
|
}
|
|
899
995
|
|
|
996
|
+
/**
|
|
997
|
+
* Effect-specific metadata for generated streaming response media types.
|
|
998
|
+
*
|
|
999
|
+
* @category models
|
|
1000
|
+
* @since 4.0.0
|
|
1001
|
+
*/
|
|
1002
|
+
export type OpenApiSpecEffectStream =
|
|
1003
|
+
| {
|
|
1004
|
+
encoding: "sse"
|
|
1005
|
+
causeSchema: JsonSchema.JsonSchema
|
|
1006
|
+
errorSchema: JsonSchema.JsonSchema
|
|
1007
|
+
failureEvent: "effect/httpapi/stream/failure"
|
|
1008
|
+
}
|
|
1009
|
+
| {
|
|
1010
|
+
encoding: "uint8array"
|
|
1011
|
+
}
|
|
1012
|
+
|
|
900
1013
|
/**
|
|
901
1014
|
* Generated OpenAPI request body object for endpoint payloads.
|
|
902
1015
|
*
|
|
@@ -82,7 +82,7 @@ export interface AtomHttpApiClient<Self, Id extends string, Groups extends HttpA
|
|
|
82
82
|
readonly reactivityKeys?: ReadonlyArray<unknown> | ReadonlyRecord<string, ReadonlyArray<unknown>> | undefined
|
|
83
83
|
}
|
|
84
84
|
>,
|
|
85
|
-
ResponseByMode<_Success["Type"], ResponseMode>,
|
|
85
|
+
ResponseByMode<Extract<_Success, Schema.Top>["Type"], ResponseMode>,
|
|
86
86
|
ErrorByMode<_Error, _Middleware, ResponseMode>
|
|
87
87
|
>
|
|
88
88
|
: never
|
|
@@ -140,7 +140,7 @@ export interface AtomHttpApiClient<Self, Id extends string, Groups extends HttpA
|
|
|
140
140
|
>
|
|
141
141
|
] ? Atom.Atom<
|
|
142
142
|
AsyncResult.AsyncResult<
|
|
143
|
-
ResponseByMode<_Success["Type"], ResponseMode>,
|
|
143
|
+
ResponseByMode<Extract<_Success, Schema.Top>["Type"], ResponseMode>,
|
|
144
144
|
ErrorByMode<_Error, _Middleware, ResponseMode>
|
|
145
145
|
>
|
|
146
146
|
>
|