effect-app 4.0.0-beta.18 → 4.0.0-beta.180
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 +760 -0
- package/dist/Array.d.ts +1 -1
- package/dist/Chunk.d.ts +1 -1
- package/dist/Chunk.d.ts.map +1 -1
- package/dist/Config/SecretURL.d.ts +1 -1
- package/dist/Config/SecretURL.d.ts.map +1 -1
- package/dist/Config/SecretURL.js +2 -2
- package/dist/Config/internal/configSecretURL.d.ts +1 -1
- package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
- 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 +40 -0
- package/dist/Context.d.ts.map +1 -0
- package/dist/Context.js +67 -0
- package/dist/Effect.d.ts +9 -10
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +3 -6
- 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 +6 -5
- package/dist/Layer.d.ts.map +1 -1
- package/dist/Layer.js +1 -1
- package/dist/NonEmptySet.d.ts +1 -1
- package/dist/NonEmptySet.d.ts.map +1 -1
- package/dist/Operations.d.ts +369 -47
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Operations.js +10 -10
- package/dist/Option.d.ts +1 -1
- package/dist/Option.d.ts.map +1 -1
- package/dist/Pure.d.ts +5 -5
- package/dist/Pure.d.ts.map +1 -1
- package/dist/Pure.js +13 -13
- package/dist/Schema/Class.d.ts +69 -20
- package/dist/Schema/Class.d.ts.map +1 -1
- package/dist/Schema/Class.js +190 -22
- 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 +33 -0
- package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
- package/dist/Schema/SpecialJsonSchema.js +122 -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 +7 -2
- package/dist/Schema/brand.d.ts.map +1 -1
- package/dist/Schema/brand.js +1 -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 +118 -45
- package/dist/Schema/ext.d.ts.map +1 -1
- package/dist/Schema/ext.js +129 -53
- package/dist/Schema/moreStrings.d.ts +111 -11
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +14 -15
- package/dist/Schema/numbers.d.ts +127 -15
- package/dist/Schema/numbers.d.ts.map +1 -1
- package/dist/Schema/numbers.js +10 -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 +37 -5
- package/dist/Schema/strings.d.ts.map +1 -1
- package/dist/Schema/strings.js +1 -5
- package/dist/Schema.d.ts +102 -56
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +128 -64
- package/dist/Set.d.ts +1 -1
- package/dist/Set.d.ts.map +1 -1
- 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 +1 -1
- package/dist/_ext/Array.d.ts.map +1 -1
- package/dist/_ext/date.d.ts +1 -1
- package/dist/_ext/misc.d.ts +1 -1
- package/dist/_ext/ord.ext.d.ts +1 -1
- package/dist/_ext/ord.ext.d.ts.map +1 -1
- 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 +17 -31
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +81 -26
- package/dist/client/clientFor.d.ts +63 -10
- 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 +360 -30
- package/dist/client/makeClient.d.ts.map +1 -1
- package/dist/client/makeClient.js +63 -23
- package/dist/client.d.ts +2 -1
- 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 +5 -5
- package/dist/http/internal/lib.d.ts +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +3 -2
- package/dist/index.d.ts +5 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -8
- package/dist/logger.d.ts +1 -1
- package/dist/middleware.d.ts +16 -9
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +13 -9
- package/dist/rpc/Invalidation.d.ts +490 -0
- package/dist/rpc/Invalidation.d.ts.map +1 -0
- package/dist/rpc/Invalidation.js +129 -0
- package/dist/rpc/MiddlewareMaker.d.ts +5 -4
- package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
- package/dist/rpc/MiddlewareMaker.js +26 -27
- package/dist/rpc/RpcContextMap.d.ts +3 -3
- package/dist/rpc/RpcContextMap.d.ts.map +1 -1
- package/dist/rpc/RpcContextMap.js +4 -4
- package/dist/rpc/RpcMiddleware.d.ts +5 -4
- 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/transform.d.ts +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +3 -3
- package/dist/utils/effectify.d.ts +1 -1
- package/dist/utils/extend.d.ts +1 -1
- package/dist/utils/extend.d.ts.map +1 -1
- package/dist/utils/gen.d.ts +2 -2
- package/dist/utils/gen.d.ts.map +1 -1
- package/dist/utils/logLevel.d.ts +2 -2
- package/dist/utils/logLevel.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +3 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +3 -3
- package/dist/utils.d.ts +30 -10
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -4
- 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/eslint.config.mjs +2 -2
- package/package.json +47 -19
- package/src/Config/SecretURL.ts +2 -1
- package/src/Config.ts +14 -0
- package/src/ConfigProvider.ts +48 -0
- package/src/{ServiceMap.ts → Context.ts} +52 -59
- package/src/Effect.ts +12 -14
- package/src/Layer.ts +5 -4
- package/src/Operations.ts +14 -14
- package/src/Pure.ts +17 -18
- package/src/Schema/Class.ts +279 -62
- package/src/Schema/SchemaParser.ts +12 -0
- package/src/Schema/SpecialJsonSchema.ts +137 -0
- package/src/Schema/SpecialOpenApi.ts +130 -0
- package/src/Schema/brand.ts +9 -1
- package/src/Schema/email.ts +7 -2
- package/src/Schema/ext.ts +210 -80
- package/src/Schema/moreStrings.ts +22 -20
- package/src/Schema/numbers.ts +14 -16
- package/src/Schema/phoneNumber.ts +5 -1
- package/src/Schema/strings.ts +4 -8
- package/src/Schema.ts +265 -105
- package/src/client/InvalidationKeys.ts +50 -0
- package/src/client/apiClientFactory.ts +203 -119
- package/src/client/clientFor.ts +112 -23
- package/src/client/errors.ts +52 -26
- package/src/client/makeClient.ts +339 -63
- package/src/client.ts +1 -0
- package/src/http/Request.ts +7 -4
- package/src/ids.ts +2 -1
- package/src/index.ts +5 -10
- package/src/middleware.ts +12 -10
- package/src/rpc/Invalidation.ts +174 -0
- package/src/rpc/MiddlewareMaker.ts +36 -47
- package/src/rpc/README.md +2 -2
- package/src/rpc/RpcContextMap.ts +6 -5
- package/src/rpc/RpcMiddleware.ts +5 -4
- package/src/rpc.ts +1 -1
- package/src/transform.ts +2 -2
- package/src/utils/gen.ts +1 -1
- package/src/utils/logger.ts +2 -2
- package/src/utils.ts +47 -11
- 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/rpc.test.ts +38 -6
- package/test/schema.test.ts +591 -17
- package/test/secretURL.test.ts +157 -0
- package/test/special.test.ts +1023 -0
- package/test/utils.test.ts +6 -6
- package/tsconfig.base.json +3 -4
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +29 -29
- package/tsconfig.test.json +2 -2
- package/dist/ServiceMap.d.ts +0 -44
- package/dist/ServiceMap.d.ts.map +0 -1
- package/dist/ServiceMap.js +0 -91
package/src/client/errors.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/** @effect-diagnostics overriddenSchemaConstructor:skip-file */
|
|
2
|
-
import {
|
|
2
|
+
import { TaggedErrorClass } from "effect-app/Schema"
|
|
3
3
|
import * as Cause from "effect/Cause"
|
|
4
4
|
import * as S from "../Schema.js"
|
|
5
5
|
|
|
6
|
-
export const tryToJson = (error:
|
|
6
|
+
export const tryToJson = (error: unknown) => {
|
|
7
7
|
try {
|
|
8
|
-
|
|
8
|
+
const errorJson = (error as any).toJSON()
|
|
9
|
+
return errorJson && typeof errorJson === "object" ? errorJson as Record<string, unknown> : { error }
|
|
9
10
|
} catch {
|
|
10
11
|
try {
|
|
11
|
-
return error.toString()
|
|
12
|
+
return { error: (error as any).toString() }
|
|
12
13
|
} catch (err) {
|
|
13
14
|
try {
|
|
14
|
-
return `Failed to convert error: ${err}`
|
|
15
|
+
return { error: `Failed to convert error: ${err}` }
|
|
15
16
|
} catch {
|
|
16
|
-
return `Failed to convert error: unknown failure`
|
|
17
|
+
return { error: `Failed to convert error: unknown failure` }
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
}
|
|
@@ -21,7 +22,7 @@ export const tryToJson = (error: { toJSON(): unknown; toString(): string }) => {
|
|
|
21
22
|
|
|
22
23
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
23
24
|
// @ts-expect-error type not used
|
|
24
|
-
export class NotFoundError<ItemType = string> extends
|
|
25
|
+
export class NotFoundError<ItemType = string> extends TaggedErrorClass<NotFoundError<ItemType>>()("NotFoundError", {
|
|
25
26
|
type: S.String,
|
|
26
27
|
id: S.Unknown
|
|
27
28
|
}) {
|
|
@@ -29,76 +30,97 @@ export class NotFoundError<ItemType = string> extends TaggedError<NotFoundError<
|
|
|
29
30
|
props: { type: string; id: unknown; cause?: unknown },
|
|
30
31
|
disableValidation?: boolean
|
|
31
32
|
) {
|
|
32
|
-
super(props
|
|
33
|
+
super(props, disableValidation as any)
|
|
33
34
|
}
|
|
34
35
|
override get message() {
|
|
35
36
|
return `Didn't find ${(this as any).type}#${JSON.stringify((this as any).id)}`
|
|
36
37
|
}
|
|
38
|
+
override toString() {
|
|
39
|
+
return `NotFoundError: ${this.message}`
|
|
40
|
+
}
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
const messageFallback = (messageOrObject?: string | { message: string }) =>
|
|
40
44
|
typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject ?? "" }
|
|
41
45
|
|
|
42
|
-
export class InvalidStateError extends
|
|
46
|
+
export class InvalidStateError extends TaggedErrorClass<InvalidStateError>()("InvalidStateError", {
|
|
43
47
|
message: S.String
|
|
44
48
|
}) {
|
|
45
49
|
constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
|
|
46
50
|
super(
|
|
47
|
-
typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject }
|
|
51
|
+
typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject },
|
|
48
52
|
disableValidation as any
|
|
49
53
|
)
|
|
50
54
|
}
|
|
55
|
+
override toString() {
|
|
56
|
+
return `InvalidStateError: ${this.message}`
|
|
57
|
+
}
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
export class ServiceUnavailableError extends
|
|
60
|
+
export class ServiceUnavailableError extends TaggedErrorClass<ServiceUnavailableError>()("ServiceUnavailableError", {
|
|
54
61
|
message: S.String
|
|
55
62
|
}) {
|
|
56
63
|
constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
|
|
57
64
|
super(
|
|
58
|
-
typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject }
|
|
65
|
+
typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject },
|
|
59
66
|
disableValidation as any
|
|
60
67
|
)
|
|
61
68
|
}
|
|
69
|
+
override toString() {
|
|
70
|
+
return `ServiceUnavailableError: ${this.message}`
|
|
71
|
+
}
|
|
62
72
|
}
|
|
63
73
|
|
|
64
|
-
export class ValidationError extends
|
|
74
|
+
export class ValidationError extends TaggedErrorClass<ValidationError>()("ValidationError", {
|
|
65
75
|
errors: S.Array(S.Unknown)
|
|
66
76
|
}) {
|
|
67
77
|
constructor(
|
|
68
78
|
props: { errors: ReadonlyArray<unknown>; cause?: unknown },
|
|
69
79
|
disableValidation?: boolean
|
|
70
80
|
) {
|
|
71
|
-
super(props
|
|
81
|
+
super(props, disableValidation as any)
|
|
72
82
|
}
|
|
73
83
|
override get message() {
|
|
74
84
|
return `Validation failed: ${(this as any).errors.map((e: any) => JSON.stringify(e, undefined, 2)).join(",\n")}`
|
|
75
85
|
}
|
|
86
|
+
override toString() {
|
|
87
|
+
return `ValidationError: ${this.message}`
|
|
88
|
+
}
|
|
76
89
|
}
|
|
77
90
|
|
|
78
|
-
export class NotLoggedInError extends
|
|
91
|
+
export class NotLoggedInError extends TaggedErrorClass<NotLoggedInError>()("NotLoggedInError", {
|
|
79
92
|
message: S.String
|
|
80
93
|
}) {
|
|
81
94
|
constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
|
|
82
|
-
super(messageFallback(messageOrObject)
|
|
95
|
+
super(messageFallback(messageOrObject), disableValidation as any)
|
|
96
|
+
}
|
|
97
|
+
override toString() {
|
|
98
|
+
return `NotLoggedInError: ${this.message}`
|
|
83
99
|
}
|
|
84
100
|
}
|
|
85
101
|
|
|
86
102
|
/**
|
|
87
103
|
* The user carries a valid Userprofile, but there is a problem with the login none the less.
|
|
88
104
|
*/
|
|
89
|
-
export class LoginError extends
|
|
105
|
+
export class LoginError extends TaggedErrorClass<LoginError>()("NotLoggedInError", {
|
|
90
106
|
message: S.String
|
|
91
107
|
}) {
|
|
92
108
|
constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
|
|
93
|
-
super(messageFallback(messageOrObject)
|
|
109
|
+
super(messageFallback(messageOrObject), disableValidation as any)
|
|
110
|
+
}
|
|
111
|
+
override toString() {
|
|
112
|
+
return `LoginError: ${this.message}`
|
|
94
113
|
}
|
|
95
114
|
}
|
|
96
115
|
|
|
97
|
-
export class UnauthorizedError extends
|
|
116
|
+
export class UnauthorizedError extends TaggedErrorClass<UnauthorizedError>()("UnauthorizedError", {
|
|
98
117
|
message: S.String
|
|
99
118
|
}) {
|
|
100
119
|
constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
|
|
101
|
-
super(messageFallback(messageOrObject)
|
|
120
|
+
super(messageFallback(messageOrObject), disableValidation as any)
|
|
121
|
+
}
|
|
122
|
+
override toString() {
|
|
123
|
+
return `UnauthorizedError: ${this.message}`
|
|
102
124
|
}
|
|
103
125
|
}
|
|
104
126
|
|
|
@@ -110,7 +132,7 @@ type OptimisticConcurrencyDetails = {
|
|
|
110
132
|
readonly found?: string | undefined
|
|
111
133
|
}
|
|
112
134
|
|
|
113
|
-
export class OptimisticConcurrencyException extends
|
|
135
|
+
export class OptimisticConcurrencyException extends TaggedErrorClass<OptimisticConcurrencyException>()(
|
|
114
136
|
"OptimisticConcurrencyException",
|
|
115
137
|
{ message: S.String }
|
|
116
138
|
) {
|
|
@@ -123,13 +145,16 @@ export class OptimisticConcurrencyException extends TaggedError<OptimisticConcur
|
|
|
123
145
|
disableValidation?: boolean
|
|
124
146
|
) {
|
|
125
147
|
super(
|
|
126
|
-
"message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` }
|
|
148
|
+
"message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` },
|
|
127
149
|
disableValidation as any
|
|
128
150
|
)
|
|
129
151
|
if (!("message" in args)) {
|
|
130
152
|
this.details = args
|
|
131
153
|
}
|
|
132
154
|
}
|
|
155
|
+
override toString() {
|
|
156
|
+
return `OptimisticConcurrencyException: ${this.message}`
|
|
157
|
+
}
|
|
133
158
|
}
|
|
134
159
|
|
|
135
160
|
const MutationOnlyErrors = [
|
|
@@ -183,6 +208,7 @@ export class CauseException<E> extends Error {
|
|
|
183
208
|
Error.stackTraceLimit = 0
|
|
184
209
|
super()
|
|
185
210
|
Error.stackTraceLimit = limit
|
|
211
|
+
this.cause = Cause.squash(originalCause)
|
|
186
212
|
// v4: makeFiberFailure removed — use Cause.prettyErrors instead
|
|
187
213
|
const errors = Cause.prettyErrors(originalCause)
|
|
188
214
|
const first = errors[0]
|
|
@@ -222,17 +248,17 @@ export class CauseException<E> extends Error {
|
|
|
222
248
|
}
|
|
223
249
|
}
|
|
224
250
|
|
|
225
|
-
export const tryToReport = (error: { toReport(): unknown
|
|
251
|
+
export const tryToReport = (error: { toReport(): Record<string, unknown>; toString(): string }) => {
|
|
226
252
|
try {
|
|
227
253
|
return error.toReport()
|
|
228
254
|
} catch {
|
|
229
255
|
try {
|
|
230
|
-
return error.toString()
|
|
256
|
+
return { error: error.toString() }
|
|
231
257
|
} catch (err) {
|
|
232
258
|
try {
|
|
233
|
-
return `Failed to convert error: ${err}`
|
|
259
|
+
return { error: `Failed to convert error: ${err}` }
|
|
234
260
|
} catch {
|
|
235
|
-
return `Failed to convert error: unknown failure`
|
|
261
|
+
return { error: `Failed to convert error: unknown failure` }
|
|
236
262
|
}
|
|
237
263
|
}
|
|
238
264
|
}
|
package/src/client/makeClient.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SchemaTransformation } from "effect"
|
|
2
|
+
import type * as Exit from "effect/Exit"
|
|
1
3
|
import { type GetContextConfig, type GetEffectError, type RequestContextMapTagAny } from "../rpc/RpcContextMap.js"
|
|
2
4
|
import * as S from "../Schema.js"
|
|
3
5
|
import { AST } from "../Schema.js"
|
|
@@ -8,36 +10,111 @@ const merge = (a: any, b: Array<any>) =>
|
|
|
8
10
|
/**
|
|
9
11
|
* Whatever the input, we will only decode or encode to void
|
|
10
12
|
*/
|
|
11
|
-
const ForceVoid
|
|
13
|
+
export const ForceVoid = S
|
|
14
|
+
.declare((_: unknown): _ is unknown => true)
|
|
15
|
+
.pipe(
|
|
16
|
+
S.decodeTo(S.Any, SchemaTransformation.transform<unknown, unknown>({ decode: () => void 0, encode: () => void 0 }))
|
|
17
|
+
)
|
|
12
18
|
|
|
13
19
|
type SchemaOrFields<T> = T extends S.Top ? T : T extends S.Struct.Fields ? S.Struct<T> : S.Void
|
|
14
20
|
|
|
15
|
-
type
|
|
21
|
+
type TaggedRequestSchema<Tag extends string, Payload extends S.Struct.Fields> = S.Struct<
|
|
22
|
+
{ readonly _tag: S.tag<Tag> } & Payload
|
|
23
|
+
>
|
|
24
|
+
|
|
25
|
+
type QueryOnlyRequests<Resource> = {
|
|
26
|
+
[K in keyof Resource as Resource[K] extends { readonly type: "query" } ? K : never]: Resource[K]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type QueryOnlyResources<Resources> = {
|
|
30
|
+
[K in keyof Resources]: QueryOnlyRequests<Resources[K]>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type InputFromPayload<Payload extends S.Struct.Fields> = keyof Payload extends never ? void
|
|
34
|
+
: S.Schema.Type<S.Struct<Payload>>
|
|
35
|
+
|
|
36
|
+
type OutputFromSuccess<Success extends S.Top> = Success extends typeof ForceVoid ? void : S.Schema.Type<Success>
|
|
37
|
+
|
|
38
|
+
type InvalidationResources = Record<string, Record<string, unknown>>
|
|
39
|
+
|
|
40
|
+
export type InvalidateQueryInstruction = {
|
|
41
|
+
readonly filters?: Record<string, unknown>
|
|
42
|
+
readonly options?: Record<string, unknown>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type InvalidationCallback<Resources, Input = unknown, Success = unknown, Failure = unknown> = (
|
|
46
|
+
queryKey: readonly string[],
|
|
47
|
+
resources: QueryOnlyResources<Resources>,
|
|
48
|
+
...args: [Input] extends [void] ? [exit: Exit.Exit<Success, Failure>]
|
|
49
|
+
: [input: Input, exit: Exit.Exit<Success, Failure>]
|
|
50
|
+
) => ReadonlyArray<InvalidateQueryInstruction>
|
|
51
|
+
|
|
52
|
+
export type InvalidationConfig<Resources, Input = unknown, Success = unknown, Failure = unknown> = {
|
|
53
|
+
readonly invalidatesQueries: InvalidationCallback<Resources, Input, Success, Failure>
|
|
54
|
+
readonly invalidationResources?: Resources
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type InvalidationConfigForCommand<
|
|
58
|
+
Resources,
|
|
59
|
+
Payload extends S.Struct.Fields,
|
|
60
|
+
Success extends S.Top,
|
|
61
|
+
Error extends S.Top
|
|
62
|
+
> = InvalidationConfig<
|
|
63
|
+
Resources,
|
|
64
|
+
InputFromPayload<Payload>,
|
|
65
|
+
OutputFromSuccess<Success>,
|
|
66
|
+
S.Schema.Type<Error>
|
|
67
|
+
>
|
|
68
|
+
|
|
69
|
+
export const configureInvalidation = <Resources>() =>
|
|
70
|
+
<Input, Success, Failure>(
|
|
71
|
+
invalidatesQueries: InvalidationCallback<Resources, NoInfer<Input>, NoInfer<Success>, NoInfer<Failure>>
|
|
72
|
+
): InvalidationConfig<Resources, Input, Success, Failure> => ({ invalidatesQueries })
|
|
73
|
+
|
|
74
|
+
export const configureInvalidationCallback = <Resources>() =>
|
|
75
|
+
<Input, Success, Failure>(
|
|
76
|
+
invalidatesQueries: InvalidationCallback<Resources, NoInfer<Input>, NoInfer<Success>, NoInfer<Failure>>
|
|
77
|
+
): InvalidationCallback<Resources, Input, Success, Failure> => invalidatesQueries
|
|
78
|
+
|
|
79
|
+
export const configureInvalidationResources = <Resources>() =>
|
|
80
|
+
({}) as Pick<InvalidationConfig<Resources>, "invalidationResources">
|
|
81
|
+
|
|
82
|
+
type TaggedRequestForResult<
|
|
83
|
+
Self,
|
|
16
84
|
Tag extends string,
|
|
17
85
|
Payload extends S.Struct.Fields,
|
|
18
86
|
Success extends S.Top,
|
|
19
87
|
Error extends S.Top,
|
|
20
|
-
Config
|
|
88
|
+
Config,
|
|
89
|
+
ModuleName extends string,
|
|
90
|
+
Type extends "command" | "query" | "stream",
|
|
91
|
+
Resources = never,
|
|
92
|
+
Final extends S.Top = never
|
|
21
93
|
> =
|
|
22
|
-
& S.
|
|
94
|
+
& S.EnhancedClass<Self, TaggedRequestSchema<Tag, Payload>, {}>
|
|
23
95
|
& {
|
|
24
|
-
new(...args: any[]): any
|
|
25
96
|
readonly _tag: Tag
|
|
26
|
-
readonly fields: { readonly _tag: S.tag<Tag> } & Payload
|
|
27
97
|
readonly success: Success
|
|
28
98
|
readonly error: Error
|
|
29
99
|
readonly config: Config
|
|
30
100
|
readonly "~decodingServices": S.Codec.DecodingServices<Success> | S.Codec.DecodingServices<Error>
|
|
101
|
+
readonly "~encodingServices": S.Codec.EncodingServices<Success> | S.Codec.EncodingServices<Error>
|
|
102
|
+
readonly id: `${ModuleName}.${Tag}`
|
|
103
|
+
readonly moduleName: ModuleName
|
|
104
|
+
readonly type: Type
|
|
105
|
+
readonly "~invalidationResources"?: Resources
|
|
31
106
|
}
|
|
107
|
+
& ([Final] extends [never] ? {} : { readonly final: Final })
|
|
32
108
|
|
|
33
109
|
export const makeRpcClient = <
|
|
34
110
|
RequestContextMap extends RequestContextMapTagAny,
|
|
35
111
|
GeneralErrors extends S.Top = never
|
|
36
112
|
>(rcs: RequestContextMap, generalErrors?: GeneralErrors) => {
|
|
37
|
-
// Long way around
|
|
113
|
+
// Long way around Context/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??)
|
|
38
114
|
type ServiceMap = {
|
|
39
115
|
success: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
|
|
40
116
|
error: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
|
|
117
|
+
final?: S.Top | S.Struct.Fields // optional final-value schema for stream requests
|
|
41
118
|
}
|
|
42
119
|
|
|
43
120
|
type RequestConfig = GetContextConfig<RequestContextMap["config"]>
|
|
@@ -47,64 +124,263 @@ export const makeRpcClient = <
|
|
|
47
124
|
: [GeneralErrors] extends [never] ? GetEffectError<RequestContextMap["config"], C>
|
|
48
125
|
: MergeError<GetEffectError<RequestContextMap["config"], C>>
|
|
49
126
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
config:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
127
|
+
// TODO: filter errors based on config + take care of inversion
|
|
128
|
+
const errorSchemas = Object.values(rcs.config).map((_) => _.error)
|
|
129
|
+
|
|
130
|
+
function makeRequestClass<Tag extends string, Fields extends S.Struct.Fields, C extends Partial<ServiceMap>>(
|
|
131
|
+
tag: Tag,
|
|
132
|
+
fields: Fields,
|
|
133
|
+
config?: C
|
|
134
|
+
) {
|
|
135
|
+
const failureSchema = merge(
|
|
136
|
+
config?.error ? S.isSchema(config.error) ? config.error : S.Struct(config.error) : undefined,
|
|
137
|
+
[...errorSchemas, generalErrors].filter(Boolean)
|
|
138
|
+
)
|
|
139
|
+
const successSchema = config?.success
|
|
140
|
+
? S.isSchema(config.success)
|
|
141
|
+
? AST.isVoid(config.success.ast) ? ForceVoid : config.success
|
|
142
|
+
: S.Struct(config.success)
|
|
143
|
+
: ForceVoid
|
|
144
|
+
|
|
145
|
+
const finalConfig = (config as any)?.final
|
|
146
|
+
const finalSchema = finalConfig && S.isSchema(finalConfig) ? finalConfig : undefined
|
|
147
|
+
|
|
148
|
+
const RequestClass = S.TaggedClass<any>()(tag, fields)
|
|
149
|
+
Object.assign(RequestClass, {
|
|
150
|
+
_tag: tag,
|
|
151
|
+
success: successSchema,
|
|
152
|
+
error: failureSchema,
|
|
153
|
+
...(finalSchema !== undefined ? { final: finalSchema } : {}),
|
|
154
|
+
config
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
return RequestClass
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function makeTaggedRequestWithMeta<ModuleName extends string, Type extends "command" | "query" | "stream">(
|
|
161
|
+
moduleName: ModuleName,
|
|
162
|
+
type: Type
|
|
163
|
+
) {
|
|
164
|
+
function TaggedRequestWithMeta<Self, Resources extends InvalidationResources = never>(): {
|
|
165
|
+
<
|
|
166
|
+
Tag extends string,
|
|
167
|
+
Payload extends S.Struct.Fields,
|
|
168
|
+
Success extends S.Top | S.Struct.Fields,
|
|
169
|
+
Error extends S.Top | S.Struct.Fields,
|
|
170
|
+
Final extends S.Top | S.Struct.Fields = never,
|
|
171
|
+
C extends RequestConfig & Record<string, any> = RequestConfig & Record<string, any>
|
|
172
|
+
>(
|
|
173
|
+
tag: Tag,
|
|
174
|
+
fields: Payload,
|
|
175
|
+
config:
|
|
176
|
+
& Omit<C, "invalidatesQueries">
|
|
177
|
+
& { success: Success; error: Error; final?: Final },
|
|
178
|
+
invalidatesQueries?: InvalidationCallback<
|
|
179
|
+
Resources,
|
|
180
|
+
InputFromPayload<Payload>,
|
|
181
|
+
OutputFromSuccess<SchemaOrFields<Success>>,
|
|
182
|
+
S.Schema.Type<ErrorResult<C & { success: Success; error: Error }>>
|
|
183
|
+
>
|
|
184
|
+
): TaggedRequestForResult<
|
|
185
|
+
Self,
|
|
186
|
+
Tag,
|
|
187
|
+
Payload,
|
|
188
|
+
SchemaOrFields<Success>,
|
|
189
|
+
ErrorResult<C & { success: Success; error: Error }>,
|
|
190
|
+
Omit<
|
|
191
|
+
& Omit<C, "invalidatesQueries">
|
|
192
|
+
& {
|
|
193
|
+
success: Success
|
|
194
|
+
error: Error
|
|
195
|
+
}
|
|
196
|
+
& Partial<
|
|
197
|
+
InvalidationConfigForCommand<
|
|
198
|
+
Resources,
|
|
199
|
+
Payload,
|
|
200
|
+
SchemaOrFields<Success>,
|
|
201
|
+
ErrorResult<C & { success: Success; error: Error }>
|
|
202
|
+
>
|
|
203
|
+
>,
|
|
204
|
+
"success" | "error"
|
|
205
|
+
>,
|
|
206
|
+
ModuleName,
|
|
207
|
+
Type,
|
|
208
|
+
Resources,
|
|
209
|
+
[Final] extends [never] ? never : SchemaOrFields<Final>
|
|
210
|
+
>
|
|
211
|
+
<
|
|
212
|
+
Tag extends string,
|
|
213
|
+
Payload extends S.Struct.Fields,
|
|
214
|
+
Success extends S.Top | S.Struct.Fields,
|
|
215
|
+
Final extends S.Top | S.Struct.Fields = never,
|
|
216
|
+
C extends RequestConfig & Record<string, any> & { error?: never } = RequestConfig & Record<string, any> & {
|
|
217
|
+
error?: never
|
|
218
|
+
}
|
|
219
|
+
>(
|
|
220
|
+
tag: Tag,
|
|
221
|
+
fields: Payload,
|
|
222
|
+
config:
|
|
223
|
+
& Omit<C, "invalidatesQueries">
|
|
224
|
+
& { success: Success; final?: Final },
|
|
225
|
+
invalidatesQueries?: InvalidationCallback<
|
|
226
|
+
Resources,
|
|
227
|
+
InputFromPayload<Payload>,
|
|
228
|
+
OutputFromSuccess<SchemaOrFields<Success>>,
|
|
229
|
+
S.Schema.Type<ErrorResult<C & { success: Success }>>
|
|
230
|
+
>
|
|
231
|
+
): TaggedRequestForResult<
|
|
232
|
+
Self,
|
|
233
|
+
Tag,
|
|
234
|
+
Payload,
|
|
235
|
+
SchemaOrFields<Success>,
|
|
236
|
+
ErrorResult<C & { success: Success }>,
|
|
237
|
+
Omit<
|
|
238
|
+
& Omit<C, "invalidatesQueries">
|
|
239
|
+
& {
|
|
240
|
+
success: Success
|
|
241
|
+
}
|
|
242
|
+
& Partial<
|
|
243
|
+
InvalidationConfigForCommand<
|
|
244
|
+
Resources,
|
|
245
|
+
Payload,
|
|
246
|
+
SchemaOrFields<Success>,
|
|
247
|
+
ErrorResult<C & { success: Success }>
|
|
248
|
+
>
|
|
249
|
+
>,
|
|
250
|
+
"success" | "error"
|
|
251
|
+
>,
|
|
252
|
+
ModuleName,
|
|
253
|
+
Type,
|
|
254
|
+
Resources,
|
|
255
|
+
[Final] extends [never] ? never : SchemaOrFields<Final>
|
|
256
|
+
>
|
|
257
|
+
<
|
|
258
|
+
Tag extends string,
|
|
259
|
+
Payload extends S.Struct.Fields,
|
|
260
|
+
Error extends S.Top | S.Struct.Fields,
|
|
261
|
+
C extends RequestConfig & Record<string, any> & { success?: never }
|
|
262
|
+
>(
|
|
263
|
+
tag: Tag,
|
|
264
|
+
fields: Payload,
|
|
265
|
+
config:
|
|
266
|
+
& Omit<C, "invalidatesQueries">
|
|
267
|
+
& { error: Error },
|
|
268
|
+
invalidatesQueries?: InvalidationCallback<
|
|
269
|
+
Resources,
|
|
270
|
+
InputFromPayload<Payload>,
|
|
271
|
+
void,
|
|
272
|
+
S.Schema.Type<ErrorResult<C & { error: Error }>>
|
|
273
|
+
>
|
|
274
|
+
): TaggedRequestForResult<
|
|
275
|
+
Self,
|
|
276
|
+
Tag,
|
|
277
|
+
Payload,
|
|
278
|
+
typeof ForceVoid,
|
|
279
|
+
ErrorResult<C & { error: Error }>,
|
|
280
|
+
Omit<
|
|
281
|
+
& Omit<C, "invalidatesQueries">
|
|
282
|
+
& {
|
|
283
|
+
error: Error
|
|
284
|
+
}
|
|
285
|
+
& Partial<
|
|
286
|
+
InvalidationConfigForCommand<
|
|
287
|
+
Resources,
|
|
288
|
+
Payload,
|
|
289
|
+
typeof ForceVoid,
|
|
290
|
+
ErrorResult<C & { error: Error }>
|
|
291
|
+
>
|
|
292
|
+
>,
|
|
293
|
+
"success" | "error"
|
|
294
|
+
>,
|
|
295
|
+
ModuleName,
|
|
296
|
+
Type,
|
|
297
|
+
Resources
|
|
298
|
+
>
|
|
299
|
+
<
|
|
300
|
+
Tag extends string,
|
|
301
|
+
Payload extends S.Struct.Fields,
|
|
302
|
+
C extends RequestConfig & Record<string, any> & { success?: never; error?: never }
|
|
303
|
+
>(
|
|
304
|
+
tag: Tag,
|
|
305
|
+
fields: Payload,
|
|
306
|
+
config: Omit<C, "invalidatesQueries">,
|
|
307
|
+
invalidatesQueries?: InvalidationCallback<
|
|
308
|
+
Resources,
|
|
309
|
+
InputFromPayload<Payload>,
|
|
310
|
+
void,
|
|
311
|
+
S.Schema.Type<ErrorResult<C>>
|
|
312
|
+
>
|
|
313
|
+
): TaggedRequestForResult<
|
|
314
|
+
Self,
|
|
315
|
+
Tag,
|
|
316
|
+
Payload,
|
|
317
|
+
typeof ForceVoid,
|
|
318
|
+
ErrorResult<C>,
|
|
319
|
+
Omit<
|
|
320
|
+
& Omit<C, "invalidatesQueries">
|
|
321
|
+
& Partial<InvalidationConfigForCommand<Resources, Payload, typeof ForceVoid, ErrorResult<C>>>,
|
|
322
|
+
"success" | "error"
|
|
323
|
+
>,
|
|
324
|
+
ModuleName,
|
|
325
|
+
Type,
|
|
326
|
+
Resources
|
|
327
|
+
>
|
|
328
|
+
<Tag extends string, Payload extends S.Struct.Fields>(
|
|
329
|
+
tag: Tag,
|
|
330
|
+
fields: Payload
|
|
331
|
+
): TaggedRequestForResult<
|
|
332
|
+
Self,
|
|
333
|
+
Tag,
|
|
334
|
+
Payload,
|
|
335
|
+
typeof ForceVoid,
|
|
336
|
+
ErrorResult<{}>,
|
|
337
|
+
Record<string, never>,
|
|
338
|
+
ModuleName,
|
|
339
|
+
Type
|
|
340
|
+
>
|
|
341
|
+
} {
|
|
342
|
+
return (<Tag extends string, Fields extends S.Struct.Fields, C extends ServiceMap>(
|
|
343
|
+
tag: Tag,
|
|
344
|
+
fields: Fields,
|
|
345
|
+
config?: C,
|
|
346
|
+
invalidatesQueries?: InvalidationCallback<Resources, unknown, unknown, unknown>
|
|
347
|
+
) => {
|
|
348
|
+
const requestConfig = invalidatesQueries === undefined ? config : { ...config, invalidatesQueries }
|
|
349
|
+
const cls = makeRequestClass(tag, fields, requestConfig)
|
|
350
|
+
Object.assign(cls, { id: `${moduleName}.${tag}`, moduleName, type })
|
|
351
|
+
return cls
|
|
352
|
+
}) as any
|
|
353
|
+
}
|
|
354
|
+
return Object.assign(TaggedRequestWithMeta, { moduleName, type } as const)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function TaggedRequestFor<ModuleName extends string>(moduleName: ModuleName) {
|
|
358
|
+
const Query = makeTaggedRequestWithMeta(moduleName, "query")
|
|
359
|
+
const Command = makeTaggedRequestWithMeta(moduleName, "command")
|
|
360
|
+
const Stream = makeTaggedRequestWithMeta(moduleName, "stream")
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
moduleName,
|
|
364
|
+
/**
|
|
365
|
+
* Create query request classes for this module.
|
|
366
|
+
* Queries read state and should not mutate server state.
|
|
367
|
+
*/
|
|
368
|
+
Query,
|
|
369
|
+
/**
|
|
370
|
+
* Create command request classes for this module.
|
|
371
|
+
* Commands mutate state and should avoid returning complex read models.
|
|
372
|
+
*/
|
|
373
|
+
Command,
|
|
374
|
+
/**
|
|
375
|
+
* Create stream request classes for this module.
|
|
376
|
+
* Streams produce a Stream of `success` values, may also fail with `error`.
|
|
377
|
+
* Handlers must return an `Effect`-compatible Stream rather than an Effect.
|
|
378
|
+
*/
|
|
379
|
+
Stream
|
|
380
|
+
} as const
|
|
105
381
|
}
|
|
106
382
|
|
|
107
383
|
return {
|
|
108
|
-
|
|
384
|
+
TaggedRequestFor
|
|
109
385
|
}
|
|
110
386
|
}
|