@effect/platform 0.69.26 → 0.69.28
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/cjs/HttpApiBuilder.js +35 -17
- package/dist/cjs/HttpApiBuilder.js.map +1 -1
- package/dist/cjs/HttpApiClient.js +2 -3
- package/dist/cjs/HttpApiClient.js.map +1 -1
- package/dist/cjs/HttpApiEndpoint.js.map +1 -1
- package/dist/cjs/HttpClient.js +4 -1
- package/dist/cjs/HttpClient.js.map +1 -1
- package/dist/cjs/OpenApi.js +22 -5
- package/dist/cjs/OpenApi.js.map +1 -1
- package/dist/cjs/PlatformLogger.js +2 -0
- package/dist/cjs/PlatformLogger.js.map +1 -1
- package/dist/cjs/internal/httpClient.js +4 -1
- package/dist/cjs/internal/httpClient.js.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts +11 -5
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/HttpApiClient.d.ts.map +1 -1
- package/dist/dts/HttpApiEndpoint.d.ts +3 -1
- package/dist/dts/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/dts/HttpClient.d.ts +15 -3
- package/dist/dts/HttpClient.d.ts.map +1 -1
- package/dist/dts/OpenApi.d.ts.map +1 -1
- package/dist/dts/PlatformLogger.d.ts +6 -0
- package/dist/dts/PlatformLogger.d.ts.map +1 -1
- package/dist/dts/internal/httpClient.d.ts.map +1 -1
- package/dist/esm/HttpApiBuilder.js +35 -17
- package/dist/esm/HttpApiBuilder.js.map +1 -1
- package/dist/esm/HttpApiClient.js +2 -3
- package/dist/esm/HttpApiClient.js.map +1 -1
- package/dist/esm/HttpApiEndpoint.js.map +1 -1
- package/dist/esm/HttpClient.js +4 -1
- package/dist/esm/HttpClient.js.map +1 -1
- package/dist/esm/OpenApi.js +22 -5
- package/dist/esm/OpenApi.js.map +1 -1
- package/dist/esm/PlatformLogger.js +2 -0
- package/dist/esm/PlatformLogger.js.map +1 -1
- package/dist/esm/internal/httpClient.js +4 -1
- package/dist/esm/internal/httpClient.js.map +1 -1
- package/package.json +2 -2
- package/src/HttpApiBuilder.ts +57 -40
- package/src/HttpApiClient.ts +1 -6
- package/src/HttpApiEndpoint.ts +2 -1
- package/src/HttpClient.ts +23 -9
- package/src/OpenApi.ts +23 -7
- package/src/PlatformLogger.ts +6 -0
- package/src/internal/httpClient.ts +16 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect/platform",
|
|
3
|
-
"version": "0.69.
|
|
3
|
+
"version": "0.69.28",
|
|
4
4
|
"description": "Unified interfaces for common platform-specific services",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"multipasta": "^0.2.5"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"effect": "^3.10.
|
|
17
|
+
"effect": "^3.10.19"
|
|
18
18
|
},
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"provenance": true
|
package/src/HttpApiBuilder.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
+
import * as Cause from "effect/Cause"
|
|
4
5
|
import * as Chunk from "effect/Chunk"
|
|
5
6
|
import * as Context from "effect/Context"
|
|
6
7
|
import * as Effect from "effect/Effect"
|
|
@@ -88,7 +89,7 @@ export const serve = <R = never>(
|
|
|
88
89
|
httpApp.pipe(
|
|
89
90
|
Effect.map((app) => HttpServer.serve(app as any, middleware!)),
|
|
90
91
|
Layer.unwrapEffect,
|
|
91
|
-
Layer.provide(Router.Live)
|
|
92
|
+
Layer.provide([Router.Live, Middleware.layer])
|
|
92
93
|
)
|
|
93
94
|
|
|
94
95
|
/**
|
|
@@ -100,23 +101,24 @@ export const serve = <R = never>(
|
|
|
100
101
|
export const httpApp: Effect.Effect<
|
|
101
102
|
HttpApp.Default<never, HttpRouter.HttpRouter.DefaultServices>,
|
|
102
103
|
never,
|
|
103
|
-
Router | HttpApi.Api
|
|
104
|
+
Router | HttpApi.Api | Middleware
|
|
104
105
|
> = Effect.gen(function*() {
|
|
105
106
|
const { api, context } = yield* HttpApi.Api
|
|
106
107
|
const middleware = makeMiddlewareMap(api.middlewares, context)
|
|
107
108
|
const router = applyMiddleware(middleware, yield* Router.router)
|
|
108
|
-
const
|
|
109
|
+
const apiMiddlewareService = yield* Middleware
|
|
110
|
+
const apiMiddleware = yield* apiMiddlewareService.retrieve
|
|
109
111
|
const errorSchema = makeErrorSchema(api as any)
|
|
110
112
|
const encodeError = Schema.encodeUnknown(errorSchema)
|
|
111
113
|
return router.pipe(
|
|
112
|
-
apiMiddleware
|
|
113
|
-
Effect.
|
|
114
|
-
Effect.matchEffect(Effect.provide(encodeError(
|
|
115
|
-
onFailure: () => Effect.
|
|
114
|
+
apiMiddleware,
|
|
115
|
+
Effect.catchAllCause((cause) =>
|
|
116
|
+
Effect.matchEffect(Effect.provide(encodeError(Cause.squash(cause)), context), {
|
|
117
|
+
onFailure: () => Effect.failCause(cause),
|
|
116
118
|
onSuccess: Effect.succeed
|
|
117
119
|
})
|
|
118
120
|
)
|
|
119
|
-
)
|
|
121
|
+
) as any
|
|
120
122
|
})
|
|
121
123
|
|
|
122
124
|
/**
|
|
@@ -125,6 +127,7 @@ export const httpApp: Effect.Effect<
|
|
|
125
127
|
* @since 1.0.0
|
|
126
128
|
* @category constructors
|
|
127
129
|
* @example
|
|
130
|
+
* ```ts
|
|
128
131
|
* import { HttpApi, HttpApiBuilder, HttpServer } from "@effect/platform"
|
|
129
132
|
* import { Layer } from "effect"
|
|
130
133
|
*
|
|
@@ -140,6 +143,7 @@ export const httpApp: Effect.Effect<
|
|
|
140
143
|
* HttpServer.layerContext
|
|
141
144
|
* )
|
|
142
145
|
* )
|
|
146
|
+
* ```
|
|
143
147
|
*/
|
|
144
148
|
export const toWebHandler = <LA, LE>(
|
|
145
149
|
layer: Layer.Layer<LA | HttpApi.Api | HttpRouter.HttpRouter.DefaultServices, LE>,
|
|
@@ -157,7 +161,7 @@ export const toWebHandler = <LA, LE>(
|
|
|
157
161
|
readonly dispose: () => Promise<void>
|
|
158
162
|
} => {
|
|
159
163
|
const runtime = ManagedRuntime.make(
|
|
160
|
-
Layer.
|
|
164
|
+
Layer.mergeAll(layer, Router.Live, Middleware.layer),
|
|
161
165
|
options?.memoMap
|
|
162
166
|
)
|
|
163
167
|
let handlerCached: ((request: Request) => Promise<Response>) | undefined
|
|
@@ -505,8 +509,7 @@ export const handler = <
|
|
|
505
509
|
|
|
506
510
|
const requestPayload = (
|
|
507
511
|
request: HttpServerRequest.HttpServerRequest,
|
|
508
|
-
urlParams: ReadonlyRecord<string, string | Array<string
|
|
509
|
-
isMultipart: boolean
|
|
512
|
+
urlParams: ReadonlyRecord<string, string | Array<string>>
|
|
510
513
|
): Effect.Effect<
|
|
511
514
|
unknown,
|
|
512
515
|
never,
|
|
@@ -515,7 +518,7 @@ const requestPayload = (
|
|
|
515
518
|
| Scope
|
|
516
519
|
> =>
|
|
517
520
|
HttpMethod.hasBody(request.method)
|
|
518
|
-
?
|
|
521
|
+
? request.headers["content-type"].includes("multipart/form-data")
|
|
519
522
|
? Effect.orDie(request.multipart)
|
|
520
523
|
: Effect.orDie(request.json)
|
|
521
524
|
: Effect.succeed(urlParams)
|
|
@@ -551,10 +554,6 @@ const handlerToRoute = (
|
|
|
551
554
|
): HttpRouter.Route<any, any> => {
|
|
552
555
|
const endpoint = endpoint_ as HttpApiEndpoint.HttpApiEndpoint.AnyWithProps
|
|
553
556
|
const decodePath = Option.map(endpoint.pathSchema, Schema.decodeUnknown)
|
|
554
|
-
const isMultipart = endpoint.payloadSchema.pipe(
|
|
555
|
-
Option.map((schema) => HttpApiSchema.getMultipart(schema.ast)),
|
|
556
|
-
Option.getOrElse(() => false)
|
|
557
|
-
)
|
|
558
557
|
const decodePayload = Option.map(endpoint.payloadSchema, Schema.decodeUnknown)
|
|
559
558
|
const decodeHeaders = Option.map(endpoint.headersSchema, Schema.decodeUnknown)
|
|
560
559
|
const decodeUrlParams = Option.map(endpoint.urlParamsSchema, Schema.decodeUnknown)
|
|
@@ -576,7 +575,7 @@ const handlerToRoute = (
|
|
|
576
575
|
}
|
|
577
576
|
if (decodePayload._tag === "Some") {
|
|
578
577
|
request.payload = yield* Effect.flatMap(
|
|
579
|
-
requestPayload(httpRequest, urlParams
|
|
578
|
+
requestPayload(httpRequest, urlParams),
|
|
580
579
|
decodePayload.value
|
|
581
580
|
)
|
|
582
581
|
}
|
|
@@ -745,8 +744,26 @@ const toResponseError = toResponseSchema(HttpApiSchema.getStatusErrorAST)
|
|
|
745
744
|
*/
|
|
746
745
|
export class Middleware extends Context.Tag("@effect/platform/HttpApiBuilder/Middleware")<
|
|
747
746
|
Middleware,
|
|
748
|
-
|
|
749
|
-
|
|
747
|
+
{
|
|
748
|
+
readonly add: (middleware: HttpMiddleware.HttpMiddleware) => Effect.Effect<void>
|
|
749
|
+
readonly retrieve: Effect.Effect<HttpMiddleware.HttpMiddleware>
|
|
750
|
+
}
|
|
751
|
+
>() {
|
|
752
|
+
/**
|
|
753
|
+
* @since 1.0.0
|
|
754
|
+
*/
|
|
755
|
+
static readonly layer = Layer.sync(Middleware, () => {
|
|
756
|
+
let middleware: HttpMiddleware.HttpMiddleware = identity
|
|
757
|
+
return Middleware.of({
|
|
758
|
+
add: (f) =>
|
|
759
|
+
Effect.sync(() => {
|
|
760
|
+
const prev = middleware
|
|
761
|
+
middleware = (app) => f(prev(app))
|
|
762
|
+
}),
|
|
763
|
+
retrieve: Effect.sync(() => middleware)
|
|
764
|
+
})
|
|
765
|
+
})
|
|
766
|
+
}
|
|
750
767
|
|
|
751
768
|
/**
|
|
752
769
|
* @since 1.0.0
|
|
@@ -756,26 +773,24 @@ export type MiddlewareFn<Error, R = HttpRouter.HttpRouter.Provided> = (
|
|
|
756
773
|
httpApp: HttpApp.Default
|
|
757
774
|
) => HttpApp.Default<Error, R>
|
|
758
775
|
|
|
759
|
-
const middlewareAdd = (
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
)
|
|
776
|
+
const middlewareAdd = (
|
|
777
|
+
middleware: HttpMiddleware.HttpMiddleware
|
|
778
|
+
): Effect.Effect<void, never, Middleware> =>
|
|
779
|
+
Effect.gen(function*() {
|
|
780
|
+
const context = yield* Effect.context<never>()
|
|
781
|
+
const service = yield* Middleware
|
|
782
|
+
yield* service.add((httpApp) =>
|
|
783
|
+
Effect.mapInputContext(middleware(httpApp), (input) => Context.merge(context, input))
|
|
784
|
+
)
|
|
785
|
+
})
|
|
769
786
|
|
|
770
787
|
const middlewareAddNoContext = (
|
|
771
788
|
middleware: HttpMiddleware.HttpMiddleware
|
|
772
|
-
): Effect.Effect<
|
|
773
|
-
Effect.
|
|
774
|
-
|
|
775
|
-
(
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
)
|
|
789
|
+
): Effect.Effect<void, never, Middleware> =>
|
|
790
|
+
Effect.gen(function*() {
|
|
791
|
+
const service = yield* Middleware
|
|
792
|
+
yield* service.add(middleware)
|
|
793
|
+
})
|
|
779
794
|
|
|
780
795
|
/**
|
|
781
796
|
* Create an `HttpApi` level middleware `Layer`.
|
|
@@ -852,9 +867,9 @@ export const middleware: {
|
|
|
852
867
|
const withContext = apiFirst ? args[2]?.withContext === true : (args as any)[1]?.withContext === true
|
|
853
868
|
const add = withContext ? middlewareAdd : middlewareAddNoContext
|
|
854
869
|
const middleware = apiFirst ? args[1] : args[0]
|
|
855
|
-
return Effect.isEffect(middleware)
|
|
856
|
-
? Layer.
|
|
857
|
-
: Layer.
|
|
870
|
+
return (Effect.isEffect(middleware)
|
|
871
|
+
? Layer.effectDiscard(Effect.flatMap(middleware as any, add))
|
|
872
|
+
: Layer.effectDiscard(add(middleware as any))).pipe(Layer.provide(Middleware.layer))
|
|
858
873
|
}
|
|
859
874
|
|
|
860
875
|
/**
|
|
@@ -937,7 +952,9 @@ export const middlewareScoped: {
|
|
|
937
952
|
const withContext = apiFirst ? args[2]?.withContext === true : (args as any)[1]?.withContext === true
|
|
938
953
|
const add = withContext ? middlewareAdd : middlewareAddNoContext
|
|
939
954
|
const middleware = apiFirst ? args[1] : args[0]
|
|
940
|
-
return Layer.
|
|
955
|
+
return Layer.scopedDiscard(Effect.flatMap(middleware as any, add)).pipe(
|
|
956
|
+
Layer.provide(Middleware.layer)
|
|
957
|
+
)
|
|
941
958
|
}
|
|
942
959
|
|
|
943
960
|
/**
|
package/src/HttpApiClient.ts
CHANGED
|
@@ -160,12 +160,7 @@ const makeClient = <Groups extends HttpApiGroup.Any, ApiError, ApiR>(
|
|
|
160
160
|
successes.forEach((ast, status) => {
|
|
161
161
|
decodeMap[status] = ast._tag === "None" ? responseAsVoid : schemaToResponse(ast.value)
|
|
162
162
|
})
|
|
163
|
-
const isMultipart = endpoint.payloadSchema.pipe(
|
|
164
|
-
Option.map((schema) => HttpApiSchema.getMultipart(schema.ast)),
|
|
165
|
-
Option.getOrElse(() => false)
|
|
166
|
-
)
|
|
167
163
|
const encodePayload = endpoint.payloadSchema.pipe(
|
|
168
|
-
Option.filter(() => !isMultipart),
|
|
169
164
|
Option.map(Schema.encodeUnknown)
|
|
170
165
|
)
|
|
171
166
|
const encodeHeaders = endpoint.headersSchema.pipe(
|
|
@@ -185,7 +180,7 @@ const makeClient = <Groups extends HttpApiGroup.Any, ApiError, ApiR>(
|
|
|
185
180
|
let httpRequest = HttpClientRequest.make(endpoint.method)(
|
|
186
181
|
request && request.path ? makeUrl(request.path) : endpoint.path
|
|
187
182
|
)
|
|
188
|
-
if (
|
|
183
|
+
if (request.payload instanceof FormData) {
|
|
189
184
|
httpRequest = HttpClientRequest.bodyFormData(httpRequest, request.payload)
|
|
190
185
|
} else if (encodePayload._tag === "Some") {
|
|
191
186
|
const payload = yield* encodePayload.value(request.payload)
|
package/src/HttpApiEndpoint.ts
CHANGED
|
@@ -406,7 +406,8 @@ export declare namespace HttpApiEndpoint {
|
|
|
406
406
|
& ([UrlParams] extends [never] ? {} : { readonly urlParams: UrlParams })
|
|
407
407
|
& ([Headers] extends [never] ? {} : { readonly headers: Headers })
|
|
408
408
|
& ([Payload] extends [never] ? {}
|
|
409
|
-
:
|
|
409
|
+
: Payload extends infer P ?
|
|
410
|
+
P extends Brand<HttpApiSchema.MultipartTypeId> ? { readonly payload: FormData } : { readonly payload: P }
|
|
410
411
|
: { readonly payload: Payload })
|
|
411
412
|
) extends infer Req ? keyof Req extends never ? (void | { readonly withResponse?: WithResponse }) :
|
|
412
413
|
Req & { readonly withResponse?: WithResponse } :
|
package/src/HttpClient.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type * as Predicate from "effect/Predicate"
|
|
|
12
12
|
import type { Ref } from "effect/Ref"
|
|
13
13
|
import type * as Schedule from "effect/Schedule"
|
|
14
14
|
import type * as Scope from "effect/Scope"
|
|
15
|
+
import type { NoInfer } from "effect/Types"
|
|
15
16
|
import type { Cookies } from "./Cookies.js"
|
|
16
17
|
import type * as Error from "./HttpClientError.js"
|
|
17
18
|
import type * as ClientRequest from "./HttpClientRequest.js"
|
|
@@ -636,34 +637,47 @@ export const retry: {
|
|
|
636
637
|
} = internal.retry
|
|
637
638
|
|
|
638
639
|
/**
|
|
639
|
-
* Retries common transient errors, such as rate limiting or network issues.
|
|
640
|
+
* Retries common transient errors, such as rate limiting, timeouts or network issues.
|
|
641
|
+
*
|
|
642
|
+
* Specifying a `while` predicate allows you to consider other errors as
|
|
643
|
+
* transient.
|
|
640
644
|
*
|
|
641
645
|
* @since 1.0.0
|
|
642
646
|
* @category error handling
|
|
643
647
|
*/
|
|
644
648
|
export const retryTransient: {
|
|
645
649
|
/**
|
|
646
|
-
* Retries common transient errors, such as rate limiting or network issues.
|
|
650
|
+
* Retries common transient errors, such as rate limiting, timeouts or network issues.
|
|
651
|
+
*
|
|
652
|
+
* Specifying a `while` predicate allows you to consider other errors as
|
|
653
|
+
* transient.
|
|
647
654
|
*
|
|
648
655
|
* @since 1.0.0
|
|
649
656
|
* @category error handling
|
|
650
657
|
*/
|
|
651
658
|
<B, E, R1 = never>(
|
|
652
|
-
options:
|
|
653
|
-
|
|
654
|
-
|
|
659
|
+
options: {
|
|
660
|
+
readonly while?: Predicate.Predicate<NoInfer<E>>
|
|
661
|
+
readonly schedule?: Schedule.Schedule<B, NoInfer<E>, R1>
|
|
662
|
+
readonly times?: number
|
|
663
|
+
} | Schedule.Schedule<B, NoInfer<E>, R1>
|
|
655
664
|
): <R>(self: HttpClient<E, R>) => HttpClient<E, R1 | R>
|
|
656
665
|
/**
|
|
657
|
-
* Retries common transient errors, such as rate limiting or network issues.
|
|
666
|
+
* Retries common transient errors, such as rate limiting, timeouts or network issues.
|
|
667
|
+
*
|
|
668
|
+
* Specifying a `while` predicate allows you to consider other errors as
|
|
669
|
+
* transient.
|
|
658
670
|
*
|
|
659
671
|
* @since 1.0.0
|
|
660
672
|
* @category error handling
|
|
661
673
|
*/
|
|
662
674
|
<E, R, B, R1 = never>(
|
|
663
675
|
self: HttpClient<E, R>,
|
|
664
|
-
options:
|
|
665
|
-
|
|
666
|
-
|
|
676
|
+
options: {
|
|
677
|
+
readonly while?: Predicate.Predicate<NoInfer<E>>
|
|
678
|
+
readonly schedule?: Schedule.Schedule<B, NoInfer<E>, R1>
|
|
679
|
+
readonly times?: number
|
|
680
|
+
} | Schedule.Schedule<B, NoInfer<E>, R1>
|
|
667
681
|
): HttpClient<E, R1 | R>
|
|
668
682
|
} = internal.retryTransient
|
|
669
683
|
|
package/src/OpenApi.ts
CHANGED
|
@@ -269,14 +269,30 @@ export const fromApi = <A extends HttpApi.HttpApi.Any>(self: A): OpenAPISpec =>
|
|
|
269
269
|
endpoint.payloadSchema.pipe(
|
|
270
270
|
Option.filter(() => HttpMethod.hasBody(endpoint.method)),
|
|
271
271
|
Option.map((schema) => {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
272
|
+
const content: Mutable<OpenApiSpecContent> = {}
|
|
273
|
+
const members = schema.ast._tag === "Union" ? schema.ast.types : [schema.ast]
|
|
274
|
+
const jsonTypes: Array<AST.AST> = []
|
|
275
|
+
const multipartTypes: Array<AST.AST> = []
|
|
276
|
+
|
|
277
|
+
for (const member of members) {
|
|
278
|
+
if (HttpApiSchema.getMultipart(member)) {
|
|
279
|
+
multipartTypes.push(member)
|
|
280
|
+
} else {
|
|
281
|
+
jsonTypes.push(member)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (jsonTypes.length > 0) {
|
|
286
|
+
content["application/json"] = {
|
|
287
|
+
schema: makeJsonSchemaOrRef(Schema.make(AST.Union.make(jsonTypes)))
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (multipartTypes.length > 0) {
|
|
291
|
+
content["multipart/form-data"] = {
|
|
292
|
+
schema: makeJsonSchemaOrRef(Schema.make(AST.Union.make(multipartTypes)))
|
|
293
|
+
}
|
|
279
294
|
}
|
|
295
|
+
op.requestBody = { content, required: true }
|
|
280
296
|
})
|
|
281
297
|
)
|
|
282
298
|
for (const [status, ast] of successes) {
|
package/src/PlatformLogger.ts
CHANGED
|
@@ -14,6 +14,7 @@ import * as internal from "./internal/platformLogger.js"
|
|
|
14
14
|
*
|
|
15
15
|
* @since 1.0.0
|
|
16
16
|
* @example
|
|
17
|
+
* ```ts
|
|
17
18
|
* import { PlatformLogger } from "@effect/platform"
|
|
18
19
|
* import { NodeFileSystem, NodeRuntime } from "@effect/platform-node"
|
|
19
20
|
* import { Effect, Layer, Logger } from "effect"
|
|
@@ -31,6 +32,7 @@ import * as internal from "./internal/platformLogger.js"
|
|
|
31
32
|
* Effect.provide(LoggerLive),
|
|
32
33
|
* NodeRuntime.runMain
|
|
33
34
|
* )
|
|
35
|
+
* ```
|
|
34
36
|
*/
|
|
35
37
|
export const toFile: {
|
|
36
38
|
/**
|
|
@@ -38,6 +40,7 @@ export const toFile: {
|
|
|
38
40
|
*
|
|
39
41
|
* @since 1.0.0
|
|
40
42
|
* @example
|
|
43
|
+
* ```ts
|
|
41
44
|
* import { PlatformLogger } from "@effect/platform"
|
|
42
45
|
* import { NodeFileSystem, NodeRuntime } from "@effect/platform-node"
|
|
43
46
|
* import { Effect, Layer, Logger } from "effect"
|
|
@@ -55,6 +58,7 @@ export const toFile: {
|
|
|
55
58
|
* Effect.provide(LoggerLive),
|
|
56
59
|
* NodeRuntime.runMain
|
|
57
60
|
* )
|
|
61
|
+
* ```
|
|
58
62
|
*/
|
|
59
63
|
(
|
|
60
64
|
path: string,
|
|
@@ -73,6 +77,7 @@ export const toFile: {
|
|
|
73
77
|
*
|
|
74
78
|
* @since 1.0.0
|
|
75
79
|
* @example
|
|
80
|
+
* ```ts
|
|
76
81
|
* import { PlatformLogger } from "@effect/platform"
|
|
77
82
|
* import { NodeFileSystem, NodeRuntime } from "@effect/platform-node"
|
|
78
83
|
* import { Effect, Layer, Logger } from "effect"
|
|
@@ -90,6 +95,7 @@ export const toFile: {
|
|
|
90
95
|
* Effect.provide(LoggerLive),
|
|
91
96
|
* NodeRuntime.runMain
|
|
92
97
|
* )
|
|
98
|
+
* ```
|
|
93
99
|
*/
|
|
94
100
|
<Message>(
|
|
95
101
|
self: Logger.Logger<Message, string>,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause"
|
|
1
2
|
import * as Context from "effect/Context"
|
|
2
3
|
import * as Effect from "effect/Effect"
|
|
3
4
|
import type * as Fiber from "effect/Fiber"
|
|
@@ -11,6 +12,7 @@ import * as Predicate from "effect/Predicate"
|
|
|
11
12
|
import * as Ref from "effect/Ref"
|
|
12
13
|
import * as Schedule from "effect/Schedule"
|
|
13
14
|
import * as Scope from "effect/Scope"
|
|
15
|
+
import type { NoInfer } from "effect/Types"
|
|
14
16
|
import * as Cookies from "../Cookies.js"
|
|
15
17
|
import * as Headers from "../Headers.js"
|
|
16
18
|
import type * as Client from "../HttpClient.js"
|
|
@@ -565,6 +567,7 @@ export const retry: {
|
|
|
565
567
|
export const retryTransient: {
|
|
566
568
|
<B, E, R1 = never>(
|
|
567
569
|
options: {
|
|
570
|
+
readonly while?: Predicate.Predicate<NoInfer<E>>
|
|
568
571
|
readonly schedule?: Schedule.Schedule<B, NoInfer<E>, R1>
|
|
569
572
|
readonly times?: number
|
|
570
573
|
} | Schedule.Schedule<B, NoInfer<E>, R1>
|
|
@@ -572,6 +575,7 @@ export const retryTransient: {
|
|
|
572
575
|
<E, R, B, R1 = never>(
|
|
573
576
|
self: Client.HttpClient<E, R>,
|
|
574
577
|
options: {
|
|
578
|
+
readonly while?: Predicate.Predicate<NoInfer<E>>
|
|
575
579
|
readonly schedule?: Schedule.Schedule<B, NoInfer<E>, R1>
|
|
576
580
|
readonly times?: number
|
|
577
581
|
} | Schedule.Schedule<B, NoInfer<E>, R1>
|
|
@@ -581,6 +585,7 @@ export const retryTransient: {
|
|
|
581
585
|
<E extends E0, E0, R, B, R1 = never>(
|
|
582
586
|
self: Client.HttpClient<E, R>,
|
|
583
587
|
options: {
|
|
588
|
+
readonly while?: Predicate.Predicate<NoInfer<E>>
|
|
584
589
|
readonly schedule?: Schedule.Schedule<B, NoInfer<E>, R1>
|
|
585
590
|
readonly times?: number
|
|
586
591
|
} | Schedule.Schedule<B, NoInfer<E>, R1>
|
|
@@ -588,16 +593,23 @@ export const retryTransient: {
|
|
|
588
593
|
transformResponse(
|
|
589
594
|
self,
|
|
590
595
|
Effect.retry({
|
|
591
|
-
while:
|
|
592
|
-
|
|
593
|
-
(
|
|
594
|
-
(error._tag === "ResponseError" && error.response.status >= 429)),
|
|
596
|
+
while: Schedule.ScheduleTypeId in options || options.while === undefined
|
|
597
|
+
? isTransientError
|
|
598
|
+
: Predicate.or(isTransientError, options.while),
|
|
595
599
|
schedule: Schedule.ScheduleTypeId in options ? options : options.schedule,
|
|
596
600
|
times: Schedule.ScheduleTypeId in options ? undefined : options.times
|
|
597
601
|
})
|
|
598
602
|
)
|
|
599
603
|
)
|
|
600
604
|
|
|
605
|
+
const isTransientError = (error: unknown) =>
|
|
606
|
+
Predicate.hasProperty(error, Cause.TimeoutExceptionTypeId) || isTransientHttpError(error)
|
|
607
|
+
|
|
608
|
+
const isTransientHttpError = (error: unknown) =>
|
|
609
|
+
Error.isHttpClientError(error) &&
|
|
610
|
+
((error._tag === "RequestError" && error.reason === "Transport") ||
|
|
611
|
+
(error._tag === "ResponseError" && error.response.status >= 429))
|
|
612
|
+
|
|
601
613
|
/** @internal */
|
|
602
614
|
export const tap = dual<
|
|
603
615
|
<_, E2, R2>(
|