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,19 +1,22 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import
|
|
3
|
-
import { flow } from "effect/Function"
|
|
2
|
+
import { constant, flow } from "effect/Function"
|
|
4
3
|
import * as Layer from "effect/Layer"
|
|
5
4
|
import * as ManagedRuntime from "effect/ManagedRuntime"
|
|
5
|
+
import * as Option from "effect/Option"
|
|
6
6
|
import * as Predicate from "effect/Predicate"
|
|
7
7
|
import * as Schema from "effect/Schema"
|
|
8
|
+
import * as Stream from "effect/Stream"
|
|
8
9
|
import * as Struct from "effect/Struct"
|
|
9
10
|
import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/unstable/rpc"
|
|
11
|
+
import * as Config from "../Config.js"
|
|
12
|
+
import * as Context from "../Context.js"
|
|
10
13
|
import * as Effect from "../Effect.js"
|
|
11
14
|
import { HttpClient, HttpClientRequest } from "../http.js"
|
|
12
|
-
import
|
|
15
|
+
import { Invalidation } from "../rpc.js"
|
|
13
16
|
import type * as S from "../Schema.js"
|
|
14
|
-
import * as ServiceMap from "../ServiceMap.js"
|
|
15
17
|
import { typedKeysOf, typedValuesOf } from "../utils.js"
|
|
16
|
-
import type { Client, ClientForOptions,
|
|
18
|
+
import type { Client, ClientForOptions, ExtractModuleName, RequestsAny } from "./clientFor.js"
|
|
19
|
+
import { InvalidationKeysFromServer } from "./InvalidationKeys.js"
|
|
17
20
|
|
|
18
21
|
export interface ApiConfig {
|
|
19
22
|
url: string
|
|
@@ -31,16 +34,22 @@ export const DefaultApiConfig = Config.all({
|
|
|
31
34
|
})
|
|
32
35
|
|
|
33
36
|
export type Req = S.Top & {
|
|
34
|
-
|
|
37
|
+
readonly make: (...args: any[]) => any
|
|
35
38
|
_tag: string
|
|
36
39
|
fields: S.Struct.Fields
|
|
37
40
|
success: S.Top
|
|
38
41
|
error: S.Top
|
|
42
|
+
/** Optional final-value schema for stream requests. When set, the execute effect resolves with the last stream value decoded to this type. */
|
|
43
|
+
final?: S.Top
|
|
39
44
|
config?: Record<string, any>
|
|
40
|
-
readonly
|
|
45
|
+
readonly id: string
|
|
46
|
+
readonly moduleName: string
|
|
47
|
+
readonly type: "command" | "query"
|
|
48
|
+
readonly stream: boolean
|
|
49
|
+
readonly middleware?: unknown
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
class RequestName extends
|
|
52
|
+
class RequestName extends Context.Reference("RequestName", {
|
|
44
53
|
defaultValue: () => ({ requestName: "Unspecified", moduleName: "Error" })
|
|
45
54
|
}) {}
|
|
46
55
|
|
|
@@ -56,7 +65,7 @@ export const HttpClientLayer = (config: ApiConfig) =>
|
|
|
56
65
|
HttpClientRequest.setHeaders(config.headers.pipe(Option.getOrElse(() => ({}))))
|
|
57
66
|
),
|
|
58
67
|
HttpClient.mapRequestEffect((req) =>
|
|
59
|
-
Effect.map(RequestName
|
|
68
|
+
Effect.map(RequestName, (ctx) =>
|
|
60
69
|
flow(
|
|
61
70
|
HttpClientRequest.appendUrlParam("action", ctx.requestName),
|
|
62
71
|
HttpClientRequest.appendUrl("/" + ctx.moduleName)
|
|
@@ -84,7 +93,7 @@ type RpcHandlers<M extends RequestsAny> = {
|
|
|
84
93
|
[K in keyof M]: Rpc.Rpc<M[K]["_tag"], M[K], M[K]["success"], M[K]["error"]>
|
|
85
94
|
}
|
|
86
95
|
|
|
87
|
-
const getFiltered = <M extends
|
|
96
|
+
const getFiltered = <M extends RequestsAny>(resource: M) => {
|
|
88
97
|
type Filtered = {
|
|
89
98
|
[K in keyof M as M[K] extends Req ? K : never]: M[K] extends Req ? M[K] : never
|
|
90
99
|
}
|
|
@@ -102,176 +111,266 @@ const getFiltered = <M extends Requests>(resource: M) => {
|
|
|
102
111
|
return filtered as unknown as Filtered
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
export const getMeta = <M extends
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
export const getMeta = <M extends RequestsAny>(
|
|
115
|
+
resource: M
|
|
116
|
+
): { moduleName: ExtractModuleName<M>; middleware?: unknown } => {
|
|
117
|
+
const first = typedValuesOf(getFiltered(resource))[0]
|
|
118
|
+
if (first && "moduleName" in first) return { moduleName: first.moduleName, middleware: (first as any).middleware }
|
|
119
|
+
throw new Error("No moduleName on requests!")
|
|
109
120
|
}
|
|
110
121
|
|
|
111
|
-
export const makeRpcGroupFromRequestsAndModuleName = <M extends
|
|
122
|
+
export const makeRpcGroupFromRequestsAndModuleName = <M extends RequestsAny, const ModuleName extends string>(
|
|
112
123
|
resource: M,
|
|
113
|
-
moduleName: ModuleName
|
|
124
|
+
moduleName: ModuleName,
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
126
|
+
middleware?: any
|
|
114
127
|
) => {
|
|
115
128
|
const filtered = getFiltered(resource)
|
|
116
129
|
type newM = typeof filtered
|
|
117
|
-
const
|
|
130
|
+
const baseRpcs = RpcGroup
|
|
118
131
|
.make(
|
|
119
132
|
...typedValuesOf(filtered).map((_) => {
|
|
120
|
-
|
|
133
|
+
const r = _ as any
|
|
134
|
+
const isStream = r.stream
|
|
135
|
+
const isCommand = r.type === "command"
|
|
136
|
+
return (isCommand
|
|
137
|
+
? isStream
|
|
138
|
+
? Invalidation.makeStreamRpc(r._tag, {
|
|
139
|
+
payload: r,
|
|
140
|
+
success: r.success,
|
|
141
|
+
error: r.error,
|
|
142
|
+
stream: true as const
|
|
143
|
+
})
|
|
144
|
+
: Invalidation.makeCommandRpc(r._tag, { payload: r, success: r.success, error: r.error })
|
|
145
|
+
: Rpc.make(r._tag, { payload: r, success: r.success, error: r.error, stream: isStream })) as any
|
|
121
146
|
})
|
|
122
147
|
)
|
|
123
|
-
.prefix(`${moduleName}.`)
|
|
124
|
-
|
|
125
|
-
|
|
148
|
+
.prefix(`${moduleName}.`)
|
|
149
|
+
// Attach the middleware tag (schema-only on the client — no Live invoked)
|
|
150
|
+
// so its declared `error` joins the rpc failure union via
|
|
151
|
+
// `Rpc.exitSchema`'s `rpc.middlewares[*].error` walk. Required for stream
|
|
152
|
+
// rpcs whose top-level `errorSchema` is forced to `Never` by effect-rpc;
|
|
153
|
+
// without it, middleware-thrown errors fail client decode.
|
|
154
|
+
const rpcs = (middleware ? baseRpcs.middleware(middleware) : baseRpcs) as unknown as RpcGroup.RpcGroup<
|
|
155
|
+
Rpc.Prefixed<RpcHandlers<newM>[keyof newM], `${ModuleName}.`>
|
|
156
|
+
>
|
|
126
157
|
return rpcs
|
|
127
158
|
}
|
|
128
159
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const ModuleName extends string
|
|
132
|
-
>(
|
|
133
|
-
resource: M & { meta: { moduleName: ModuleName } }
|
|
134
|
-
) => makeRpcGroupFromRequestsAndModuleName(resource, resource.meta.moduleName)
|
|
135
|
-
|
|
136
|
-
const makeRpcTag = <M extends Requests>(resource: M) => {
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
161
|
+
const makeRpcTag = <M extends RequestsAny>(resource: M, middleware?: any) => {
|
|
137
162
|
const meta = getMeta(resource)
|
|
138
|
-
const rpcs = makeRpcGroupFromRequestsAndModuleName(resource, meta.moduleName)
|
|
163
|
+
const rpcs = makeRpcGroupFromRequestsAndModuleName(resource, meta.moduleName, middleware)
|
|
139
164
|
|
|
140
165
|
// Use Object.assign instead of class extension to avoid TS2509 with complex generic return types.
|
|
141
166
|
// The first type arg is `any` because this is a dynamically created tag — its identity is the string key.
|
|
142
|
-
const TheClient =
|
|
167
|
+
const TheClient = Context.Opaque<
|
|
143
168
|
any,
|
|
144
169
|
RpcClient.RpcClient<RpcGroup.Rpcs<typeof rpcs>>
|
|
145
170
|
>()(`RpcClient.${meta.moduleName}`)
|
|
146
171
|
// Use Layer.effect directly (not TheClient.toLayer) so TypeScript properly excludes Scope
|
|
147
172
|
const layer = Layer.effect(
|
|
148
173
|
TheClient,
|
|
149
|
-
RpcClient.make(rpcs
|
|
174
|
+
RpcClient.make(rpcs)
|
|
150
175
|
)
|
|
151
176
|
return Object.assign(TheClient, { layer })
|
|
152
177
|
}
|
|
153
178
|
|
|
154
179
|
const makeApiClientFactory = Effect
|
|
155
180
|
.gen(function*() {
|
|
156
|
-
const ctx = yield* Effect.
|
|
157
|
-
const makeClientFor =
|
|
181
|
+
const ctx = yield* Effect.context<RpcSerialization.RpcSerialization | HttpClient.HttpClient>()
|
|
182
|
+
const makeClientFor = Effect.fnUntraced(function*<M extends RequestsAny>(
|
|
158
183
|
resource: M,
|
|
159
184
|
requestLevelLayers = Layer.empty,
|
|
160
185
|
options?: ClientForOptions
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
) {
|
|
187
|
+
const meta = getMeta(resource)
|
|
188
|
+
|
|
189
|
+
const TheClient = makeRpcTag(resource, meta.middleware)
|
|
190
|
+
|
|
191
|
+
// TODO: somehow we need a protocol per REQUEST kind of it seems ...
|
|
192
|
+
// otherwise it locks up on the client, navigation remains empty...
|
|
193
|
+
const clientLayer = TheClient.layer.pipe(
|
|
194
|
+
// add ApiClientFactory for nested schemas
|
|
195
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
196
|
+
Layer.provide(Layer.succeed(ApiClientFactory, makeClientForCached as any)),
|
|
197
|
+
Layer.provide(
|
|
198
|
+
RpcClient
|
|
199
|
+
.layerProtocolHttp({ url: "" }) // why not here set meta.moduleName as root?
|
|
200
|
+
.pipe(
|
|
201
|
+
Layer.provideMerge(Layer.succeedContext(ctx))
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
const mr = ManagedRuntime.make(clientLayer)
|
|
206
|
+
|
|
207
|
+
const filtered = getFiltered(resource)
|
|
208
|
+
|
|
209
|
+
// Unwrap `CommandResponseWithMetaData` (success) and `CommandFailureWithMetaData`
|
|
210
|
+
// (handler-thrown failure): forward accumulated invalidation keys to
|
|
211
|
+
// `InvalidationKeysFromServer` and yield the raw payload / re-fail with the raw
|
|
212
|
+
// error. Middleware-thrown failures arrive raw on the Cause already (no wrap to
|
|
213
|
+
// strip) — the `else` branch passes them through.
|
|
214
|
+
const unwrapCommand = (eff: Effect.Effect<any, any, any>): Effect.Effect<any, any, any> =>
|
|
215
|
+
eff.pipe(
|
|
216
|
+
Effect.flatMap((result: any) =>
|
|
217
|
+
Effect.gen(function*() {
|
|
218
|
+
const keys: ReadonlyArray<Invalidation.InvalidationKey> = result?.metadata?.invalidateQueries ?? []
|
|
219
|
+
const invalidationKeys = yield* InvalidationKeysFromServer
|
|
220
|
+
yield* Effect.forEach(keys, (key) => invalidationKeys.add(key), { discard: true })
|
|
221
|
+
return result.payload
|
|
222
|
+
})
|
|
223
|
+
),
|
|
224
|
+
Effect.catch((result: any) =>
|
|
225
|
+
result?._tag === "CommandFailureWithMetaData"
|
|
226
|
+
? Effect.gen(function*() {
|
|
227
|
+
const keys: ReadonlyArray<Invalidation.InvalidationKey> = result.metadata?.invalidateQueries ?? []
|
|
228
|
+
const invalidationKeys = yield* InvalidationKeysFromServer
|
|
229
|
+
yield* Effect.forEach(keys, (key) => invalidationKeys.add(key), { discard: true })
|
|
230
|
+
return yield* Effect.fail(result.error)
|
|
177
231
|
})
|
|
178
|
-
.
|
|
179
|
-
Layer.provideMerge(Layer.succeedServices(ctx))
|
|
180
|
-
)
|
|
232
|
+
: Effect.fail(result)
|
|
181
233
|
)
|
|
182
234
|
)
|
|
183
|
-
const mr = ManagedRuntime.make(clientLayer)
|
|
184
235
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
236
|
+
return {
|
|
237
|
+
mr,
|
|
238
|
+
client: typedKeysOf(filtered)
|
|
239
|
+
.reduce((prev, cur) => {
|
|
240
|
+
const h = filtered[cur]!
|
|
241
|
+
|
|
242
|
+
const Request = h
|
|
243
|
+
|
|
244
|
+
const id = `${meta.moduleName}.${cur as string}`
|
|
245
|
+
.replaceAll(".js", "")
|
|
246
|
+
|
|
247
|
+
const requestMeta = {
|
|
248
|
+
Request,
|
|
249
|
+
id,
|
|
250
|
+
options
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const requestNameLayer = Layer.succeed(RequestName, {
|
|
254
|
+
requestName: cur as string,
|
|
255
|
+
moduleName: meta.moduleName
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
const layers = requestLevelLayers.pipe(Layer.provideMerge(requestNameLayer))
|
|
259
|
+
|
|
260
|
+
const fields = Struct.omit(Request.fields, ["_tag"] as const)
|
|
261
|
+
const requestAttr = `${meta.moduleName}.${h._tag}`
|
|
262
|
+
const isCommand = h.type === "command"
|
|
263
|
+
const isStream = h.stream
|
|
264
|
+
|
|
265
|
+
const buildEffect = (input: any) =>
|
|
266
|
+
mr.contextEffect.pipe(
|
|
267
|
+
Effect.flatMap((svcs) => {
|
|
268
|
+
const rpcEffect = TheClient
|
|
269
|
+
.use((client) => (client as any)[requestAttr]!(Request.make(input)) as Effect.Effect<any, any>)
|
|
270
|
+
.pipe(
|
|
271
|
+
// local: true → isolate to this RPC call. `layers` is pure today
|
|
272
|
+
// (RequestName + caller-supplied requestLevelLayers), but the
|
|
273
|
+
// flag prevents a stateful caller-supplied layer from leaking
|
|
274
|
+
// across RPC calls via the ambient fiber MemoMap.
|
|
275
|
+
Effect.provide(layers, { local: true }),
|
|
276
|
+
Effect.provide(svcs)
|
|
277
|
+
)
|
|
278
|
+
return isCommand ? unwrapCommand(rpcEffect) : rpcEffect
|
|
279
|
+
})
|
|
280
|
+
)
|
|
193
281
|
|
|
194
|
-
|
|
195
|
-
|
|
282
|
+
const buildStream = (input: any) =>
|
|
283
|
+
Stream.unwrap(
|
|
284
|
+
mr.contextEffect.pipe(
|
|
285
|
+
Effect.flatMap((svcs) =>
|
|
286
|
+
TheClient
|
|
287
|
+
.useSync((client) => {
|
|
288
|
+
const rpcStream = (client as any)[requestAttr]!(
|
|
289
|
+
Request.make(input)
|
|
290
|
+
) as Stream.Stream<any, any, any>
|
|
291
|
+
return rpcStream.pipe(
|
|
292
|
+
// Collect server invalidation keys from the "done" chunk, then discard it.
|
|
293
|
+
Stream.tap((item: any) =>
|
|
294
|
+
item._tag === "done" || item._tag === "metadata"
|
|
295
|
+
? InvalidationKeysFromServer.use((svc) =>
|
|
296
|
+
Effect.forEach(
|
|
297
|
+
(item.metadata as Invalidation.CommandMetaData).invalidateQueries,
|
|
298
|
+
svc.add,
|
|
299
|
+
{ discard: true }
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
: Effect.void
|
|
303
|
+
),
|
|
304
|
+
Stream.filter((item: any) => item._tag === "value"),
|
|
305
|
+
Stream.map((item: any) => item.value),
|
|
306
|
+
// V2: unwrap StreamFailureChunk — forward keys from failures too,
|
|
307
|
+
// then re-fail with the original error so callers see the unmodified
|
|
308
|
+
// error type.
|
|
309
|
+
Stream.catch((err: any) =>
|
|
310
|
+
err?._tag === "error" && err?.metadata
|
|
311
|
+
? Stream.fromEffect(
|
|
312
|
+
InvalidationKeysFromServer.use((svc) =>
|
|
313
|
+
Effect
|
|
314
|
+
.forEach(
|
|
315
|
+
(err.metadata as Invalidation.CommandMetaData).invalidateQueries,
|
|
316
|
+
svc.add,
|
|
317
|
+
{ discard: true }
|
|
318
|
+
)
|
|
319
|
+
.pipe(Effect.flatMap(() => Effect.fail(err.error)))
|
|
320
|
+
)
|
|
321
|
+
)
|
|
322
|
+
: Stream.fail(err)
|
|
323
|
+
),
|
|
324
|
+
// local: true — see buildEffect above.
|
|
325
|
+
Stream.provide(layers, { local: true }),
|
|
326
|
+
Stream.provide(svcs)
|
|
327
|
+
)
|
|
328
|
+
})
|
|
329
|
+
.pipe(Effect.provide(svcs))
|
|
330
|
+
)
|
|
331
|
+
)
|
|
332
|
+
)
|
|
196
333
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
334
|
+
// @ts-expect-error doc
|
|
335
|
+
prev[cur] = Object.keys(fields).length === 0
|
|
336
|
+
? {
|
|
337
|
+
handler: isStream ? constant(buildStream({})) : constant(buildEffect({})),
|
|
338
|
+
...requestMeta
|
|
339
|
+
}
|
|
340
|
+
: {
|
|
341
|
+
handler: isStream
|
|
342
|
+
? (req: any) => buildStream(req)
|
|
343
|
+
: (req: any) => buildEffect(req),
|
|
344
|
+
...requestMeta
|
|
201
345
|
}
|
|
202
346
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const layers = requestLevelLayers.pipe(Layer.provideMerge(requestNameLayer))
|
|
209
|
-
|
|
210
|
-
const fields = Struct.omit(Request.fields, ["_tag"] as const)
|
|
211
|
-
const requestAttr = `${meta.moduleName}.${h._tag}`
|
|
212
|
-
// @ts-expect-error doc
|
|
213
|
-
prev[cur] = Object.keys(fields).length === 0
|
|
214
|
-
? {
|
|
215
|
-
handler: mr.servicesEffect.pipe(
|
|
216
|
-
Effect.flatMap((svcs) =>
|
|
217
|
-
TheClient
|
|
218
|
-
.use((client) => (client as any)[requestAttr]!(new Request()) as Effect.Effect<any, any, never>)
|
|
219
|
-
.pipe(
|
|
220
|
-
Effect.provide(layers),
|
|
221
|
-
Effect.provide(svcs)
|
|
222
|
-
)
|
|
223
|
-
)
|
|
224
|
-
),
|
|
225
|
-
...requestMeta
|
|
226
|
-
}
|
|
227
|
-
: {
|
|
228
|
-
handler: (req: any) =>
|
|
229
|
-
mr.servicesEffect.pipe(
|
|
230
|
-
Effect.flatMap((svcs) =>
|
|
231
|
-
TheClient
|
|
232
|
-
.use((client) =>
|
|
233
|
-
(client as any)[requestAttr]!(new Request(req)) as Effect.Effect<any, any, never>
|
|
234
|
-
)
|
|
235
|
-
.pipe(
|
|
236
|
-
Effect.provide(layers),
|
|
237
|
-
Effect.provide(svcs)
|
|
238
|
-
)
|
|
239
|
-
)
|
|
240
|
-
),
|
|
241
|
-
|
|
242
|
-
...requestMeta
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return prev
|
|
246
|
-
}, {} as Client<M, M["meta"]["moduleName"]>)
|
|
247
|
-
}
|
|
248
|
-
})
|
|
347
|
+
return prev
|
|
348
|
+
}, {} as Client<M, ExtractModuleName<M>>)
|
|
349
|
+
}
|
|
350
|
+
})
|
|
249
351
|
|
|
250
352
|
const register: ManagedRuntime.ManagedRuntime<any, any>[] = []
|
|
251
353
|
yield* Effect.addFinalizer(() => Effect.forEach(register, (mr) => mr.disposeEffect))
|
|
252
354
|
|
|
253
355
|
const cacheL = new Map<any, Map<any, Client<any, any>>>()
|
|
254
356
|
|
|
255
|
-
function makeClientForCached(requestLevelLayers: Layer.Layer<never
|
|
357
|
+
function makeClientForCached(requestLevelLayers: Layer.Layer<never>, options?: ClientForOptions) {
|
|
256
358
|
let cache = cacheL.get(requestLevelLayers)
|
|
257
359
|
if (!cache) {
|
|
258
360
|
cache = new Map<any, Client<any, any>>()
|
|
259
361
|
cacheL.set(requestLevelLayers, cache)
|
|
260
362
|
}
|
|
261
363
|
|
|
262
|
-
return
|
|
263
|
-
models
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
register.push(m.mr)
|
|
273
|
-
return m.client
|
|
274
|
-
})
|
|
364
|
+
return Effect.fnUntraced(function*<M extends RequestsAny>(models: M) {
|
|
365
|
+
const found = cache.get(models) as Client<M, ExtractModuleName<M>> | undefined
|
|
366
|
+
if (found) {
|
|
367
|
+
return found
|
|
368
|
+
}
|
|
369
|
+
const m = yield* makeClientFor(models, requestLevelLayers, options)
|
|
370
|
+
cache.set(models, m.client)
|
|
371
|
+
register.push(m.mr)
|
|
372
|
+
return m.client
|
|
373
|
+
})
|
|
275
374
|
}
|
|
276
375
|
|
|
277
376
|
return makeClientForCached
|
|
@@ -281,7 +380,7 @@ const makeApiClientFactory = Effect
|
|
|
281
380
|
* Used to create clients for resource modules.
|
|
282
381
|
*/
|
|
283
382
|
export class ApiClientFactory
|
|
284
|
-
extends
|
|
383
|
+
extends Context.Opaque<ApiClientFactory, Effect.Success<typeof makeApiClientFactory>>()("ApiClientFactory")
|
|
285
384
|
{
|
|
286
385
|
static readonly layer = (config: ApiConfig) =>
|
|
287
386
|
ApiClientFactory.toLayer(makeApiClientFactory).pipe(Layer.provide(RpcSerializationLayer(config)))
|
|
@@ -293,8 +392,8 @@ export class ApiClientFactory
|
|
|
293
392
|
)
|
|
294
393
|
|
|
295
394
|
static readonly makeFor =
|
|
296
|
-
(requestLevelLayers: Layer.Layer<never
|
|
297
|
-
<M extends
|
|
395
|
+
(requestLevelLayers: Layer.Layer<never>, options?: ClientForOptions) =>
|
|
396
|
+
<M extends RequestsAny>(
|
|
298
397
|
resource: M
|
|
299
398
|
) =>
|
|
300
399
|
ApiClientFactory.use((apiClientFactory) => {
|
package/src/client/clientFor.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
3
|
|
|
4
4
|
import * as Record from "effect/Record"
|
|
5
|
-
import type * as
|
|
5
|
+
import type * as Stream from "effect/Stream"
|
|
6
6
|
import type { Path } from "path-parser"
|
|
7
7
|
import qs from "query-string"
|
|
8
8
|
import type * as Effect from "../Effect.js"
|
|
@@ -48,9 +48,14 @@ export function makePathWithBody(
|
|
|
48
48
|
return path.build(pars, { ignoreSearch: true, ignoreConstraints: true })
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export type Requests
|
|
51
|
+
export type Requests = RequestsAny
|
|
52
52
|
export type RequestsAny = Record<string, any>
|
|
53
53
|
|
|
54
|
+
export type ExtractModuleName<M extends RequestsAny> =
|
|
55
|
+
{ [K in keyof M]: M[K] extends { moduleName: infer N extends string } ? N : never }[keyof M] extends
|
|
56
|
+
infer R extends string ? R
|
|
57
|
+
: string
|
|
58
|
+
|
|
54
59
|
export type Client<M extends RequestsAny, ModuleName extends string> = RequestHandlers<
|
|
55
60
|
never,
|
|
56
61
|
never,
|
|
@@ -58,56 +63,122 @@ export type Client<M extends RequestsAny, ModuleName extends string> = RequestHa
|
|
|
58
63
|
ModuleName
|
|
59
64
|
>
|
|
60
65
|
|
|
61
|
-
export type ExtractResponse<T> = T extends S.Codec<any> ?
|
|
66
|
+
export type ExtractResponse<T> = T extends S.Codec<any> ? T["Type"]
|
|
62
67
|
: T extends unknown ? void
|
|
63
68
|
: never
|
|
64
69
|
|
|
65
|
-
export type ExtractEResponse<T> = T extends S.Codec<any> ?
|
|
70
|
+
export type ExtractEResponse<T> = T extends S.Codec<any> ? T["Encoded"]
|
|
66
71
|
: T extends unknown ? void
|
|
67
72
|
: never
|
|
68
73
|
|
|
69
|
-
type IsEmpty<T> = keyof T extends never ? true
|
|
70
|
-
: false
|
|
71
|
-
|
|
72
|
-
// v4: Request.RequestTypeId, S.symbolSerializable, S.symbolWithResult removed — use keyof Request to filter internal props
|
|
73
|
-
type Cruft = "_tag" | keyof Request.Request<any, any, any>
|
|
74
|
-
|
|
75
74
|
export interface ClientForOptions {
|
|
76
75
|
readonly skipQueryKey?: readonly string[]
|
|
76
|
+
/**
|
|
77
|
+
* Middleware tag to attach to every rpc on the client. Schema-only — the
|
|
78
|
+
* client never invokes the middleware (no Live impl required), but its
|
|
79
|
+
* declared `error` schema joins the rpc failure union via
|
|
80
|
+
* `Rpc.exitSchema`'s `rpc.middlewares[*].error` walk. Required when
|
|
81
|
+
* middleware can throw errors that aren't part of the resource's declared
|
|
82
|
+
* error union (e.g. auth middleware throwing `NotLoggedInError`); without
|
|
83
|
+
* it the client decode would fail with a `SchemaError` for stream rpcs.
|
|
84
|
+
*/
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
// $Project/$Configuration.Index
|
|
88
|
+
// -> "$Project", "$Configuration", "Index"
|
|
89
|
+
export const makeQueryKey = ({ id, options }: { id: string; options?: ClientForOptions }) =>
|
|
90
|
+
id
|
|
91
|
+
.split("/")
|
|
92
|
+
.filter((segment: string) => !options || !options.skipQueryKey?.includes(segment))
|
|
93
|
+
.map((segment: string) => "$" + segment)
|
|
94
|
+
.join(".")
|
|
95
|
+
.split(".")
|
|
96
|
+
|
|
97
|
+
export interface RequestHandlerWithInput<I, A, E, R, Request extends Req, Id extends string> {
|
|
98
|
+
handler: (i: I) => Effect.Effect<A, E, R>
|
|
81
99
|
id: Id
|
|
82
100
|
options?: ClientForOptions
|
|
83
101
|
Request: Request
|
|
84
102
|
}
|
|
85
103
|
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
/** Type alias: a no-input handler is simply `RequestHandlerWithInput<void, …>`. */
|
|
105
|
+
export type RequestHandler<A, E, R, Request extends Req, Id extends string> = RequestHandlerWithInput<
|
|
106
|
+
void,
|
|
107
|
+
A,
|
|
108
|
+
E,
|
|
109
|
+
R,
|
|
110
|
+
Request,
|
|
111
|
+
Id
|
|
112
|
+
>
|
|
113
|
+
|
|
114
|
+
export interface RequestStreamHandlerWithInput<I, A, E, R, Request extends Req, Id extends string, Final = A> {
|
|
115
|
+
handler: (i: I) => Stream.Stream<A, E, R>
|
|
88
116
|
id: Id
|
|
89
117
|
options?: ClientForOptions
|
|
90
118
|
Request: Request
|
|
119
|
+
/**
|
|
120
|
+
* Phantom type property (never set at runtime) that carries the `Final` type to
|
|
121
|
+
* `StreamMutationWithExtensions`. The tilde prefix follows the Effect convention for
|
|
122
|
+
* phantom/virtual properties and prevents accidental runtime access.
|
|
123
|
+
* Stream failures bubble through the execute effect's typed error channel `E`;
|
|
124
|
+
* the reactive `AsyncResult` ref also mirrors the failure for live progress UI.
|
|
125
|
+
*/
|
|
126
|
+
readonly "~final"?: Final
|
|
91
127
|
}
|
|
92
128
|
|
|
129
|
+
/** Type alias: a no-input stream handler is simply `RequestStreamHandlerWithInput<void, …>`. */
|
|
130
|
+
export type RequestStreamHandler<A, E, R, Request extends Req, Id extends string, Final = A> =
|
|
131
|
+
RequestStreamHandlerWithInput<void, A, E, R, Request, Id, Final>
|
|
132
|
+
|
|
93
133
|
// make sure this is exported or d.ts of apiClientFactory breaks?!
|
|
94
|
-
type
|
|
134
|
+
export type RequestInputFromMake<I extends { readonly make: (...args: any[]) => any }> = Parameters<I["make"]> extends
|
|
135
|
+
[] ? void : Parameters<I["make"]>[0]
|
|
136
|
+
|
|
137
|
+
// Has no input only when the request schema declares no payload fields (the auto-added
|
|
138
|
+
// `_tag` field is ignored). Any payload fields (even all-optional) produce a function handler.
|
|
139
|
+
type HasNoFields<I> = I extends { readonly fields: infer F extends S.Struct.Fields }
|
|
140
|
+
? [Exclude<keyof F, "_tag">] extends [never] ? true : false
|
|
141
|
+
: false
|
|
142
|
+
|
|
143
|
+
type RequestInput<I extends { readonly make: (...args: any[]) => any }> = Parameters<I["make"]>[0]
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Caller-facing input type for a request. `void` when the request schema has no fields;
|
|
147
|
+
* otherwise `make`'s first param type.
|
|
148
|
+
*/
|
|
149
|
+
export type HandlerInput<I extends { readonly make: (...args: any[]) => any }> = HasNoFields<I> extends true ? void
|
|
150
|
+
: RequestInput<I>
|
|
151
|
+
|
|
152
|
+
/** Extracts the final-value type from a stream request. Defaults to the success type when no `final` schema is set. */
|
|
153
|
+
type FinalTypeOf<T extends Req> = T extends { readonly final: infer F extends S.Top } ? F["Type"]
|
|
154
|
+
: T["success"]["Type"]
|
|
155
|
+
|
|
156
|
+
// `T["success"]` / `T["error"]` are constrained to `S.Top` via `Req`, so we
|
|
157
|
+
// can read `["DecodingServices"]` directly. Avoids the conditional in
|
|
158
|
+
// `S.Codec.DecodingServices<X> = X extends Top ? X["DecodingServices"] : never`,
|
|
159
|
+
// which tsgo (native) fails to reduce in this generic position and leaves as
|
|
160
|
+
// `unknown`, polluting the `R` channel of every client handler.
|
|
161
|
+
type RequestHandlerFor<R, E, T extends Req, Id extends string> = T["stream"] extends true
|
|
162
|
+
? RequestStreamHandlerWithInput<
|
|
163
|
+
HandlerInput<T>,
|
|
164
|
+
T["success"]["Type"],
|
|
165
|
+
T["error"]["Type"] | E,
|
|
166
|
+
R | T["success"]["DecodingServices"] | T["error"]["DecodingServices"],
|
|
167
|
+
T,
|
|
168
|
+
Id,
|
|
169
|
+
FinalTypeOf<T>
|
|
170
|
+
>
|
|
171
|
+
: RequestHandlerWithInput<
|
|
172
|
+
HandlerInput<T>,
|
|
173
|
+
T["success"]["Type"],
|
|
174
|
+
T["error"]["Type"] | E,
|
|
175
|
+
R | T["success"]["DecodingServices"] | T["error"]["DecodingServices"],
|
|
176
|
+
T,
|
|
177
|
+
Id
|
|
178
|
+
>
|
|
95
179
|
|
|
96
180
|
export type RequestHandlers<R, E, M extends RequestsAny, ModuleName extends string> = {
|
|
97
|
-
[K in keyof M as M[K] extends Req ? K : never]:
|
|
98
|
-
?
|
|
99
|
-
|
|
100
|
-
S.Schema.Type<M[K]["error"]> | E,
|
|
101
|
-
R | ReqDecodingServices<M[K]>,
|
|
102
|
-
M[K],
|
|
103
|
-
`${ModuleName}.${K & string}`
|
|
104
|
-
>
|
|
105
|
-
: RequestHandlerWithInput<
|
|
106
|
-
Omit<S.Schema.Type<M[K]>, Cruft>,
|
|
107
|
-
S.Schema.Type<M[K]["success"]>,
|
|
108
|
-
S.Schema.Type<M[K]["error"]> | E,
|
|
109
|
-
R | ReqDecodingServices<M[K]>,
|
|
110
|
-
M[K],
|
|
111
|
-
`${ModuleName}.${K & string}`
|
|
112
|
-
>
|
|
181
|
+
[K in keyof M as M[K] extends Req ? K : never]: Extract<M[K], Req> extends infer T extends Req
|
|
182
|
+
? RequestHandlerFor<R, E, T, `${ModuleName}.${K & string}`>
|
|
183
|
+
: never
|
|
113
184
|
}
|