effect-app 4.0.0-beta.25 → 4.0.0-beta.251
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/CHANGELOG.md +1137 -0
- package/dist/Array.d.ts +3 -2
- package/dist/Array.d.ts.map +1 -1
- package/dist/Array.js +4 -4
- package/dist/Chunk.d.ts +1 -1
- package/dist/Chunk.d.ts.map +1 -1
- package/dist/Config/SecretURL.d.ts +4 -2
- package/dist/Config/SecretURL.d.ts.map +1 -1
- package/dist/Config/SecretURL.js +3 -6
- package/dist/Config/internal/configSecretURL.d.ts +1 -1
- package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
- package/dist/Config/internal/configSecretURL.js +2 -2
- package/dist/Config.d.ts +7 -0
- package/dist/Config.d.ts.map +1 -0
- package/dist/Config.js +6 -0
- package/dist/ConfigProvider.d.ts +39 -0
- package/dist/ConfigProvider.d.ts.map +1 -0
- package/dist/ConfigProvider.js +42 -0
- package/dist/Context.d.ts +42 -0
- package/dist/Context.d.ts.map +1 -0
- package/dist/Context.js +67 -0
- package/dist/Effect.d.ts +13 -12
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +5 -8
- package/dist/Emailer.d.ts +51 -0
- package/dist/Emailer.d.ts.map +1 -0
- package/dist/Emailer.js +7 -0
- package/dist/Function.d.ts +1 -1
- package/dist/Function.d.ts.map +1 -1
- package/dist/Inputify.type.d.ts +1 -1
- package/dist/Layer.d.ts +11 -7
- package/dist/Layer.d.ts.map +1 -1
- package/dist/Layer.js +3 -2
- package/dist/Model/Repository/Registry.d.ts +21 -0
- package/dist/Model/Repository/Registry.d.ts.map +1 -0
- package/dist/Model/Repository/Registry.js +18 -0
- package/dist/Model/Repository/ext.d.ts +60 -0
- package/dist/Model/Repository/ext.d.ts.map +1 -0
- package/dist/Model/Repository/ext.js +122 -0
- package/dist/Model/Repository/internal/internal.d.ts +62 -0
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
- package/dist/Model/Repository/internal/internal.js +397 -0
- package/dist/Model/Repository/legacy.d.ts +21 -0
- package/dist/Model/Repository/legacy.d.ts.map +1 -0
- package/dist/Model/Repository/legacy.js +2 -0
- package/dist/Model/Repository/makeRepo.d.ts +53 -0
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
- package/dist/Model/Repository/makeRepo.js +27 -0
- package/dist/Model/Repository/service.d.ts +97 -0
- package/dist/Model/Repository/service.d.ts.map +1 -0
- package/dist/Model/Repository/service.js +2 -0
- package/dist/Model/Repository/validation.d.ts +71 -0
- package/dist/Model/Repository/validation.d.ts.map +1 -0
- package/dist/Model/Repository/validation.js +32 -0
- package/dist/Model/Repository.d.ts +7 -0
- package/dist/Model/Repository.d.ts.map +1 -0
- package/dist/Model/Repository.js +7 -0
- package/dist/Model/dsl.d.ts +33 -0
- package/dist/Model/dsl.d.ts.map +1 -0
- package/dist/Model/dsl.js +43 -0
- package/dist/Model/filter/filterApi.d.ts +30 -0
- package/dist/Model/filter/filterApi.d.ts.map +1 -0
- package/dist/Model/filter/filterApi.js +2 -0
- package/dist/Model/filter/types/errors.d.ts +29 -0
- package/dist/Model/filter/types/errors.d.ts.map +1 -0
- package/dist/Model/filter/types/errors.js +2 -0
- package/dist/Model/filter/types/fields.d.ts +15 -0
- package/dist/Model/filter/types/fields.d.ts.map +1 -0
- package/dist/Model/filter/types/fields.js +2 -0
- package/dist/Model/filter/types/path/common.d.ts +316 -0
- package/dist/Model/filter/types/path/common.d.ts.map +1 -0
- package/dist/Model/filter/types/path/common.js +2 -0
- package/dist/Model/filter/types/path/eager.d.ts +95 -0
- package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
- package/dist/Model/filter/types/path/eager.js +31 -0
- package/dist/Model/filter/types/path/index.d.ts +4 -0
- package/dist/Model/filter/types/path/index.d.ts.map +1 -0
- package/dist/Model/filter/types/path/index.js +3 -0
- package/dist/Model/filter/types/utils.d.ts +79 -0
- package/dist/Model/filter/types/utils.d.ts.map +1 -0
- package/dist/Model/filter/types/utils.js +2 -0
- package/dist/Model/filter/types/validator.d.ts +30 -0
- package/dist/Model/filter/types/validator.d.ts.map +1 -0
- package/dist/Model/filter/types/validator.js +2 -0
- package/dist/Model/filter/types.d.ts +5 -0
- package/dist/Model/filter/types.d.ts.map +1 -0
- package/dist/Model/filter/types.js +7 -0
- package/dist/Model/query/dsl.d.ts +446 -0
- package/dist/Model/query/dsl.d.ts.map +1 -0
- package/dist/Model/query/dsl.js +342 -0
- package/dist/Model/query/new-kid-interpreter.d.ts +136 -0
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
- package/dist/Model/query/new-kid-interpreter.js +336 -0
- package/dist/Model/query.d.ts +15 -0
- package/dist/Model/query.d.ts.map +1 -0
- package/dist/Model/query.js +3 -0
- package/dist/Model.d.ts +5 -0
- package/dist/Model.d.ts.map +1 -0
- package/dist/Model.js +5 -0
- package/dist/NonEmptySet.d.ts +4 -2
- package/dist/NonEmptySet.d.ts.map +1 -1
- package/dist/NonEmptySet.js +2 -2
- package/dist/Option.d.ts +2 -1
- package/dist/Option.d.ts.map +1 -1
- package/dist/Option.js +3 -1
- package/dist/Pure.d.ts +8 -6
- package/dist/Pure.d.ts.map +1 -1
- package/dist/Pure.js +17 -14
- package/dist/QueueMaker.d.ts +13 -0
- package/dist/QueueMaker.d.ts.map +1 -0
- package/dist/QueueMaker.js +4 -0
- package/dist/RequestContext.d.ts +103 -0
- package/dist/RequestContext.d.ts.map +1 -0
- package/dist/RequestContext.js +49 -0
- package/dist/Schema/Class.d.ts +66 -20
- package/dist/Schema/Class.d.ts.map +1 -1
- package/dist/Schema/Class.js +192 -23
- package/dist/Schema/FastCheck.d.ts +1 -1
- package/dist/Schema/FastCheck.d.ts.map +1 -1
- package/dist/Schema/Methods.d.ts +1 -1
- package/dist/Schema/SchemaParser.d.ts +5 -0
- package/dist/Schema/SchemaParser.d.ts.map +1 -0
- package/dist/Schema/SchemaParser.js +6 -0
- package/dist/Schema/SpecialJsonSchema.d.ts +34 -0
- package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
- package/dist/Schema/SpecialJsonSchema.js +118 -0
- package/dist/Schema/SpecialOpenApi.d.ts +32 -0
- package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
- package/dist/Schema/SpecialOpenApi.js +123 -0
- package/dist/Schema/brand.d.ts +5 -3
- package/dist/Schema/brand.d.ts.map +1 -1
- package/dist/Schema/brand.js +3 -1
- package/dist/Schema/email.d.ts +1 -1
- package/dist/Schema/email.d.ts.map +1 -1
- package/dist/Schema/email.js +7 -4
- package/dist/Schema/ext.d.ts +339 -56
- package/dist/Schema/ext.d.ts.map +1 -1
- package/dist/Schema/ext.js +358 -53
- package/dist/Schema/moreStrings.d.ts +108 -26
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +45 -16
- package/dist/Schema/numbers.d.ts +55 -15
- package/dist/Schema/numbers.d.ts.map +1 -1
- package/dist/Schema/numbers.js +60 -12
- package/dist/Schema/phoneNumber.d.ts +1 -1
- package/dist/Schema/phoneNumber.d.ts.map +1 -1
- package/dist/Schema/phoneNumber.js +6 -3
- package/dist/Schema/schema.d.ts +1 -1
- package/dist/Schema/strings.d.ts +5 -5
- package/dist/Schema/strings.d.ts.map +1 -1
- package/dist/Schema/strings.js +1 -5
- package/dist/Schema.d.ts +214 -8
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +190 -11
- package/dist/Set.d.ts +5 -2
- package/dist/Set.d.ts.map +1 -1
- package/dist/Set.js +3 -2
- package/dist/Store.d.ts +170 -0
- package/dist/Store.d.ts.map +1 -0
- package/dist/Store.js +121 -0
- package/dist/TypeTest.d.ts +1 -1
- package/dist/Types.d.ts +1 -1
- package/dist/Widen.type.d.ts +1 -1
- package/dist/_ext/Array.d.ts +2 -2
- package/dist/_ext/Array.d.ts.map +1 -1
- package/dist/_ext/Array.js +4 -2
- package/dist/_ext/date.d.ts +1 -1
- package/dist/_ext/misc.d.ts +5 -2
- package/dist/_ext/misc.d.ts.map +1 -1
- package/dist/_ext/misc.js +4 -2
- package/dist/_ext/ord.ext.d.ts +3 -2
- package/dist/_ext/ord.ext.d.ts.map +1 -1
- package/dist/_ext/ord.ext.js +2 -2
- package/dist/builtin.d.ts +1 -1
- package/dist/builtin.d.ts.map +1 -1
- package/dist/client/InvalidationKeys.d.ts +29 -0
- package/dist/client/InvalidationKeys.d.ts.map +1 -0
- package/dist/client/InvalidationKeys.js +33 -0
- package/dist/client/apiClientFactory.d.ts +20 -32
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +104 -34
- package/dist/client/clientFor.d.ts +53 -19
- package/dist/client/clientFor.d.ts.map +1 -1
- package/dist/client/clientFor.js +9 -1
- package/dist/client/errors.d.ts +49 -25
- package/dist/client/errors.d.ts.map +1 -1
- package/dist/client/errors.js +43 -17
- package/dist/client/makeClient.d.ts +495 -33
- package/dist/client/makeClient.d.ts.map +1 -1
- package/dist/client/makeClient.js +66 -24
- package/dist/client.d.ts +6 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/faker.d.ts +1 -1
- package/dist/faker.d.ts.map +1 -1
- package/dist/http/Request.d.ts +2 -2
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +2 -2
- package/dist/http/internal/lib.d.ts +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/ids.d.ts +40 -12
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +25 -3
- package/dist/index.d.ts +7 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/logger.d.ts +1 -1
- package/dist/middleware.d.ts +14 -8
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +14 -8
- package/dist/rpc/Invalidation.d.ts +420 -0
- package/dist/rpc/Invalidation.d.ts.map +1 -0
- package/dist/rpc/Invalidation.js +168 -0
- package/dist/rpc/MiddlewareMaker.d.ts +12 -8
- package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
- package/dist/rpc/MiddlewareMaker.js +59 -38
- package/dist/rpc/RpcContextMap.d.ts +4 -4
- package/dist/rpc/RpcContextMap.d.ts.map +1 -1
- package/dist/rpc/RpcContextMap.js +4 -4
- package/dist/rpc/RpcMiddleware.d.ts +15 -11
- package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
- package/dist/rpc/RpcMiddleware.js +1 -1
- package/dist/rpc.d.ts +2 -2
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -2
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +40 -0
- package/dist/setupRequest.d.ts +19 -0
- package/dist/setupRequest.d.ts.map +1 -0
- package/dist/setupRequest.js +69 -0
- package/dist/toast.d.ts +51 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +34 -0
- package/dist/transform.d.ts +2 -2
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +4 -5
- package/dist/utils/effectify.d.ts +2 -2
- package/dist/utils/effectify.d.ts.map +1 -1
- package/dist/utils/effectify.js +2 -2
- package/dist/utils/extend.d.ts +1 -1
- package/dist/utils/extend.d.ts.map +1 -1
- package/dist/utils/gen.d.ts +5 -5
- package/dist/utils/gen.d.ts.map +1 -1
- package/dist/utils/logLevel.d.ts +3 -3
- package/dist/utils/logLevel.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +5 -4
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +4 -4
- package/dist/utils.d.ts +40 -45
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +19 -27
- package/dist/validation/validators.d.ts +1 -1
- package/dist/validation/validators.d.ts.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/withToast.d.ts +30 -0
- package/dist/withToast.d.ts.map +1 -0
- package/dist/withToast.js +64 -0
- package/package.json +162 -24
- package/src/Array.ts +3 -3
- package/src/Config/SecretURL.ts +5 -2
- package/src/Config/internal/configSecretURL.ts +1 -1
- package/src/Config.ts +14 -0
- package/src/ConfigProvider.ts +48 -0
- package/src/{ServiceMap.ts → Context.ts} +56 -63
- package/src/Effect.ts +12 -14
- package/src/Emailer.ts +51 -0
- package/src/Layer.ts +10 -6
- package/src/Model/Repository/Registry.ts +34 -0
- package/src/Model/Repository/ext.ts +375 -0
- package/src/Model/Repository/internal/internal.ts +691 -0
- package/src/Model/Repository/legacy.ts +29 -0
- package/src/Model/Repository/makeRepo.ts +144 -0
- package/src/Model/Repository/service.ts +639 -0
- package/src/Model/Repository/validation.ts +31 -0
- package/src/Model/Repository.ts +6 -0
- package/src/Model/dsl.ts +129 -0
- package/src/Model/filter/filterApi.ts +60 -0
- package/src/Model/filter/types/errors.ts +47 -0
- package/src/Model/filter/types/fields.ts +50 -0
- package/src/Model/filter/types/path/common.ts +404 -0
- package/src/Model/filter/types/path/eager.ts +297 -0
- package/src/Model/filter/types/path/index.ts +4 -0
- package/src/Model/filter/types/utils.ts +128 -0
- package/src/Model/filter/types/validator.ts +46 -0
- package/src/Model/filter/types.ts +6 -0
- package/src/Model/query/dsl.ts +2546 -0
- package/src/Model/query/new-kid-interpreter.ts +484 -0
- package/src/Model/query.ts +13 -0
- package/src/Model.ts +4 -0
- package/src/NonEmptySet.ts +3 -1
- package/src/Option.ts +2 -0
- package/src/Pure.ts +21 -19
- package/src/QueueMaker.ts +19 -0
- package/src/RequestContext.ts +62 -0
- package/src/Schema/Class.ts +274 -64
- package/src/Schema/SchemaParser.ts +12 -0
- package/src/Schema/SpecialJsonSchema.ts +139 -0
- package/src/Schema/SpecialOpenApi.ts +130 -0
- package/src/Schema/brand.ts +22 -2
- package/src/Schema/email.ts +7 -2
- package/src/Schema/ext.ts +443 -88
- package/src/Schema/moreStrings.ts +93 -37
- package/src/Schema/numbers.ts +64 -16
- package/src/Schema/phoneNumber.ts +5 -1
- package/src/Schema/strings.ts +4 -8
- package/src/Schema.ts +374 -10
- package/src/Set.ts +5 -1
- package/src/Store.ts +277 -0
- package/src/_ext/Array.ts +3 -1
- package/src/_ext/misc.ts +4 -1
- package/src/_ext/ord.ext.ts +2 -1
- package/src/client/InvalidationKeys.ts +50 -0
- package/src/client/apiClientFactory.ts +230 -131
- package/src/client/clientFor.ts +102 -31
- package/src/client/errors.ts +52 -26
- package/src/client/makeClient.ts +592 -71
- package/src/client.ts +5 -4
- package/src/http/Request.ts +1 -1
- package/src/ids.ts +25 -3
- package/src/index.ts +7 -10
- package/src/middleware.ts +13 -9
- package/src/rpc/Invalidation.ts +261 -0
- package/src/rpc/MiddlewareMaker.ts +83 -75
- package/src/rpc/README.md +2 -2
- package/src/rpc/RpcContextMap.ts +6 -5
- package/src/rpc/RpcMiddleware.ts +18 -12
- package/src/rpc.ts +1 -1
- package/src/runtime.ts +56 -0
- package/src/setupRequest.ts +134 -0
- package/src/toast.ts +54 -0
- package/src/transform.ts +3 -3
- package/src/utils/effectify.ts +1 -1
- package/src/utils/gen.ts +8 -8
- package/src/utils/logLevel.ts +1 -1
- package/src/utils/logger.ts +4 -3
- package/src/utils.ts +62 -139
- package/src/withToast.ts +133 -0
- package/test/dist/rpc-dynamic-middleware.test.d.ts.map +1 -0
- package/test/dist/rpc.test.d.ts.map +1 -1
- package/test/dist/secretURL.test.d.ts.map +1 -0
- package/test/dist/special.test.d.ts.map +1 -0
- package/test/dist/stream-error.types.d.ts +2 -0
- package/test/dist/stream-error.types.d.ts.map +1 -0
- package/test/dist/stream-error.types.js +27 -0
- package/test/moreStrings.test.ts +1 -1
- package/test/rpc.test.ts +46 -6
- package/test/schema.test.ts +459 -30
- package/test/secretURL.test.ts +160 -0
- package/test/special.test.ts +1026 -0
- package/test/utils.test.ts +7 -7
- package/tsconfig.base.json +6 -5
- package/tsconfig.json +2 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +29 -29
- package/tsconfig.test.json +2 -2
- package/dist/Operations.d.ts +0 -123
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -29
- package/dist/ServiceMap.d.ts +0 -44
- package/dist/ServiceMap.d.ts.map +0 -1
- package/dist/ServiceMap.js +0 -91
- package/eslint.config.mjs +0 -26
- package/src/Operations.ts +0 -55
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { Effect, Layer, type Schema, Schema as S, type Scope, ServiceMap } from "effect"
|
|
3
2
|
import { type NonEmptyArray, type NonEmptyReadonlyArray } from "effect/Array"
|
|
3
|
+
import * as Effect from "effect/Effect"
|
|
4
|
+
import * as Layer from "effect/Layer"
|
|
5
|
+
import * as S from "effect/Schema"
|
|
6
|
+
import type * as Scope from "effect/Scope"
|
|
4
7
|
import { type Simplify } from "effect/Types"
|
|
5
8
|
import { Rpc, type RpcGroup, type RpcSchema } from "effect/unstable/rpc"
|
|
6
9
|
import { type HandlersFrom } from "effect/unstable/rpc/RpcGroup"
|
|
7
|
-
import
|
|
8
|
-
import { type HttpHeaders } from "../http.js"
|
|
10
|
+
import * as Context from "../Context.js"
|
|
9
11
|
import { PreludeLogger } from "../logger.js"
|
|
10
12
|
import { type TypeTestId } from "../TypeTest.js"
|
|
11
|
-
import { typedValuesOf } from "../utils.js"
|
|
12
13
|
import { type GetContextConfig, type RequestContextMapTagAny, type RpcContextMap } from "./RpcContextMap.js"
|
|
13
14
|
import { type AddMiddleware, type AnyDynamic, type RpcDynamic, type RpcMiddlewareV4, type TagClassAny } from "./RpcMiddleware.js"
|
|
14
15
|
import * as RpcMiddlewareX from "./RpcMiddleware.js"
|
|
@@ -61,13 +62,13 @@ export interface MiddlewareMaker<
|
|
|
61
62
|
}
|
|
62
63
|
>
|
|
63
64
|
{
|
|
64
|
-
readonly layer: Layer.Layer<Self, never,
|
|
65
|
+
readonly layer: Layer.Layer<Self, never, Context.Service.Identifier<MiddlewareProviders[number]>>
|
|
65
66
|
readonly requestContext: RequestContextTag<RequestContextMap>
|
|
66
67
|
readonly requestContextMap: RequestContextMap
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
export interface RequestContextTag<RequestContextMap extends Record<string, RpcContextMap.Any>>
|
|
70
|
-
extends
|
|
71
|
+
extends Context.Service<"RequestContextConfig", GetContextConfig<RequestContextMap>>
|
|
71
72
|
{}
|
|
72
73
|
|
|
73
74
|
export namespace MiddlewareMaker {
|
|
@@ -93,7 +94,7 @@ export namespace MiddlewareMaker {
|
|
|
93
94
|
: never
|
|
94
95
|
: never
|
|
95
96
|
|
|
96
|
-
export type Errors<T> = T extends TagClassAny ? T extends { error: S.Top } ?
|
|
97
|
+
export type Errors<T> = T extends TagClassAny ? T extends { error: S.Top } ? T["error"]["Type"]
|
|
97
98
|
: never
|
|
98
99
|
: never
|
|
99
100
|
|
|
@@ -169,9 +170,9 @@ export interface BuildingMiddleware<
|
|
|
169
170
|
> {
|
|
170
171
|
rpc: <
|
|
171
172
|
const Tag extends string,
|
|
172
|
-
Payload extends
|
|
173
|
-
Success extends
|
|
174
|
-
Error extends
|
|
173
|
+
Payload extends S.Top | S.Struct.Fields = typeof S.Void,
|
|
174
|
+
Success extends S.Top = typeof S.Void,
|
|
175
|
+
Error extends S.Top = typeof S.Never,
|
|
175
176
|
const Stream extends boolean = false,
|
|
176
177
|
Config extends GetContextConfig<RequestContextMap> = {}
|
|
177
178
|
>(tag: Tag, options?: {
|
|
@@ -180,16 +181,16 @@ export interface BuildingMiddleware<
|
|
|
180
181
|
readonly error?: Error
|
|
181
182
|
readonly stream?: Stream
|
|
182
183
|
readonly config?: Config
|
|
183
|
-
readonly primaryKey?: [Payload] extends [
|
|
184
|
-
payload: Payload extends
|
|
184
|
+
readonly primaryKey?: [Payload] extends [S.Struct.Fields] ? ((
|
|
185
|
+
payload: Payload extends S.Struct.Fields ? Simplify<S.Struct<Payload>["Type"]> : Payload["Type"]
|
|
185
186
|
) => string)
|
|
186
187
|
: never
|
|
187
188
|
}) =>
|
|
188
189
|
& Rpc.Rpc<
|
|
189
190
|
Tag,
|
|
190
|
-
Payload extends
|
|
191
|
+
Payload extends S.Struct.Fields ? S.Struct<Payload> : Payload,
|
|
191
192
|
Stream extends true ? RpcSchema.Stream<Success, Error> : Success,
|
|
192
|
-
Stream extends true ? typeof
|
|
193
|
+
Stream extends true ? typeof S.Never : Error
|
|
193
194
|
>
|
|
194
195
|
& { readonly config: Config }
|
|
195
196
|
|
|
@@ -258,10 +259,10 @@ export type MiddlewaresBuilder<
|
|
|
258
259
|
: { new(_: never): {} }
|
|
259
260
|
: { new(_: never): {} })
|
|
260
261
|
|
|
261
|
-
const middlewareMaker =
|
|
262
|
+
const middlewareMaker = Effect.fnUntraced(function*<
|
|
262
263
|
MiddlewareProviders extends ReadonlyArray<MiddlewareMaker.Any>
|
|
263
|
-
>(middlewares: MiddlewareProviders)
|
|
264
|
-
RpcMiddlewareV4<
|
|
264
|
+
>(middlewares: MiddlewareProviders) {
|
|
265
|
+
type Middleware = RpcMiddlewareV4<
|
|
265
266
|
MiddlewareMaker.ManyProvided<MiddlewareProviders>,
|
|
266
267
|
MiddlewareMaker.ManyErrors<MiddlewareProviders>,
|
|
267
268
|
Exclude<
|
|
@@ -270,42 +271,32 @@ const middlewareMaker = <
|
|
|
270
271
|
> extends never ? never
|
|
271
272
|
: Exclude<MiddlewareMaker.ManyRequired<MiddlewareProviders>, MiddlewareMaker.ManyProvided<MiddlewareProviders>>
|
|
272
273
|
>
|
|
273
|
-
|
|
274
|
+
type Next = Parameters<Middleware>[0]
|
|
275
|
+
type Options = Parameters<Middleware>[1]
|
|
276
|
+
|
|
274
277
|
// we want to run them in reverse order because latter middlewares will provide context to former ones
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
//
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
let handler = next
|
|
294
|
-
|
|
295
|
-
// inspired from Effect/RpcMiddleware
|
|
296
|
-
for (const tag of middlewares) {
|
|
297
|
-
// use the tag to get the middleware from context
|
|
298
|
-
const middleware = ServiceMap.getUnsafe(context, tag)
|
|
299
|
-
|
|
300
|
-
// wrap the current handler, allowing the middleware to run before and after it
|
|
301
|
-
handler = PreludeLogger.logDebug("Applying middleware wrap " + tag.key).pipe(
|
|
302
|
-
Effect.andThen(middleware(handler, options))
|
|
303
|
-
) as any
|
|
304
|
-
}
|
|
305
|
-
return handler
|
|
278
|
+
const reversed = middlewares.toReversed()
|
|
279
|
+
const context = yield* Effect.context()
|
|
280
|
+
|
|
281
|
+
// returns a Effect/RpcMiddlewareV4 with Scope.Scope in requirements
|
|
282
|
+
// v4: wrap middleware takes (effect, options) as two params instead of a single options bag
|
|
283
|
+
return (next: Next, options: Options) => {
|
|
284
|
+
// we start with the actual handler
|
|
285
|
+
let handler = next
|
|
286
|
+
|
|
287
|
+
// inspired from Effect/RpcMiddleware
|
|
288
|
+
for (const tag of reversed) {
|
|
289
|
+
// use the tag to get the middleware from context
|
|
290
|
+
const middleware = Context.getUnsafe(context, tag)
|
|
291
|
+
|
|
292
|
+
// wrap the current handler, allowing the middleware to run before and after it
|
|
293
|
+
handler = PreludeLogger.logDebug("Applying middleware wrap " + tag.key).pipe(
|
|
294
|
+
Effect.andThen(middleware(handler, options))
|
|
295
|
+
) as any
|
|
306
296
|
}
|
|
307
|
-
|
|
308
|
-
}
|
|
297
|
+
return handler
|
|
298
|
+
}
|
|
299
|
+
})
|
|
309
300
|
|
|
310
301
|
const makeMiddlewareBasic = <Self>() =>
|
|
311
302
|
// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
|
|
@@ -321,7 +312,26 @@ const makeMiddlewareBasic = <Self>() =>
|
|
|
321
312
|
// reverse middlewares and wrap one after the other
|
|
322
313
|
const middleware = middlewareMaker(make)
|
|
323
314
|
|
|
324
|
-
|
|
315
|
+
// Per-middleware error: union of the static `error` on the tag (if any) AND
|
|
316
|
+
// the rcm config entry pointed at by the middleware's `dynamic.key` (if any).
|
|
317
|
+
// Reason: middlewares declared with `dynamic: RequestContextMap.get("foo")`
|
|
318
|
+
// don't set a static `error` field — at runtime their `.error` defaults to
|
|
319
|
+
// `S.Never`. Without pulling from rcm, the composite middleware's
|
|
320
|
+
// `.error` collapses to `Never`, and `Rpc.exitSchema` (which walks
|
|
321
|
+
// `rpc.middlewares[*].error` to build the wire failure union) can't decode
|
|
322
|
+
// the actual middleware-thrown error type. Critical for stream rpcs whose
|
|
323
|
+
// top-level `errorSchema` is force-set to `Never` by effect-rpc.
|
|
324
|
+
const isMeaningfulError = (e: S.Top | undefined): e is S.Top => e !== undefined && e !== null && e !== S.Never
|
|
325
|
+
const rcmRecord = rcm as Record<string, RpcContextMap.Any>
|
|
326
|
+
const failures: Array<S.Top> = make.flatMap((_) => {
|
|
327
|
+
const out: Array<S.Top> = []
|
|
328
|
+
if (isMeaningfulError(_.error)) out.push(_.error)
|
|
329
|
+
const key = _.dynamic?.key as string | undefined
|
|
330
|
+
if (key && rcmRecord[key] && isMeaningfulError(rcmRecord[key].error)) {
|
|
331
|
+
out.push(rcmRecord[key].error)
|
|
332
|
+
}
|
|
333
|
+
return out
|
|
334
|
+
})
|
|
325
335
|
const provides = make.flatMap((_) => !_.provides ? [] : Array.isArray(_.provides) ? _.provides : [_.provides])
|
|
326
336
|
const requires = make
|
|
327
337
|
.flatMap((_) => !_.requires ? [] : Array.isArray(_.requires) ? _.requires : [_.requires])
|
|
@@ -357,17 +367,18 @@ const makeMiddlewareBasic = <Self>() =>
|
|
|
357
367
|
.effect(
|
|
358
368
|
MiddlewareMaker,
|
|
359
369
|
middleware as Effect.Effect<
|
|
360
|
-
any
|
|
361
|
-
Effect.Error<typeof middleware>,
|
|
362
|
-
Effect.Services<typeof middleware>
|
|
370
|
+
any
|
|
363
371
|
>
|
|
372
|
+
// todo; they dont change the type..
|
|
373
|
+
// Effect.Error<typeof middleware>,
|
|
374
|
+
// Effect.Services<typeof middleware>
|
|
364
375
|
)
|
|
365
376
|
|
|
366
377
|
// add to the tag a default implementation
|
|
367
378
|
return Object.assign(MiddlewareMaker, {
|
|
368
379
|
layer,
|
|
369
380
|
// tag to be used to retrieve the RequestContextConfig from Rpc annotations
|
|
370
|
-
requestContext:
|
|
381
|
+
requestContext: Context.Service<"RequestContextConfig", GetContextConfig<RequestContextMap>>(
|
|
371
382
|
"RequestContextConfig"
|
|
372
383
|
),
|
|
373
384
|
requestContextMap: rcm
|
|
@@ -379,8 +390,8 @@ export const Tag = <Self>() =>
|
|
|
379
390
|
const Id extends string,
|
|
380
391
|
RequestContextMap extends RequestContextMapTagAny
|
|
381
392
|
>(id: Id, rcm: RequestContextMap): MiddlewaresBuilder<Self, Id, RequestContextMap["config"]> => {
|
|
382
|
-
|
|
383
|
-
const requestContext =
|
|
393
|
+
const allMiddleware: MiddlewareMaker.Any[] = []
|
|
394
|
+
const requestContext = Context.Service<"RequestContextConfig", GetContextConfig<RequestContextMap["config"]>>(
|
|
384
395
|
"RequestContextConfig"
|
|
385
396
|
)
|
|
386
397
|
const it = {
|
|
@@ -388,9 +399,9 @@ export const Tag = <Self>() =>
|
|
|
388
399
|
// rpc with config
|
|
389
400
|
rpc: <
|
|
390
401
|
const Tag extends string,
|
|
391
|
-
Payload extends
|
|
392
|
-
Success extends
|
|
393
|
-
Error extends
|
|
402
|
+
Payload extends S.Top | S.Struct.Fields = typeof S.Void,
|
|
403
|
+
Success extends S.Top = typeof S.Void,
|
|
404
|
+
Error extends S.Top = typeof S.Never,
|
|
394
405
|
const Stream extends boolean = false,
|
|
395
406
|
Config extends GetContextConfig<RequestContextMap["config"]> = {}
|
|
396
407
|
>(tag: Tag, options?: {
|
|
@@ -399,35 +410,32 @@ export const Tag = <Self>() =>
|
|
|
399
410
|
readonly error?: Error
|
|
400
411
|
readonly stream?: Stream
|
|
401
412
|
readonly config?: Config
|
|
402
|
-
readonly primaryKey?: [Payload] extends [
|
|
403
|
-
payload: Payload extends
|
|
413
|
+
readonly primaryKey?: [Payload] extends [S.Struct.Fields] ? ((
|
|
414
|
+
payload: Payload extends S.Struct.Fields ? Simplify<S.Struct<Payload>["Type"]> : Payload["Type"]
|
|
404
415
|
) => string)
|
|
405
416
|
: never
|
|
406
417
|
}):
|
|
407
418
|
& Rpc.Rpc<
|
|
408
419
|
Tag,
|
|
409
|
-
Payload extends
|
|
420
|
+
Payload extends S.Struct.Fields ? S.Struct<Payload> : Payload,
|
|
410
421
|
// TODO: enhance `Error`. type based on middleware config.
|
|
411
422
|
Stream extends true ? RpcSchema.Stream<Success, Error> : Success,
|
|
412
|
-
Stream extends true ? typeof
|
|
423
|
+
Stream extends true ? typeof S.Never : Error
|
|
413
424
|
>
|
|
414
425
|
& { config: Config } =>
|
|
415
426
|
{
|
|
416
427
|
const config = options?.config ?? {} as Config
|
|
417
428
|
|
|
418
|
-
//
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const [firstError, ...restErrors] = allErrors
|
|
424
|
-
const newError = firstError ? S.Union([firstError, ...restErrors]) : S.Never
|
|
425
|
-
|
|
429
|
+
// The rpc's `error` schema carries ONLY the request's own declared errors.
|
|
430
|
+
// Middleware errors (rcm-derived) reach the wire via the middleware tag
|
|
431
|
+
// attached to the rpc group later (`RpcGroup.middleware(...)` at the
|
|
432
|
+
// routing/client level), and are unioned into the failure schema by
|
|
433
|
+
// `Rpc.exitSchema`'s `rpc.middlewares[*].error` walk.
|
|
426
434
|
// @ts-expect-error — TypeScript can't prove Simplify<T> ≡ { [K in keyof T]: T[K] } for unresolved generics (primaryKey)
|
|
427
435
|
const rpc = Rpc.make(tag, {
|
|
428
436
|
...options?.payload !== undefined ? { payload: options.payload } : {},
|
|
429
437
|
...options?.success !== undefined ? { success: options.success } : {},
|
|
430
|
-
error:
|
|
438
|
+
...options?.error !== undefined ? { error: options.error } : {},
|
|
431
439
|
...options?.stream !== undefined ? { stream: options.stream } : {},
|
|
432
440
|
...options?.primaryKey !== undefined ? { primaryKey: options.primaryKey } : {}
|
|
433
441
|
}) as any
|
|
@@ -437,7 +445,7 @@ export const Tag = <Self>() =>
|
|
|
437
445
|
middleware: (...middlewares: any[]) => {
|
|
438
446
|
for (const mw of middlewares) {
|
|
439
447
|
// recall that we run middlewares in reverse order
|
|
440
|
-
allMiddleware
|
|
448
|
+
allMiddleware.unshift(mw)
|
|
441
449
|
}
|
|
442
450
|
return allMiddleware.filter((m) => !!m.dynamic).length !== Object.keys(rcm.config).length
|
|
443
451
|
// for sure, until all the dynamic middlewares are provided it's non sensical to call makeMiddlewareBasic
|
package/src/rpc/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The extensions use V4 format of RPC middleware:
|
|
4
4
|
|
|
5
5
|
- supports `requires` besides `provides`
|
|
6
|
-
- `requires` and `provides`
|
|
6
|
+
- `requires` and `provides` should be set as second generic argument: `Tag<Self, Config>`.
|
|
7
7
|
- `wrap: true` is the default, there is no classic `provides: Tag`
|
|
8
8
|
|
|
9
9
|
## Features
|
|
@@ -34,7 +34,7 @@ NOTE: perhaps not as useful anymore if support for dynamic middleware gets integ
|
|
|
34
34
|
|
|
35
35
|
## Examples
|
|
36
36
|
|
|
37
|
-
See
|
|
37
|
+
See [tests](../../../infra/test/rpc-multi-middleware.test.ts)
|
|
38
38
|
|
|
39
39
|
## Future
|
|
40
40
|
|
package/src/rpc/RpcContextMap.ts
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import type * as S from "effect/Schema"
|
|
6
6
|
import { type AnyWithProps } from "effect/unstable/rpc/Rpc"
|
|
7
|
+
import * as Context from "../Context.js"
|
|
7
8
|
import { type RpcDynamic } from "./RpcMiddleware.js"
|
|
8
9
|
|
|
9
10
|
type Values<T extends Record<any, any>> = T[keyof T]
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* Middleware is inactivate by default, the Key is optional in route context, and the service is optionally provided as Effect
|
|
13
|
+
* Middleware is inactivate by default, the Key is optional in route context, and the service is optionally provided as Effect Context.
|
|
13
14
|
* Unless explicitly configured as `true`.
|
|
14
15
|
*/
|
|
15
16
|
export type RpcContextMap<Service, E> = {
|
|
@@ -22,7 +23,7 @@ export type RpcContextMap<Service, E> = {
|
|
|
22
23
|
|
|
23
24
|
export declare namespace RpcContextMap {
|
|
24
25
|
/**
|
|
25
|
-
* Middleware is active by default, and provides the Service at Key in route context, and the Service is provided as Effect
|
|
26
|
+
* Middleware is active by default, and provides the Service at Key in route context, and the Service is provided as Effect Context.
|
|
26
27
|
* Unless explicitly omitted.
|
|
27
28
|
*/
|
|
28
29
|
export type Inverted<Service, E> = {
|
|
@@ -97,7 +98,7 @@ export type GetEffectError<RequestContextMap extends Record<string, RpcContextMa
|
|
|
97
98
|
}
|
|
98
99
|
>
|
|
99
100
|
|
|
100
|
-
const tag =
|
|
101
|
+
const tag = Context.Service("RequestContextConfig")
|
|
101
102
|
|
|
102
103
|
export const makeMap = <const Config extends Record<string, RpcContextMap.Any>>(config: Config) => {
|
|
103
104
|
const cls = class {
|
|
@@ -109,7 +110,7 @@ export const makeMap = <const Config extends Record<string, RpcContextMap.Any>>(
|
|
|
109
110
|
return Object.assign(cls, {
|
|
110
111
|
config, /** Retrieves RequestContextConfig out of the Rpc annotations */
|
|
111
112
|
getConfig: (rpc: AnyWithProps): GetContextConfig<Config> => {
|
|
112
|
-
return
|
|
113
|
+
return Context.getOrElse(rpc.annotations, tag as any, () => ({}))
|
|
113
114
|
},
|
|
114
115
|
/** Adapter used when setting the dynamic prop on a middleware implementation */
|
|
115
116
|
get: <
|
package/src/rpc/RpcMiddleware.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
-
import { type Effect, type Schema, type Schema as S, type Scope, type ServiceMap, type Stream } from "effect"
|
|
5
4
|
import { type NonEmptyReadonlyArray } from "effect/Array"
|
|
5
|
+
import type * as Effect from "effect/Effect"
|
|
6
|
+
import type * as S from "effect/Schema"
|
|
7
|
+
import type * as Scope from "effect/Scope"
|
|
8
|
+
import type * as Stream from "effect/Stream"
|
|
6
9
|
import { type Rpc, RpcMiddleware } from "effect/unstable/rpc"
|
|
7
10
|
import { type TypeId } from "effect/unstable/rpc/RpcMiddleware"
|
|
11
|
+
import type * as Context from "../Context.js"
|
|
8
12
|
import { type GetEffectContext, type RpcContextMap } from "./RpcContextMap.js"
|
|
9
13
|
|
|
10
14
|
export type RpcMiddlewareV4<Provides, E, Requires> = RpcMiddleware.RpcMiddleware<Provides, E, Requires>
|
|
11
15
|
|
|
12
16
|
export type RpcOptionsOriginal = {
|
|
13
17
|
readonly optional?: boolean
|
|
14
|
-
readonly error?:
|
|
18
|
+
readonly error?: S.Top
|
|
15
19
|
readonly requiredForClient?: boolean
|
|
16
20
|
}
|
|
17
21
|
|
|
@@ -39,7 +43,7 @@ export interface TagClassAny extends RpcMiddleware.AnyService {
|
|
|
39
43
|
readonly optional: boolean
|
|
40
44
|
readonly provides: any
|
|
41
45
|
readonly requires: any
|
|
42
|
-
readonly error:
|
|
46
|
+
readonly error: S.Top
|
|
43
47
|
readonly dynamic?: RpcDynamic<any, any> | undefined
|
|
44
48
|
readonly dependsOn?: NonEmptyReadonlyArray<AnyDynamic> | undefined
|
|
45
49
|
}
|
|
@@ -49,27 +53,29 @@ export declare namespace TagClass {
|
|
|
49
53
|
* @since 1.0.0
|
|
50
54
|
* @category models
|
|
51
55
|
*/
|
|
52
|
-
export type FailureSchema<Options> = Options extends { readonly error:
|
|
56
|
+
export type FailureSchema<Options> = Options extends { readonly error: S.Top; readonly optional?: false }
|
|
53
57
|
? Options["error"]
|
|
54
58
|
// actually not, the Failure depends on Dynamic Middleware Configuration!
|
|
55
59
|
// : Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["error"]
|
|
56
|
-
: typeof
|
|
60
|
+
: typeof S.Never
|
|
57
61
|
|
|
58
62
|
/**
|
|
59
63
|
* @since 1.0.0
|
|
60
64
|
* @category models
|
|
61
65
|
*/
|
|
62
|
-
export type Failure<Options> = Options extends { readonly error:
|
|
63
|
-
? _A
|
|
66
|
+
export type Failure<Options> = Options extends { readonly error: S.Codec<infer _A>; readonly optional?: false } ? _A
|
|
64
67
|
// actually not, the Failure depends on Dynamic Middleware Configuration!
|
|
65
|
-
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ?
|
|
68
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["error"]["Type"]
|
|
66
69
|
: never
|
|
67
70
|
|
|
68
71
|
/**
|
|
69
72
|
* @since 1.0.0
|
|
70
73
|
* @category models
|
|
71
74
|
*/
|
|
72
|
-
|
|
75
|
+
// Avoid `S.Codec.DecodingServices<X> = X extends Top ? X["DecodingServices"] : never`:
|
|
76
|
+
// tsgo fails to reduce it here and leaves `unknown`. `FailureSchema<Options>` is
|
|
77
|
+
// always `S.Top` (either `Options["error"]` or `typeof S.Never`), so read directly.
|
|
78
|
+
export type FailureContext<Options> = FailureSchema<Options>["DecodingServices"]
|
|
73
79
|
|
|
74
80
|
/**
|
|
75
81
|
* @since 1.0.0
|
|
@@ -102,8 +108,8 @@ export declare namespace TagClass {
|
|
|
102
108
|
requires?: any
|
|
103
109
|
provides?: any
|
|
104
110
|
}
|
|
105
|
-
> extends
|
|
106
|
-
new(_: never):
|
|
111
|
+
> extends Context.Service<Self, Service> {
|
|
112
|
+
new(_: never): Context.ServiceClass.Shape<Name, Service>
|
|
107
113
|
readonly [TypeId]: TypeId
|
|
108
114
|
readonly optional: Optional<Options>
|
|
109
115
|
readonly error: FailureSchema<Options>
|
|
@@ -226,7 +232,7 @@ export type ExtractProvides<R extends Rpc.Any, Tag extends string> = R extends
|
|
|
226
232
|
Rpc.Rpc<Tag, infer _Payload, infer _Success, infer _Error, infer _Middleware, infer _Requires> ? _Middleware extends {
|
|
227
233
|
readonly provides: infer _P
|
|
228
234
|
} ? [_P] extends [never] ? never
|
|
229
|
-
: _P /*_P extends
|
|
235
|
+
: _P /*_P extends Context.Service<infer _I, infer _S> ? _I
|
|
230
236
|
: never */
|
|
231
237
|
: never
|
|
232
238
|
: never
|
package/src/rpc.ts
CHANGED
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as Exit from "effect/Exit"
|
|
2
|
+
import { flow } from "effect/Function"
|
|
3
|
+
import * as Logger from "effect/Logger"
|
|
4
|
+
import * as ManagedRuntime from "effect/ManagedRuntime"
|
|
5
|
+
import { CauseException } from "./client/errors.js"
|
|
6
|
+
import { type Context } from "./Context.js"
|
|
7
|
+
import * as Effect from "./Effect.js"
|
|
8
|
+
import * as Layer from "./Layer.js"
|
|
9
|
+
|
|
10
|
+
export const makeAppRuntime = Effect.fnUntraced(function*<A, E>(layer: Layer.Layer<A, E>) {
|
|
11
|
+
const l = layer.pipe(
|
|
12
|
+
Layer.provide(Logger.layer([Logger.consolePretty()]))
|
|
13
|
+
) as Layer.Layer<A>
|
|
14
|
+
const mrt = ManagedRuntime.make(l)
|
|
15
|
+
yield* mrt.contextEffect
|
|
16
|
+
return Object.assign(mrt, {
|
|
17
|
+
[Symbol.dispose]() {
|
|
18
|
+
return Effect.runSync(mrt.disposeEffect)
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
[Symbol.asyncDispose]() {
|
|
22
|
+
return mrt.dispose()
|
|
23
|
+
}
|
|
24
|
+
}) // as we initialise here, there is no more error left.
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export function initializeSync<A, E>(layer: Layer.Layer<A, E>) {
|
|
28
|
+
const runtime = Effect.runSync(makeAppRuntime(layer))
|
|
29
|
+
return runtime
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function initializeAsync<A, E>(layer: Layer.Layer<A, E>) {
|
|
33
|
+
return Effect
|
|
34
|
+
.runPromise(makeAppRuntime(layer))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// we wrap into CauseException because we want to keep the full cause of the failure.
|
|
38
|
+
export const makeRunPromise = <T>(services: Context<T>) =>
|
|
39
|
+
flow(Effect.runPromiseExitWith(services), (_) =>
|
|
40
|
+
_.then(
|
|
41
|
+
Exit.match({
|
|
42
|
+
onFailure: (cause) => Promise.reject(new CauseException(cause, "runPromise")),
|
|
43
|
+
onSuccess: (value) => Promise.resolve(value)
|
|
44
|
+
})
|
|
45
|
+
))
|
|
46
|
+
|
|
47
|
+
export const makeRunSync = <T>(services: Context<T>) =>
|
|
48
|
+
flow(
|
|
49
|
+
Effect.runSyncExitWith(services),
|
|
50
|
+
Exit.match({
|
|
51
|
+
onFailure: (cause) => {
|
|
52
|
+
throw new CauseException(cause, "runSync")
|
|
53
|
+
},
|
|
54
|
+
onSuccess: (value) => value
|
|
55
|
+
})
|
|
56
|
+
)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import * as Tracer from "effect/Tracer"
|
|
2
|
+
import { SqlClient } from "effect/unstable/sql"
|
|
3
|
+
import * as Effect from "./Effect.js"
|
|
4
|
+
import * as Layer from "./Layer.js"
|
|
5
|
+
import * as Option from "./Option.js"
|
|
6
|
+
import { LocaleRef, RequestContext, spanAttributes } from "./RequestContext.js"
|
|
7
|
+
import { NonEmptyString255 } from "./Schema.js"
|
|
8
|
+
import { ContextMapContainer, storeId } from "./Store.js"
|
|
9
|
+
|
|
10
|
+
const withSqlTransaction = <R, E, A>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
11
|
+
Effect.serviceOption(SqlClient.SqlClient).pipe(
|
|
12
|
+
Effect.flatMap(Option.match({
|
|
13
|
+
onNone: () => self,
|
|
14
|
+
onSome: (sql) => sql.withTransaction(self).pipe(Effect.orDie)
|
|
15
|
+
}))
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
export const getRequestContext = Effect
|
|
19
|
+
.all({
|
|
20
|
+
span: Effect.currentSpan.pipe(Effect.orDie),
|
|
21
|
+
locale: LocaleRef,
|
|
22
|
+
namespace: storeId
|
|
23
|
+
})
|
|
24
|
+
.pipe(
|
|
25
|
+
Effect.map(({ locale, namespace, span }) =>
|
|
26
|
+
RequestContext.make({
|
|
27
|
+
span: Tracer.externalSpan(span),
|
|
28
|
+
locale,
|
|
29
|
+
namespace,
|
|
30
|
+
name: NonEmptyString255(span.name)
|
|
31
|
+
})
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
export const getRC = Effect.all({
|
|
36
|
+
locale: LocaleRef,
|
|
37
|
+
namespace: storeId
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const withRequestSpan = (name = "request", options?: Tracer.SpanOptions) => <R, E, A>(f: Effect.Effect<A, E, R>) =>
|
|
41
|
+
Effect.andThen(
|
|
42
|
+
getRC,
|
|
43
|
+
(ctx) =>
|
|
44
|
+
f.pipe(
|
|
45
|
+
Effect.withSpan(name, {
|
|
46
|
+
...options,
|
|
47
|
+
attributes: { ...spanAttributes({ ...ctx, name: NonEmptyString255(name) }), ...options?.attributes }
|
|
48
|
+
}, {
|
|
49
|
+
captureStackTrace: options?.captureStackTrace ?? false
|
|
50
|
+
}),
|
|
51
|
+
// TODO: false
|
|
52
|
+
// request context info is picked up directly in the logger for annotations.
|
|
53
|
+
Effect.withLogSpan(name)
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
export interface SetupRequestOptions {
|
|
58
|
+
readonly withTransaction?: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Build `layer` against the ambient (request) scope rather than a sub-scope of the
|
|
62
|
+
// returned Effect. Required when the returned value is a streaming HttpServerResponse:
|
|
63
|
+
// the response body keeps producing chunks (and using layer-provided state) after the
|
|
64
|
+
// Effect returns, so a sub-scope would close too early and run finalizers mid-stream.
|
|
65
|
+
export const provideOnRequestScope =
|
|
66
|
+
<ROut, E2, RIn>(layer: Layer.Layer<ROut, E2, RIn>) => <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
|
67
|
+
Effect.gen(function*() {
|
|
68
|
+
const requestScope = yield* Effect.scope
|
|
69
|
+
// Fresh MemoMap per request: `Layer.buildWithScope` would otherwise reuse
|
|
70
|
+
// the ambient MemoMap living on the HTTP server fiber, sharing the built
|
|
71
|
+
// value (e.g. ContextMap) across every request handled by that server.
|
|
72
|
+
const memoMap = yield* Layer.makeMemoMap
|
|
73
|
+
const ctx = yield* Layer.buildWithMemoMap(layer, memoMap, requestScope)
|
|
74
|
+
return yield* Effect.provide(self, ctx)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
export const setupRequestContextFromCurrent =
|
|
78
|
+
(name = "request", options?: Tracer.SpanOptions & SetupRequestOptions) => <R, E, A>(self: Effect.Effect<A, E, R>) =>
|
|
79
|
+
self
|
|
80
|
+
.pipe(
|
|
81
|
+
options?.withTransaction === true ? withSqlTransaction : (_) => _,
|
|
82
|
+
withRequestSpan(name, options),
|
|
83
|
+
Effect.provide(ContextMapContainer.layer, { local: true })
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
// Streaming variant: binds ContextMapContainer to the ambient (request) scope so its
|
|
87
|
+
// finalizer (clear()) runs only after the response body is fully drained, not when the
|
|
88
|
+
// outer Effect returns its HttpServerResponse value. Use for handlers that return a
|
|
89
|
+
// streaming HttpServerResponse (e.g. SSE) — see RequestContextMiddleware for context.
|
|
90
|
+
export const setupStreamingRequestContextFromCurrent =
|
|
91
|
+
(name = "request", options?: Tracer.SpanOptions & SetupRequestOptions) => <R, E, A>(self: Effect.Effect<A, E, R>) =>
|
|
92
|
+
self.pipe(
|
|
93
|
+
options?.withTransaction === true ? withSqlTransaction : (_) => _,
|
|
94
|
+
withRequestSpan(name, options),
|
|
95
|
+
provideOnRequestScope(ContextMapContainer.layer)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
// TODO: consider integrating Effect.withParentSpan
|
|
99
|
+
export function setupRequestContext<R, E, A>(
|
|
100
|
+
self: Effect.Effect<A, E, R>,
|
|
101
|
+
requestContext: RequestContext,
|
|
102
|
+
options?: SetupRequestOptions
|
|
103
|
+
) {
|
|
104
|
+
const layer = Layer.mergeAll(
|
|
105
|
+
ContextMapContainer.layer,
|
|
106
|
+
Layer.succeed(LocaleRef, requestContext.locale),
|
|
107
|
+
Layer.succeed(storeId, requestContext.namespace)
|
|
108
|
+
)
|
|
109
|
+
return self
|
|
110
|
+
.pipe(
|
|
111
|
+
options?.withTransaction === true ? withSqlTransaction : (_) => _,
|
|
112
|
+
withRequestSpan(requestContext.name),
|
|
113
|
+
Effect.provide(layer, { local: true })
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function setupRequestContextWithCustomSpan<R, E, A>(
|
|
118
|
+
self: Effect.Effect<A, E, R>,
|
|
119
|
+
requestContext: RequestContext,
|
|
120
|
+
name: string,
|
|
121
|
+
options?: Tracer.SpanOptions & SetupRequestOptions
|
|
122
|
+
) {
|
|
123
|
+
const layer = Layer.mergeAll(
|
|
124
|
+
ContextMapContainer.layer,
|
|
125
|
+
Layer.succeed(LocaleRef, requestContext.locale),
|
|
126
|
+
Layer.succeed(storeId, requestContext.namespace)
|
|
127
|
+
)
|
|
128
|
+
return self
|
|
129
|
+
.pipe(
|
|
130
|
+
options?.withTransaction === true ? withSqlTransaction : (_) => _,
|
|
131
|
+
withRequestSpan(name, options),
|
|
132
|
+
Effect.provide(layer, { local: true })
|
|
133
|
+
)
|
|
134
|
+
}
|