effect 4.0.0-beta.37 → 4.0.0-beta.39
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/ErrorReporter.d.ts.map +1 -1
- package/dist/ErrorReporter.js +3 -2
- package/dist/ErrorReporter.js.map +1 -1
- package/dist/Queue.d.ts +5 -2
- package/dist/Queue.d.ts.map +1 -1
- package/dist/Queue.js +5 -2
- package/dist/Queue.js.map +1 -1
- package/dist/References.d.ts +235 -224
- package/dist/References.d.ts.map +1 -1
- package/dist/References.js +234 -246
- package/dist/References.js.map +1 -1
- package/dist/Schedule.d.ts +6 -202
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js +6 -71
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +6 -6
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +9 -13
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts +5 -0
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaParser.d.ts.map +1 -1
- package/dist/SchemaParser.js +7 -2
- package/dist/SchemaParser.js.map +1 -1
- package/dist/Stream.d.ts +1 -1
- package/dist/Stream.js +1 -1
- package/dist/Struct.d.ts +7 -7
- package/dist/Struct.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/effect.js +1 -5
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/references.d.ts +2 -0
- package/dist/internal/references.d.ts.map +1 -0
- package/dist/internal/references.js +51 -0
- package/dist/internal/references.js.map +1 -0
- package/dist/unstable/cluster/EntityAddress.d.ts.map +1 -1
- package/dist/unstable/cluster/EntityAddress.js +1 -1
- package/dist/unstable/cluster/EntityAddress.js.map +1 -1
- package/dist/unstable/cluster/Runner.d.ts.map +1 -1
- package/dist/unstable/cluster/Runner.js +1 -1
- package/dist/unstable/cluster/Runner.js.map +1 -1
- package/dist/unstable/cluster/RunnerAddress.d.ts.map +1 -1
- package/dist/unstable/cluster/RunnerAddress.js +1 -1
- package/dist/unstable/cluster/RunnerAddress.js.map +1 -1
- package/dist/unstable/cluster/ShardId.js +3 -3
- package/dist/unstable/cluster/ShardId.js.map +1 -1
- package/dist/unstable/eventlog/EventJournal.js +2 -2
- package/dist/unstable/eventlog/EventJournal.js.map +1 -1
- package/dist/unstable/eventlog/EventLog.js +1 -1
- package/dist/unstable/eventlog/EventLog.js.map +1 -1
- package/dist/unstable/eventlog/SqlEventLogJournal.js +2 -2
- package/dist/unstable/eventlog/SqlEventLogJournal.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.js +9 -8
- package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiClient.d.ts +36 -20
- package/dist/unstable/httpapi/HttpApiClient.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiClient.js +49 -18
- package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiEndpoint.d.ts +186 -67
- package/dist/unstable/httpapi/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiEndpoint.js +44 -29
- package/dist/unstable/httpapi/HttpApiEndpoint.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiSchema.d.ts +5 -0
- package/dist/unstable/httpapi/HttpApiSchema.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiSchema.js +20 -2
- package/dist/unstable/httpapi/HttpApiSchema.js.map +1 -1
- package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
- package/dist/unstable/httpapi/OpenApi.js +2 -5
- package/dist/unstable/httpapi/OpenApi.js.map +1 -1
- package/dist/unstable/reactivity/AtomHttpApi.d.ts +11 -7
- package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomHttpApi.js +6 -6
- package/dist/unstable/reactivity/AtomHttpApi.js.map +1 -1
- package/dist/unstable/schema/VariantSchema.d.ts +1 -1
- package/dist/unstable/schema/VariantSchema.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ErrorReporter.ts +3 -2
- package/src/Queue.ts +5 -2
- package/src/References.ts +276 -285
- package/src/Schedule.ts +7 -212
- package/src/Schema.ts +8 -12
- package/src/SchemaAST.ts +6 -0
- package/src/SchemaParser.ts +7 -2
- package/src/Stream.ts +1 -1
- package/src/Struct.ts +7 -7
- package/src/index.ts +1 -1
- package/src/internal/effect.ts +14 -21
- package/src/internal/references.ts +72 -0
- package/src/unstable/cluster/EntityAddress.ts +1 -1
- package/src/unstable/cluster/Runner.ts +1 -1
- package/src/unstable/cluster/RunnerAddress.ts +1 -1
- package/src/unstable/cluster/ShardId.ts +2 -2
- package/src/unstable/eventlog/EventJournal.ts +2 -2
- package/src/unstable/eventlog/EventLog.ts +1 -1
- package/src/unstable/eventlog/SqlEventLogJournal.ts +2 -2
- package/src/unstable/httpapi/HttpApiBuilder.ts +15 -9
- package/src/unstable/httpapi/HttpApiClient.ts +118 -55
- package/src/unstable/httpapi/HttpApiEndpoint.ts +164 -36
- package/src/unstable/httpapi/HttpApiSchema.ts +20 -2
- package/src/unstable/httpapi/OpenApi.ts +2 -6
- package/src/unstable/reactivity/AtomHttpApi.ts +22 -17
- package/src/unstable/schema/VariantSchema.ts +1 -1
|
@@ -199,7 +199,7 @@ export const make = (options?: {
|
|
|
199
199
|
event,
|
|
200
200
|
primaryKey,
|
|
201
201
|
payload
|
|
202
|
-
}, {
|
|
202
|
+
}, { disableChecks: true })
|
|
203
203
|
yield* insertEntry(toEntryRow(entry))
|
|
204
204
|
const value = yield* effect(entry)
|
|
205
205
|
yield* PubSub.publish(pubsub, entry)
|
|
@@ -280,7 +280,7 @@ const toEntry = (row: EntryRow): EventJournal.Entry =>
|
|
|
280
280
|
event: row.event,
|
|
281
281
|
primaryKey: row.primary_key,
|
|
282
282
|
payload: row.payload
|
|
283
|
-
}, {
|
|
283
|
+
}, { disableChecks: true })
|
|
284
284
|
|
|
285
285
|
const toEntryRow = (entry: EventJournal.Entry): EntryRow => ({
|
|
286
286
|
id: entry.id,
|
|
@@ -652,7 +652,7 @@ const applyMiddleware = <A extends Effect.Effect<any, any, any>>(
|
|
|
652
652
|
}
|
|
653
653
|
|
|
654
654
|
const securityMiddlewareCache = new WeakMap<
|
|
655
|
-
|
|
655
|
+
object,
|
|
656
656
|
(effect: Effect.Effect<any, any, any>, options: any) => Effect.Effect<any, any, any>
|
|
657
657
|
>()
|
|
658
658
|
|
|
@@ -660,13 +660,14 @@ const makeSecurityMiddleware = (
|
|
|
660
660
|
key: HttpApiMiddleware.AnyServiceSecurity,
|
|
661
661
|
service: HttpApiMiddleware.HttpApiMiddlewareSecurity<any, any, any, any>
|
|
662
662
|
): (effect: Effect.Effect<any, any, any>, options: any) => Effect.Effect<any, any, any> => {
|
|
663
|
-
|
|
664
|
-
|
|
663
|
+
const cached = securityMiddlewareCache.get(service)
|
|
664
|
+
if (cached !== undefined) {
|
|
665
|
+
return cached
|
|
665
666
|
}
|
|
666
667
|
|
|
667
|
-
const entries = Object.entries(key.security).map(([
|
|
668
|
+
const entries = Object.entries(key.security).map(([securityKey, security]) => ({
|
|
668
669
|
decode: securityDecode(security),
|
|
669
|
-
middleware: service[
|
|
670
|
+
middleware: service[securityKey]
|
|
670
671
|
}))
|
|
671
672
|
if (entries.length === 0) {
|
|
672
673
|
return identity
|
|
@@ -694,7 +695,7 @@ const makeSecurityMiddleware = (
|
|
|
694
695
|
return yield* lastResult!.asEffect()
|
|
695
696
|
})
|
|
696
697
|
|
|
697
|
-
securityMiddlewareCache.set(
|
|
698
|
+
securityMiddlewareCache.set(service, middleware)
|
|
698
699
|
return middleware
|
|
699
700
|
}
|
|
700
701
|
|
|
@@ -734,7 +735,11 @@ function getResponseTransformation(
|
|
|
734
735
|
schema: Schema.Top
|
|
735
736
|
): Transformation.Transformation<unknown, Response.HttpServerResponse> {
|
|
736
737
|
const ast = schema.ast
|
|
737
|
-
const encode = getResponseEncode(
|
|
738
|
+
const encode = getResponseEncode(
|
|
739
|
+
getStatus(ast),
|
|
740
|
+
HttpApiSchema.getResponseEncoding(ast),
|
|
741
|
+
HttpApiSchema.isNoContent(ast)
|
|
742
|
+
)
|
|
738
743
|
|
|
739
744
|
return Transformation.transformOrFail({
|
|
740
745
|
decode: (res) => Effect.fail(new Issue.Forbidden(Option.some(res), { message: "Encode only schema" })),
|
|
@@ -744,12 +749,13 @@ function getResponseTransformation(
|
|
|
744
749
|
|
|
745
750
|
function getResponseEncode<E>(
|
|
746
751
|
status: number,
|
|
747
|
-
encoding: HttpApiSchema.ResponseEncoding
|
|
752
|
+
encoding: HttpApiSchema.ResponseEncoding,
|
|
753
|
+
isNoContent: boolean
|
|
748
754
|
): (e: E) => Effect.Effect<Response.HttpServerResponse, Issue.InvalidValue, never> {
|
|
749
755
|
switch (encoding._tag) {
|
|
750
756
|
case "Json": {
|
|
751
757
|
return ((e) => {
|
|
752
|
-
if (e === undefined) {
|
|
758
|
+
if (e === undefined || isNoContent) {
|
|
753
759
|
return Effect.succeed(Response.empty({ status }))
|
|
754
760
|
}
|
|
755
761
|
try {
|
|
@@ -8,7 +8,7 @@ import { identity } from "../../Function.ts"
|
|
|
8
8
|
import * as Option from "../../Option.ts"
|
|
9
9
|
import * as Predicate from "../../Predicate.ts"
|
|
10
10
|
import * as Schema from "../../Schema.ts"
|
|
11
|
-
import
|
|
11
|
+
import * as AST from "../../SchemaAST.ts"
|
|
12
12
|
import * as Issue from "../../SchemaIssue.ts"
|
|
13
13
|
import * as Transformation from "../../SchemaTransformation.ts"
|
|
14
14
|
import type * as ServiceMap from "../../ServiceMap.ts"
|
|
@@ -59,6 +59,21 @@ export type ForApi<Api extends HttpApi.Any, E = BadRequest, R = never> = Api ext
|
|
|
59
59
|
* @category models
|
|
60
60
|
*/
|
|
61
61
|
export declare namespace Client {
|
|
62
|
+
/**
|
|
63
|
+
* @since 4.0.0
|
|
64
|
+
* @category models
|
|
65
|
+
*/
|
|
66
|
+
export type ResponseMode = HttpApiEndpoint.ClientResponseMode
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @since 4.0.0
|
|
70
|
+
* @category models
|
|
71
|
+
*/
|
|
72
|
+
export type Response<Success, Mode extends ResponseMode> = [Mode] extends ["decoded-and-response"]
|
|
73
|
+
? [Success, HttpClientResponse.HttpClientResponse]
|
|
74
|
+
: [Mode] extends ["response-only"] ? HttpClientResponse.HttpClientResponse
|
|
75
|
+
: Success
|
|
76
|
+
|
|
62
77
|
/**
|
|
63
78
|
* @since 4.0.0
|
|
64
79
|
* @category models
|
|
@@ -88,23 +103,21 @@ export declare namespace Client {
|
|
|
88
103
|
infer _Middleware,
|
|
89
104
|
infer _MR
|
|
90
105
|
>
|
|
91
|
-
] ? <
|
|
92
|
-
request: Simplify<HttpApiEndpoint.ClientRequest<_Params, _Query, _Payload, _Headers,
|
|
106
|
+
] ? <Mode extends ResponseMode = ResponseMode>(
|
|
107
|
+
request: Simplify<HttpApiEndpoint.ClientRequest<_Params, _Query, _Payload, _Headers, Mode>>
|
|
93
108
|
) => Effect.Effect<
|
|
94
|
-
|
|
95
|
-
| _Error["Type"]
|
|
109
|
+
Response<_Success["Type"], Mode>,
|
|
96
110
|
| HttpApiMiddleware.Error<_Middleware>
|
|
97
111
|
| HttpApiMiddleware.ClientError<_Middleware>
|
|
98
112
|
| E
|
|
99
113
|
| HttpClientError.HttpClientError
|
|
100
|
-
| Schema.SchemaError,
|
|
114
|
+
| ([Mode] extends ["response-only"] ? never : _Error["Type"] | Schema.SchemaError),
|
|
101
115
|
| R
|
|
102
116
|
| _Params["EncodingServices"]
|
|
103
117
|
| _Query["EncodingServices"]
|
|
104
118
|
| _Payload["EncodingServices"]
|
|
105
119
|
| _Headers["EncodingServices"]
|
|
106
|
-
| _Success["DecodingServices"]
|
|
107
|
-
| _Error["DecodingServices"]
|
|
120
|
+
| ([Mode] extends ["response-only"] ? never : _Success["DecodingServices"] | _Error["DecodingServices"])
|
|
108
121
|
> :
|
|
109
122
|
never
|
|
110
123
|
|
|
@@ -120,24 +133,11 @@ export declare namespace Client {
|
|
|
120
133
|
never
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
type ApiGroups<Api extends HttpApi.Any> = Api extends HttpApi.HttpApi<infer _ApiId, infer Groups> ? Groups : never
|
|
124
|
-
|
|
125
|
-
type EndpointId<Endpoint extends HttpApiEndpoint.Any> = Endpoint extends {
|
|
126
|
-
readonly method: infer Method extends HttpMethod.HttpMethod
|
|
127
|
-
readonly path: infer Path extends string
|
|
128
|
-
} ? `${Method} ${Path}`
|
|
129
|
-
: never
|
|
130
|
-
|
|
131
|
-
type EndpointWithId<Endpoints extends HttpApiEndpoint.Any, Id extends string> = Id extends
|
|
132
|
-
`${infer Method extends HttpMethod.HttpMethod} ${infer Path extends string}` ?
|
|
133
|
-
Extract<Endpoints, { readonly method: Method; readonly path: Path }> :
|
|
134
|
-
never
|
|
135
|
-
|
|
136
136
|
type UrlBuilderRequest<Endpoint extends HttpApiEndpoint.Any> = (
|
|
137
|
-
& ([HttpApiEndpoint.Params<Endpoint>["
|
|
138
|
-
: { readonly params: HttpApiEndpoint.Params<Endpoint>["
|
|
139
|
-
& ([HttpApiEndpoint.Query<Endpoint>["
|
|
140
|
-
: { readonly query: HttpApiEndpoint.Query<Endpoint>["
|
|
137
|
+
& ([HttpApiEndpoint.Params<Endpoint>["Type"]] extends [never] ? {}
|
|
138
|
+
: { readonly params: HttpApiEndpoint.Params<Endpoint>["Type"] })
|
|
139
|
+
& ([HttpApiEndpoint.Query<Endpoint>["Type"]] extends [never] ? {}
|
|
140
|
+
: { readonly query: HttpApiEndpoint.Query<Endpoint>["Type"] })
|
|
141
141
|
) extends infer Request ? keyof Request extends never ? void | undefined : Request
|
|
142
142
|
: never
|
|
143
143
|
|
|
@@ -149,15 +149,33 @@ type UrlBuilderArgs<Endpoint extends HttpApiEndpoint.Any> = [UrlBuilderRequest<E
|
|
|
149
149
|
* @since 4.0.0
|
|
150
150
|
* @category models
|
|
151
151
|
*/
|
|
152
|
-
export type UrlBuilder<Api extends HttpApi.Any> = <
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
export type UrlBuilder<Api extends HttpApi.Any> = Api extends HttpApi.HttpApi<infer _ApiId, infer Groups> ? Simplify<
|
|
153
|
+
& {
|
|
154
|
+
readonly [Group in Extract<Groups, { readonly topLevel: false }> as HttpApiGroup.Name<Group>]: UrlBuilderGroup<
|
|
155
|
+
HttpApiGroup.Endpoints<Group>
|
|
156
|
+
>
|
|
157
|
+
}
|
|
158
|
+
& {
|
|
159
|
+
readonly [Method in UrlBuilderTopLevelMethods<Groups> as Method[0]]: Method[1]
|
|
160
|
+
}
|
|
161
|
+
>
|
|
162
|
+
: never
|
|
163
|
+
|
|
164
|
+
type UrlBuilderGroup<Endpoints extends HttpApiEndpoint.Any> = {
|
|
165
|
+
readonly [Endpoint in Endpoints as HttpApiEndpoint.Name<Endpoint>]: UrlBuilderMethod<Endpoint>
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
type UrlBuilderMethod<Endpoint extends HttpApiEndpoint.Any> = (
|
|
169
|
+
...args: UrlBuilderArgs<Endpoint>
|
|
159
170
|
) => string
|
|
160
171
|
|
|
172
|
+
type UrlBuilderTopLevelMethods<Groups extends HttpApiGroup.Any> = Extract<Groups, { readonly topLevel: true }> extends
|
|
173
|
+
HttpApiGroup.HttpApiGroup<infer _Id, infer _Endpoints, infer _TopLevel> ?
|
|
174
|
+
_Endpoints extends infer Endpoint extends HttpApiEndpoint.Any ?
|
|
175
|
+
[HttpApiEndpoint.Name<Endpoint>, UrlBuilderMethod<Endpoint>]
|
|
176
|
+
: never :
|
|
177
|
+
never
|
|
178
|
+
|
|
161
179
|
const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>(
|
|
162
180
|
api: HttpApi.HttpApi<ApiId, Groups>,
|
|
163
181
|
options: {
|
|
@@ -268,7 +286,7 @@ const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>
|
|
|
268
286
|
const payloadSchemas = HttpApiEndpoint.getPayloadSchemas(endpoint)
|
|
269
287
|
const encodePayload = Arr.isArrayNonEmpty(payloadSchemas) ?
|
|
270
288
|
HttpMethod.hasBody(endpoint.method)
|
|
271
|
-
? Schema.encodeUnknownEffect(getEncodePayloadSchema(payloadSchemas))
|
|
289
|
+
? Schema.encodeUnknownEffect(getEncodePayloadSchema(payloadSchemas, endpoint.method))
|
|
272
290
|
: Schema.encodeUnknownEffect(Schema.Union(payloadSchemas)) :
|
|
273
291
|
undefined
|
|
274
292
|
|
|
@@ -283,7 +301,7 @@ const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>
|
|
|
283
301
|
readonly query: unknown
|
|
284
302
|
readonly payload: unknown
|
|
285
303
|
readonly headers: Record<string, string> | undefined
|
|
286
|
-
readonly
|
|
304
|
+
readonly responseMode?: HttpApiEndpoint.ClientResponseMode
|
|
287
305
|
} | undefined
|
|
288
306
|
) {
|
|
289
307
|
let httpRequest = HttpClientRequest.make(endpoint.method)(endpoint.path)
|
|
@@ -331,11 +349,15 @@ const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>
|
|
|
331
349
|
middlewareKeys.length - 1
|
|
332
350
|
)
|
|
333
351
|
|
|
352
|
+
if (request?.responseMode === "response-only") {
|
|
353
|
+
return response
|
|
354
|
+
}
|
|
355
|
+
|
|
334
356
|
const value = yield* (options.transformResponse === undefined
|
|
335
357
|
? decodeResponse(response)
|
|
336
358
|
: options.transformResponse(decodeResponse(response)))
|
|
337
359
|
|
|
338
|
-
return request?.
|
|
360
|
+
return request?.responseMode === "decoded-and-response" ? [value, response] : value
|
|
339
361
|
})
|
|
340
362
|
|
|
341
363
|
options.onEndpoint({
|
|
@@ -477,7 +499,7 @@ export const endpoint = <
|
|
|
477
499
|
}
|
|
478
500
|
|
|
479
501
|
/**
|
|
480
|
-
* Creates a type-safe URL builder
|
|
502
|
+
* Creates a type-safe URL builder that mirrors `HttpApiClient.make`.
|
|
481
503
|
*
|
|
482
504
|
* @example
|
|
483
505
|
* ```ts
|
|
@@ -492,11 +514,11 @@ export const endpoint = <
|
|
|
492
514
|
* )
|
|
493
515
|
* )
|
|
494
516
|
*
|
|
495
|
-
* const buildUrl = HttpApiClient.urlBuilder
|
|
517
|
+
* const buildUrl = HttpApiClient.urlBuilder(Api, {
|
|
496
518
|
* baseUrl: "https://api.example.com"
|
|
497
519
|
* })
|
|
498
520
|
*
|
|
499
|
-
* buildUrl(
|
|
521
|
+
* buildUrl.users.getUser({
|
|
500
522
|
* params: { id: "123" }
|
|
501
523
|
* })
|
|
502
524
|
* //=> "https://api.example.com/users/123"
|
|
@@ -504,19 +526,45 @@ export const endpoint = <
|
|
|
504
526
|
* @since 4.0.0
|
|
505
527
|
* @category constructors
|
|
506
528
|
*/
|
|
507
|
-
export const urlBuilder = <Api extends HttpApi.Any>(options?: {
|
|
529
|
+
export const urlBuilder = <Api extends HttpApi.Any>(api: Api, options?: {
|
|
508
530
|
readonly baseUrl?: URL | string | undefined
|
|
509
531
|
}): UrlBuilder<Api> => {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
532
|
+
const builder: Record<string, any> = {}
|
|
533
|
+
|
|
534
|
+
HttpApi.reflect(api as unknown as HttpApi.AnyWithProps, {
|
|
535
|
+
onGroup({ group }) {
|
|
536
|
+
if (group.topLevel) return
|
|
537
|
+
builder[group.identifier] = {}
|
|
538
|
+
},
|
|
539
|
+
onEndpoint({ group, endpoint }) {
|
|
540
|
+
const makeUrl = compilePath(endpoint.path)
|
|
541
|
+
const encodeParams = endpoint.params === undefined
|
|
542
|
+
? undefined
|
|
543
|
+
: Schema.encodeSync(endpoint.params as Schema.Encoder<unknown>)
|
|
544
|
+
const encodeQuery = endpoint.query === undefined
|
|
545
|
+
? undefined
|
|
546
|
+
: Schema.encodeSync(endpoint.query as Schema.Encoder<unknown>)
|
|
547
|
+
|
|
548
|
+
const endpointBuilder = (request?: {
|
|
549
|
+
readonly params?: unknown
|
|
550
|
+
readonly query?: unknown
|
|
551
|
+
}) => {
|
|
552
|
+
const params = request?.params
|
|
553
|
+
const path = params === undefined
|
|
554
|
+
? endpoint.path
|
|
555
|
+
: makeUrl((encodeParams === undefined ? params : encodeParams(params)) as Record<string, string | undefined>)
|
|
556
|
+
const queryInput = request?.query === undefined
|
|
557
|
+
? undefined
|
|
558
|
+
: (encodeQuery === undefined ? request.query : encodeQuery(request.query)) as UrlParams.Input
|
|
559
|
+
const query = queryInput === undefined ? "" : UrlParams.toString(UrlParams.fromInput(queryInput))
|
|
560
|
+
const url = query === "" ? path : `${path}?${query}`
|
|
561
|
+
return options?.baseUrl === undefined ? url : new URL(url, options.baseUrl.toString()).toString()
|
|
562
|
+
}
|
|
563
|
+
;(group.topLevel ? builder : builder[group.identifier])[endpoint.name] = endpointBuilder
|
|
564
|
+
}
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
return builder as UrlBuilder<Api>
|
|
520
568
|
}
|
|
521
569
|
|
|
522
570
|
// ----------------------------------------------------------------------------
|
|
@@ -608,8 +656,19 @@ function toCodecArrayBuffer(schemas: readonly [Schema.Top, ...Array<Schema.Top>]
|
|
|
608
656
|
function onSchema(schema: Schema.Top) {
|
|
609
657
|
const encoding = HttpApiSchema.getResponseEncoding(schema.ast)
|
|
610
658
|
switch (encoding._tag) {
|
|
611
|
-
case "Json":
|
|
612
|
-
|
|
659
|
+
case "Json": {
|
|
660
|
+
// handle json codecs that transform void schemas to null
|
|
661
|
+
const encodedIsNull = AST.isNull(AST.toEncoded(schema.ast))
|
|
662
|
+
return UnknownFromArrayBuffer.pipe(Schema.decodeTo(
|
|
663
|
+
schema,
|
|
664
|
+
encodedIsNull ?
|
|
665
|
+
Transformation.transform({
|
|
666
|
+
decode: (a) => a === undefined ? null : a,
|
|
667
|
+
encode: (a) => a === null ? undefined : a
|
|
668
|
+
}) as any :
|
|
669
|
+
undefined
|
|
670
|
+
))
|
|
671
|
+
}
|
|
613
672
|
case "FormUrlEncoded":
|
|
614
673
|
return StringFromArrayBuffer.pipe(
|
|
615
674
|
Schema.decodeTo(UrlParams.schemaRecord),
|
|
@@ -635,21 +694,25 @@ const statusOrElse = (response: HttpClientResponse.HttpClientResponse) =>
|
|
|
635
694
|
|
|
636
695
|
const $HttpBody = Schema.declare(HttpBody.isHttpBody)
|
|
637
696
|
|
|
638
|
-
function getEncodePayloadSchema(
|
|
639
|
-
|
|
697
|
+
function getEncodePayloadSchema(
|
|
698
|
+
schemas: readonly [Schema.Top, ...Array<Schema.Top>],
|
|
699
|
+
method: HttpMethod.HttpMethod
|
|
700
|
+
): Schema.Top {
|
|
701
|
+
return Schema.Union(schemas.map((s) => getEncodePayloadSchemaFromBody(s, method)))
|
|
640
702
|
}
|
|
641
703
|
|
|
642
704
|
const bodyFromPayloadCache = new WeakMap<AST.AST, Schema.Top>()
|
|
643
705
|
|
|
644
706
|
function getEncodePayloadSchemaFromBody(
|
|
645
|
-
schema: Schema.Top
|
|
707
|
+
schema: Schema.Top,
|
|
708
|
+
method: HttpMethod.HttpMethod
|
|
646
709
|
): Schema.Top {
|
|
647
710
|
const ast = schema.ast
|
|
648
711
|
const cached = bodyFromPayloadCache.get(ast)
|
|
649
712
|
if (cached !== undefined) {
|
|
650
713
|
return cached
|
|
651
714
|
}
|
|
652
|
-
const encoding = HttpApiSchema.getPayloadEncoding(ast)
|
|
715
|
+
const encoding = HttpApiSchema.getPayloadEncoding(ast, method)
|
|
653
716
|
const out = $HttpBody.pipe(Schema.decodeTo(
|
|
654
717
|
schema,
|
|
655
718
|
Transformation.transformOrFail({
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as Arr from "../../Array.ts"
|
|
5
5
|
import type { Brand } from "../../Brand.ts"
|
|
6
6
|
import type { Effect } from "../../Effect.ts"
|
|
7
|
+
import { identity } from "../../Function.ts"
|
|
7
8
|
import { type Pipeable, pipeArguments } from "../../Pipeable.ts"
|
|
8
9
|
import * as Predicate from "../../Predicate.ts"
|
|
9
10
|
import * as Schema from "../../Schema.ts"
|
|
@@ -476,7 +477,7 @@ export type ClientRequest<
|
|
|
476
477
|
Query extends Schema.Top,
|
|
477
478
|
Payload extends Schema.Top,
|
|
478
479
|
Headers extends Schema.Top,
|
|
479
|
-
|
|
480
|
+
ResponseMode extends ClientResponseMode
|
|
480
481
|
> = (
|
|
481
482
|
& ([Params["Type"]] extends [never] ? {} : { readonly params: Params["Type"] })
|
|
482
483
|
& ([Query["Type"]] extends [never] ? {} : { readonly query: Query["Type"] })
|
|
@@ -487,10 +488,16 @@ export type ClientRequest<
|
|
|
487
488
|
? { readonly payload: FormData }
|
|
488
489
|
: { readonly payload: Payload["Type"] }
|
|
489
490
|
: { readonly payload: Payload["Type"] })
|
|
490
|
-
) extends infer Req ? keyof Req extends never ? (void | { readonly
|
|
491
|
-
Req & { readonly
|
|
491
|
+
) extends infer Req ? keyof Req extends never ? (void | { readonly responseMode?: ResponseMode }) :
|
|
492
|
+
Req & { readonly responseMode?: ResponseMode } :
|
|
492
493
|
void
|
|
493
494
|
|
|
495
|
+
/**
|
|
496
|
+
* @since 4.0.0
|
|
497
|
+
* @category models
|
|
498
|
+
*/
|
|
499
|
+
export type ClientResponseMode = "decoded-only" | "decoded-and-response" | "response-only"
|
|
500
|
+
|
|
494
501
|
/**
|
|
495
502
|
* @since 4.0.0
|
|
496
503
|
* @category models
|
|
@@ -888,6 +895,14 @@ export type PayloadConstraint<Method extends HttpMethod> = Method extends HttpMe
|
|
|
888
895
|
> :
|
|
889
896
|
SuccessConstraint
|
|
890
897
|
|
|
898
|
+
/**
|
|
899
|
+
* @since 4.0.0
|
|
900
|
+
* @category constraints
|
|
901
|
+
*/
|
|
902
|
+
export type PayloadConstraintCodecs<Method extends HttpMethod> = Method extends HttpMethod.NoBody ?
|
|
903
|
+
Record<string, Schema.Top> :
|
|
904
|
+
Schema.Top | ReadonlyArray<Schema.Top>
|
|
905
|
+
|
|
891
906
|
/**
|
|
892
907
|
* @since 4.0.0
|
|
893
908
|
* @category constraints
|
|
@@ -904,7 +919,73 @@ export type ErrorConstraint = Schema.Top | ReadonlyArray<Schema.Top>
|
|
|
904
919
|
* @since 4.0.0
|
|
905
920
|
* @category constructors
|
|
906
921
|
*/
|
|
907
|
-
export const make = <Method extends HttpMethod>(method: Method)
|
|
922
|
+
export const make = <Method extends HttpMethod>(method: Method): {
|
|
923
|
+
<
|
|
924
|
+
const Name extends string,
|
|
925
|
+
const Path extends HttpRouter.PathInput,
|
|
926
|
+
Params extends Schema.Top | Schema.Struct.Fields = never,
|
|
927
|
+
Query extends Schema.Top | Schema.Struct.Fields = never,
|
|
928
|
+
Payload extends PayloadConstraintCodecs<Method> = never,
|
|
929
|
+
Headers extends Schema.Top | Schema.Struct.Fields = never,
|
|
930
|
+
const Success extends Schema.Top | ReadonlyArray<Schema.Top> = HttpApiSchema.NoContent,
|
|
931
|
+
const Error extends Schema.Top | ReadonlyArray<Schema.Top> = never
|
|
932
|
+
>(
|
|
933
|
+
name: Name,
|
|
934
|
+
path: Path,
|
|
935
|
+
options?: {
|
|
936
|
+
readonly disableCodecs?: false | undefined
|
|
937
|
+
readonly params?: Params | undefined
|
|
938
|
+
readonly query?: Query | undefined
|
|
939
|
+
readonly headers?: Headers | undefined
|
|
940
|
+
readonly payload?: Payload | undefined
|
|
941
|
+
readonly success?: Success | undefined
|
|
942
|
+
readonly error?: Error | undefined
|
|
943
|
+
}
|
|
944
|
+
): HttpApiEndpoint<
|
|
945
|
+
Name,
|
|
946
|
+
Method,
|
|
947
|
+
Path,
|
|
948
|
+
StringTree<Params extends Schema.Struct.Fields ? Schema.Struct<Params> : Params>,
|
|
949
|
+
StringTree<Query extends Schema.Struct.Fields ? Schema.Struct<Query> : Query>,
|
|
950
|
+
Method extends HttpMethod.WithBody ? Json<ExtractSchemaOrArray<Payload>>
|
|
951
|
+
: StringTree<ExtractSchemaOrArray<Payload>>,
|
|
952
|
+
StringTree<Headers extends Schema.Struct.Fields ? Schema.Struct<Headers> : Headers>,
|
|
953
|
+
Json<Success extends ReadonlyArray<Schema.Top> ? Success[number] : Success>,
|
|
954
|
+
Json<(Error extends ReadonlyArray<Schema.Top> ? Error[number] : Error) | typeof BadRequestNoContent>
|
|
955
|
+
>
|
|
956
|
+
<
|
|
957
|
+
const Name extends string,
|
|
958
|
+
const Path extends HttpRouter.PathInput,
|
|
959
|
+
Params extends ParamsConstraint = never,
|
|
960
|
+
Query extends QueryConstraint = never,
|
|
961
|
+
Payload extends PayloadConstraint<Method> = never,
|
|
962
|
+
Headers extends HeadersConstraint = never,
|
|
963
|
+
const Success extends SuccessConstraint = HttpApiSchema.NoContent,
|
|
964
|
+
const Error extends ErrorConstraint = never
|
|
965
|
+
>(
|
|
966
|
+
name: Name,
|
|
967
|
+
path: Path,
|
|
968
|
+
options?: {
|
|
969
|
+
readonly disableCodecs: true
|
|
970
|
+
readonly params?: Params | undefined
|
|
971
|
+
readonly query?: Query | undefined
|
|
972
|
+
readonly headers?: Headers | undefined
|
|
973
|
+
readonly payload?: Payload | undefined
|
|
974
|
+
readonly success?: Success | undefined
|
|
975
|
+
readonly error?: Error | undefined
|
|
976
|
+
}
|
|
977
|
+
): HttpApiEndpoint<
|
|
978
|
+
Name,
|
|
979
|
+
Method,
|
|
980
|
+
Path,
|
|
981
|
+
Params extends Schema.Struct.Fields ? Schema.Struct<Params> : Params,
|
|
982
|
+
Query extends Schema.Struct.Fields ? Schema.Struct<Query> : Query,
|
|
983
|
+
ExtractSchemaOrArray<Payload>,
|
|
984
|
+
ExtractSchemaOrArray<Headers>,
|
|
985
|
+
Success extends ReadonlyArray<Schema.Top> ? Success[number] : Success,
|
|
986
|
+
(Error extends ReadonlyArray<Schema.Top> ? Error[number] : Error) | typeof BadRequestNoContent
|
|
987
|
+
>
|
|
988
|
+
} =>
|
|
908
989
|
<
|
|
909
990
|
const Name extends string,
|
|
910
991
|
const Path extends HttpRouter.PathInput,
|
|
@@ -918,6 +999,7 @@ export const make = <Method extends HttpMethod>(method: Method) =>
|
|
|
918
999
|
name: Name,
|
|
919
1000
|
path: Path,
|
|
920
1001
|
options?: {
|
|
1002
|
+
readonly disableCodecs?: boolean | undefined
|
|
921
1003
|
readonly params?: Params | undefined
|
|
922
1004
|
readonly query?: Query | undefined
|
|
923
1005
|
readonly headers?: Headers | undefined
|
|
@@ -938,42 +1020,62 @@ export const make = <Method extends HttpMethod>(method: Method) =>
|
|
|
938
1020
|
Success extends ReadonlyArray<Schema.Top> ? Success[number] : Success,
|
|
939
1021
|
(Error extends ReadonlyArray<Schema.Top> ? Error[number] : Error) | typeof BadRequestNoContent
|
|
940
1022
|
> => {
|
|
1023
|
+
const disableCodecs = options?.disableCodecs ?? false
|
|
1024
|
+
const transformStringTree = disableCodecs ? identity : Schema.toCodecStringTree
|
|
941
1025
|
return makeProto({
|
|
942
1026
|
name,
|
|
943
1027
|
path,
|
|
944
1028
|
method,
|
|
945
|
-
params:
|
|
946
|
-
query:
|
|
947
|
-
headers:
|
|
948
|
-
payload: getPayload(options?.payload),
|
|
949
|
-
success:
|
|
950
|
-
error:
|
|
1029
|
+
params: ensureStruct(options?.params, transformStringTree),
|
|
1030
|
+
query: ensureStruct(options?.query, transformStringTree),
|
|
1031
|
+
headers: ensureStruct(options?.headers, transformStringTree),
|
|
1032
|
+
payload: getPayload(options?.payload, method, disableCodecs),
|
|
1033
|
+
success: getResponse(options?.success, disableCodecs),
|
|
1034
|
+
error: getResponse(options?.error, disableCodecs),
|
|
951
1035
|
annotations: ServiceMap.empty(),
|
|
952
1036
|
middlewares: new Set()
|
|
953
1037
|
})
|
|
954
1038
|
}
|
|
955
1039
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
}
|
|
1040
|
+
type ExtractSchemaOrArray<S extends Schema.Struct.Fields | Schema.Top | ReadonlyArray<Schema.Top>> = S extends
|
|
1041
|
+
Schema.Struct.Fields ? Schema.Struct<S>
|
|
1042
|
+
: S extends ReadonlyArray<Schema.Top> ? S[number]
|
|
1043
|
+
: S
|
|
961
1044
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1045
|
+
/**
|
|
1046
|
+
* @since 4.0.0
|
|
1047
|
+
* @category Codecs
|
|
1048
|
+
*/
|
|
1049
|
+
export interface Json<S extends Schema.Top>
|
|
1050
|
+
extends Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
|
|
1051
|
+
{}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* @since 4.0.0
|
|
1055
|
+
* @category Codecs
|
|
1056
|
+
*/
|
|
1057
|
+
export interface StringTree<S extends Schema.Top> extends
|
|
1058
|
+
Schema.Codec<
|
|
1059
|
+
S["Type"],
|
|
1060
|
+
Schema.StringTree,
|
|
1061
|
+
S["DecodingServices"],
|
|
1062
|
+
S["EncodingServices"]
|
|
1063
|
+
>
|
|
1064
|
+
{}
|
|
967
1065
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1066
|
+
function ensureStruct(
|
|
1067
|
+
params: Schema.Struct.Fields | Schema.Top | undefined,
|
|
1068
|
+
transform: typeof Schema.toCodecJson | typeof Schema.toCodecStringTree
|
|
1069
|
+
): Schema.Top | undefined {
|
|
1070
|
+
if (params === undefined) return undefined
|
|
1071
|
+
if (Schema.isSchema(params)) return transform(params)
|
|
1072
|
+
return transform(Schema.Struct(params))
|
|
973
1073
|
}
|
|
974
1074
|
|
|
975
1075
|
function getPayload(
|
|
976
|
-
payload: Schema.Top | ReadonlyArray<Schema.Top> | Schema.Struct.Fields | undefined
|
|
1076
|
+
payload: Schema.Top | ReadonlyArray<Schema.Top> | Schema.Struct.Fields | undefined,
|
|
1077
|
+
method: HttpMethod,
|
|
1078
|
+
disableCodecs: boolean
|
|
977
1079
|
): PayloadMap {
|
|
978
1080
|
const result: Map<string, { encoding: HttpApiSchema.PayloadEncoding; schemas: [Schema.Top, ...Array<Schema.Top>] }> =
|
|
979
1081
|
new Map()
|
|
@@ -982,9 +1084,11 @@ function getPayload(
|
|
|
982
1084
|
? payload
|
|
983
1085
|
: Schema.isSchema(payload)
|
|
984
1086
|
? [payload]
|
|
985
|
-
: [Schema.Struct(payload as any).pipe(HttpApiSchema.asFormUrlEncoded())]
|
|
1087
|
+
: [(Schema.Struct(payload as any)).pipe(HttpApiSchema.asFormUrlEncoded())]
|
|
1088
|
+
const transform = disableCodecs ? identity : transformPayload
|
|
1089
|
+
|
|
986
1090
|
for (const schema of schemas) {
|
|
987
|
-
const encoding = HttpApiSchema.getPayloadEncoding(schema.ast)
|
|
1091
|
+
const encoding = HttpApiSchema.getPayloadEncoding(schema.ast, method)
|
|
988
1092
|
const existing = result.get(encoding.contentType)
|
|
989
1093
|
if (existing) {
|
|
990
1094
|
if (existing.encoding._tag !== encoding._tag) {
|
|
@@ -993,24 +1097,48 @@ function getPayload(
|
|
|
993
1097
|
if (existing.encoding._tag === "Multipart") {
|
|
994
1098
|
throw new Error(`Multiple multipart payloads for content-type: ${encoding.contentType}`)
|
|
995
1099
|
}
|
|
996
|
-
existing.schemas.push(schema)
|
|
1100
|
+
existing.schemas.push(transform(schema, method))
|
|
997
1101
|
} else {
|
|
998
|
-
result.set(encoding.contentType, { encoding, schemas: [schema] })
|
|
1102
|
+
result.set(encoding.contentType, { encoding, schemas: [transform(schema, method)] })
|
|
999
1103
|
}
|
|
1000
1104
|
}
|
|
1001
1105
|
return result
|
|
1002
1106
|
}
|
|
1003
1107
|
|
|
1004
|
-
function
|
|
1005
|
-
success: Schema.Top | ReadonlyArray<Schema.Top> | undefined
|
|
1108
|
+
function getResponse(
|
|
1109
|
+
success: Schema.Top | ReadonlyArray<Schema.Top> | undefined,
|
|
1110
|
+
disableCodecs: boolean
|
|
1006
1111
|
): Set<Schema.Top> {
|
|
1007
1112
|
if (success === undefined) return new Set()
|
|
1008
|
-
|
|
1113
|
+
const arr = Arr.ensure(success)
|
|
1114
|
+
return new Set(disableCodecs ? arr : arr.map(transformResponse))
|
|
1009
1115
|
}
|
|
1010
1116
|
|
|
1011
|
-
function
|
|
1012
|
-
|
|
1013
|
-
|
|
1117
|
+
function transformResponse(schema: Schema.Top): Schema.Top {
|
|
1118
|
+
const encoding = HttpApiSchema.getResponseEncoding(schema.ast)
|
|
1119
|
+
switch (encoding._tag) {
|
|
1120
|
+
case "Json":
|
|
1121
|
+
return Schema.toCodecJson(schema)
|
|
1122
|
+
case "FormUrlEncoded":
|
|
1123
|
+
return Schema.toCodecStringTree(schema)
|
|
1124
|
+
case "Text":
|
|
1125
|
+
case "Uint8Array":
|
|
1126
|
+
return schema
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
function transformPayload(schema: Schema.Top, method: HttpMethod): Schema.Top {
|
|
1131
|
+
const encoding = HttpApiSchema.getPayloadEncoding(schema.ast, method)
|
|
1132
|
+
switch (encoding._tag) {
|
|
1133
|
+
case "Json":
|
|
1134
|
+
return Schema.toCodecJson(schema)
|
|
1135
|
+
case "FormUrlEncoded":
|
|
1136
|
+
return Schema.toCodecStringTree(schema)
|
|
1137
|
+
case "Text":
|
|
1138
|
+
case "Uint8Array":
|
|
1139
|
+
case "Multipart":
|
|
1140
|
+
return schema
|
|
1141
|
+
}
|
|
1014
1142
|
}
|
|
1015
1143
|
|
|
1016
1144
|
/**
|