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.
Files changed (218) hide show
  1. package/CHANGELOG.md +760 -0
  2. package/dist/Array.d.ts +1 -1
  3. package/dist/Chunk.d.ts +1 -1
  4. package/dist/Chunk.d.ts.map +1 -1
  5. package/dist/Config/SecretURL.d.ts +1 -1
  6. package/dist/Config/SecretURL.d.ts.map +1 -1
  7. package/dist/Config/SecretURL.js +2 -2
  8. package/dist/Config/internal/configSecretURL.d.ts +1 -1
  9. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  10. package/dist/Config.d.ts +7 -0
  11. package/dist/Config.d.ts.map +1 -0
  12. package/dist/Config.js +6 -0
  13. package/dist/ConfigProvider.d.ts +39 -0
  14. package/dist/ConfigProvider.d.ts.map +1 -0
  15. package/dist/ConfigProvider.js +42 -0
  16. package/dist/Context.d.ts +40 -0
  17. package/dist/Context.d.ts.map +1 -0
  18. package/dist/Context.js +67 -0
  19. package/dist/Effect.d.ts +9 -10
  20. package/dist/Effect.d.ts.map +1 -1
  21. package/dist/Effect.js +3 -6
  22. package/dist/Function.d.ts +1 -1
  23. package/dist/Function.d.ts.map +1 -1
  24. package/dist/Inputify.type.d.ts +1 -1
  25. package/dist/Layer.d.ts +6 -5
  26. package/dist/Layer.d.ts.map +1 -1
  27. package/dist/Layer.js +1 -1
  28. package/dist/NonEmptySet.d.ts +1 -1
  29. package/dist/NonEmptySet.d.ts.map +1 -1
  30. package/dist/Operations.d.ts +369 -47
  31. package/dist/Operations.d.ts.map +1 -1
  32. package/dist/Operations.js +10 -10
  33. package/dist/Option.d.ts +1 -1
  34. package/dist/Option.d.ts.map +1 -1
  35. package/dist/Pure.d.ts +5 -5
  36. package/dist/Pure.d.ts.map +1 -1
  37. package/dist/Pure.js +13 -13
  38. package/dist/Schema/Class.d.ts +69 -20
  39. package/dist/Schema/Class.d.ts.map +1 -1
  40. package/dist/Schema/Class.js +190 -22
  41. package/dist/Schema/FastCheck.d.ts +1 -1
  42. package/dist/Schema/FastCheck.d.ts.map +1 -1
  43. package/dist/Schema/Methods.d.ts +1 -1
  44. package/dist/Schema/SchemaParser.d.ts +5 -0
  45. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  46. package/dist/Schema/SchemaParser.js +6 -0
  47. package/dist/Schema/SpecialJsonSchema.d.ts +33 -0
  48. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  49. package/dist/Schema/SpecialJsonSchema.js +122 -0
  50. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  51. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  52. package/dist/Schema/SpecialOpenApi.js +123 -0
  53. package/dist/Schema/brand.d.ts +7 -2
  54. package/dist/Schema/brand.d.ts.map +1 -1
  55. package/dist/Schema/brand.js +1 -1
  56. package/dist/Schema/email.d.ts +1 -1
  57. package/dist/Schema/email.d.ts.map +1 -1
  58. package/dist/Schema/email.js +7 -4
  59. package/dist/Schema/ext.d.ts +118 -45
  60. package/dist/Schema/ext.d.ts.map +1 -1
  61. package/dist/Schema/ext.js +129 -53
  62. package/dist/Schema/moreStrings.d.ts +111 -11
  63. package/dist/Schema/moreStrings.d.ts.map +1 -1
  64. package/dist/Schema/moreStrings.js +14 -15
  65. package/dist/Schema/numbers.d.ts +127 -15
  66. package/dist/Schema/numbers.d.ts.map +1 -1
  67. package/dist/Schema/numbers.js +10 -12
  68. package/dist/Schema/phoneNumber.d.ts +1 -1
  69. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  70. package/dist/Schema/phoneNumber.js +6 -3
  71. package/dist/Schema/schema.d.ts +1 -1
  72. package/dist/Schema/strings.d.ts +37 -5
  73. package/dist/Schema/strings.d.ts.map +1 -1
  74. package/dist/Schema/strings.js +1 -5
  75. package/dist/Schema.d.ts +102 -56
  76. package/dist/Schema.d.ts.map +1 -1
  77. package/dist/Schema.js +128 -64
  78. package/dist/Set.d.ts +1 -1
  79. package/dist/Set.d.ts.map +1 -1
  80. package/dist/TypeTest.d.ts +1 -1
  81. package/dist/Types.d.ts +1 -1
  82. package/dist/Widen.type.d.ts +1 -1
  83. package/dist/_ext/Array.d.ts +1 -1
  84. package/dist/_ext/Array.d.ts.map +1 -1
  85. package/dist/_ext/date.d.ts +1 -1
  86. package/dist/_ext/misc.d.ts +1 -1
  87. package/dist/_ext/ord.ext.d.ts +1 -1
  88. package/dist/_ext/ord.ext.d.ts.map +1 -1
  89. package/dist/builtin.d.ts +1 -1
  90. package/dist/builtin.d.ts.map +1 -1
  91. package/dist/client/InvalidationKeys.d.ts +29 -0
  92. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  93. package/dist/client/InvalidationKeys.js +33 -0
  94. package/dist/client/apiClientFactory.d.ts +17 -31
  95. package/dist/client/apiClientFactory.d.ts.map +1 -1
  96. package/dist/client/apiClientFactory.js +81 -26
  97. package/dist/client/clientFor.d.ts +63 -10
  98. package/dist/client/clientFor.d.ts.map +1 -1
  99. package/dist/client/clientFor.js +9 -1
  100. package/dist/client/errors.d.ts +49 -25
  101. package/dist/client/errors.d.ts.map +1 -1
  102. package/dist/client/errors.js +43 -17
  103. package/dist/client/makeClient.d.ts +360 -30
  104. package/dist/client/makeClient.d.ts.map +1 -1
  105. package/dist/client/makeClient.js +63 -23
  106. package/dist/client.d.ts +2 -1
  107. package/dist/client.d.ts.map +1 -1
  108. package/dist/client.js +2 -1
  109. package/dist/faker.d.ts +1 -1
  110. package/dist/faker.d.ts.map +1 -1
  111. package/dist/http/Request.d.ts +2 -2
  112. package/dist/http/Request.d.ts.map +1 -1
  113. package/dist/http/Request.js +5 -5
  114. package/dist/http/internal/lib.d.ts +1 -1
  115. package/dist/http.d.ts +1 -1
  116. package/dist/ids.d.ts +3 -3
  117. package/dist/ids.d.ts.map +1 -1
  118. package/dist/ids.js +3 -2
  119. package/dist/index.d.ts +5 -8
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +6 -8
  122. package/dist/logger.d.ts +1 -1
  123. package/dist/middleware.d.ts +16 -9
  124. package/dist/middleware.d.ts.map +1 -1
  125. package/dist/middleware.js +13 -9
  126. package/dist/rpc/Invalidation.d.ts +490 -0
  127. package/dist/rpc/Invalidation.d.ts.map +1 -0
  128. package/dist/rpc/Invalidation.js +129 -0
  129. package/dist/rpc/MiddlewareMaker.d.ts +5 -4
  130. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  131. package/dist/rpc/MiddlewareMaker.js +26 -27
  132. package/dist/rpc/RpcContextMap.d.ts +3 -3
  133. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  134. package/dist/rpc/RpcContextMap.js +4 -4
  135. package/dist/rpc/RpcMiddleware.d.ts +5 -4
  136. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  137. package/dist/rpc/RpcMiddleware.js +1 -1
  138. package/dist/rpc.d.ts +2 -2
  139. package/dist/rpc.d.ts.map +1 -1
  140. package/dist/rpc.js +2 -2
  141. package/dist/transform.d.ts +1 -1
  142. package/dist/transform.d.ts.map +1 -1
  143. package/dist/transform.js +3 -3
  144. package/dist/utils/effectify.d.ts +1 -1
  145. package/dist/utils/extend.d.ts +1 -1
  146. package/dist/utils/extend.d.ts.map +1 -1
  147. package/dist/utils/gen.d.ts +2 -2
  148. package/dist/utils/gen.d.ts.map +1 -1
  149. package/dist/utils/logLevel.d.ts +2 -2
  150. package/dist/utils/logLevel.d.ts.map +1 -1
  151. package/dist/utils/logger.d.ts +3 -3
  152. package/dist/utils/logger.d.ts.map +1 -1
  153. package/dist/utils/logger.js +3 -3
  154. package/dist/utils.d.ts +30 -10
  155. package/dist/utils.d.ts.map +1 -1
  156. package/dist/utils.js +10 -4
  157. package/dist/validation/validators.d.ts +1 -1
  158. package/dist/validation/validators.d.ts.map +1 -1
  159. package/dist/validation.d.ts +1 -1
  160. package/dist/validation.d.ts.map +1 -1
  161. package/eslint.config.mjs +2 -2
  162. package/package.json +47 -19
  163. package/src/Config/SecretURL.ts +2 -1
  164. package/src/Config.ts +14 -0
  165. package/src/ConfigProvider.ts +48 -0
  166. package/src/{ServiceMap.ts → Context.ts} +52 -59
  167. package/src/Effect.ts +12 -14
  168. package/src/Layer.ts +5 -4
  169. package/src/Operations.ts +14 -14
  170. package/src/Pure.ts +17 -18
  171. package/src/Schema/Class.ts +279 -62
  172. package/src/Schema/SchemaParser.ts +12 -0
  173. package/src/Schema/SpecialJsonSchema.ts +137 -0
  174. package/src/Schema/SpecialOpenApi.ts +130 -0
  175. package/src/Schema/brand.ts +9 -1
  176. package/src/Schema/email.ts +7 -2
  177. package/src/Schema/ext.ts +210 -80
  178. package/src/Schema/moreStrings.ts +22 -20
  179. package/src/Schema/numbers.ts +14 -16
  180. package/src/Schema/phoneNumber.ts +5 -1
  181. package/src/Schema/strings.ts +4 -8
  182. package/src/Schema.ts +265 -105
  183. package/src/client/InvalidationKeys.ts +50 -0
  184. package/src/client/apiClientFactory.ts +203 -119
  185. package/src/client/clientFor.ts +112 -23
  186. package/src/client/errors.ts +52 -26
  187. package/src/client/makeClient.ts +339 -63
  188. package/src/client.ts +1 -0
  189. package/src/http/Request.ts +7 -4
  190. package/src/ids.ts +2 -1
  191. package/src/index.ts +5 -10
  192. package/src/middleware.ts +12 -10
  193. package/src/rpc/Invalidation.ts +174 -0
  194. package/src/rpc/MiddlewareMaker.ts +36 -47
  195. package/src/rpc/README.md +2 -2
  196. package/src/rpc/RpcContextMap.ts +6 -5
  197. package/src/rpc/RpcMiddleware.ts +5 -4
  198. package/src/rpc.ts +1 -1
  199. package/src/transform.ts +2 -2
  200. package/src/utils/gen.ts +1 -1
  201. package/src/utils/logger.ts +2 -2
  202. package/src/utils.ts +47 -11
  203. package/test/dist/rpc.test.d.ts.map +1 -1
  204. package/test/dist/secretURL.test.d.ts.map +1 -0
  205. package/test/dist/special.test.d.ts.map +1 -0
  206. package/test/rpc.test.ts +38 -6
  207. package/test/schema.test.ts +591 -17
  208. package/test/secretURL.test.ts +157 -0
  209. package/test/special.test.ts +1023 -0
  210. package/test/utils.test.ts +6 -6
  211. package/tsconfig.base.json +3 -4
  212. package/tsconfig.json +0 -1
  213. package/tsconfig.json.bak +2 -2
  214. package/tsconfig.src.json +29 -29
  215. package/tsconfig.test.json +2 -2
  216. package/dist/ServiceMap.d.ts +0 -44
  217. package/dist/ServiceMap.d.ts.map +0 -1
  218. package/dist/ServiceMap.js +0 -91
@@ -1,19 +1,20 @@
1
1
  /** @effect-diagnostics overriddenSchemaConstructor:skip-file */
2
- import { TaggedError } from "effect-app/Schema"
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: { toJSON(): unknown; toString(): string }) => {
6
+ export const tryToJson = (error: unknown) => {
7
7
  try {
8
- return error.toJSON()
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 TaggedError<NotFoundError<ItemType>>()("NotFoundError", {
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 as any, disableValidation as any)
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 TaggedError<InvalidStateError>()("InvalidStateError", {
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 } as any,
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 TaggedError<ServiceUnavailableError>()("ServiceUnavailableError", {
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 } as any,
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 TaggedError<ValidationError>()("ValidationError", {
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 as any, disableValidation as any)
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 TaggedError<NotLoggedInError>()("NotLoggedInError", {
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) as any, disableValidation as any)
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 TaggedError<LoginError>()("NotLoggedInError", {
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) as any, disableValidation as any)
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 TaggedError<UnauthorizedError>()("UnauthorizedError", {
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) as any, disableValidation as any)
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 TaggedError<OptimisticConcurrencyException>()(
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` } as any,
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; toString(): string }) => {
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
  }
@@ -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: S.Codec<void> = S.Void as any
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 TaggedRequestResult<
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 = Record<string, never>
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.TaggedStruct<Tag, Payload>
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 ServiceMap/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??)
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
- function TaggedRequest<_Self>(): {
51
- <Tag extends string, Payload extends S.Struct.Fields, C extends ServiceMap>(
52
- tag: Tag,
53
- fields: Payload,
54
- config: RequestConfig & C
55
- ): TaggedRequestResult<Tag, Payload, SchemaOrFields<C["success"]>, ErrorResult<C>, Omit<C, "success" | "error">>
56
- <Tag extends string, Payload extends S.Struct.Fields, C extends Pick<ServiceMap, "success">>(
57
- tag: Tag,
58
- fields: Payload,
59
- config: RequestConfig & C
60
- ): TaggedRequestResult<Tag, Payload, SchemaOrFields<C["success"]>, ErrorResult<C>, Omit<C, "success" | "error">>
61
- <Tag extends string, Payload extends S.Struct.Fields, C extends Pick<ServiceMap, "error">>(
62
- tag: Tag,
63
- fields: Payload,
64
- config: RequestConfig & C
65
- ): TaggedRequestResult<Tag, Payload, S.Codec<void>, ErrorResult<C>, Omit<C, "success" | "error">>
66
- <Tag extends string, Payload extends S.Struct.Fields, C extends Record<string, any>>(
67
- tag: Tag,
68
- fields: Payload,
69
- config: C & RequestConfig
70
- ): TaggedRequestResult<Tag, Payload, S.Codec<void>, ErrorResult<C>, Omit<C, "success" | "error">>
71
- <Tag extends string, Payload extends S.Struct.Fields>(
72
- tag: Tag,
73
- fields: Payload
74
- ): TaggedRequestResult<Tag, Payload, S.Codec<void>, ErrorResult<never>, Record<string, never>>
75
- } {
76
- // TODO: filter errors based on config + take care of inversion
77
- const errorSchemas = Object.values(rcs.config).map((_) => _.error)
78
- return (<Tag extends string, Fields extends S.Struct.Fields, C extends ServiceMap>(
79
- tag: Tag,
80
- fields: Fields,
81
- config?: C
82
- ) => {
83
- // TODO: S.TaggedRequest removed in v4 needs rework to use Rpc.make or Request.TaggedClass
84
- // For now, creating a simple tagged struct class with success/failure properties
85
- const failureSchema = merge(
86
- config?.error ? S.isSchema(config.error) ? config.error : S.Struct(config.error) : undefined,
87
- [...errorSchemas, generalErrors].filter(Boolean)
88
- )
89
- const successSchema = config?.success
90
- ? S.isSchema(config.success)
91
- ? AST.isVoid(config.success.ast) ? ForceVoid : config.success
92
- : S.Struct(config.success)
93
- : ForceVoid
94
-
95
- const RequestClass = S.TaggedClass<any>()(tag, fields)
96
- Object.assign(RequestClass, {
97
- _tag: tag,
98
- success: successSchema,
99
- error: failureSchema,
100
- config
101
- })
102
-
103
- return RequestClass
104
- }) as any
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
- TaggedRequest
384
+ TaggedRequestFor
109
385
  }
110
386
  }
package/src/client.ts CHANGED
@@ -2,5 +2,6 @@
2
2
  export * from "./client/apiClientFactory.js"
3
3
  export * from "./client/clientFor.js"
4
4
  export * from "./client/errors.js"
5
+ export * from "./client/InvalidationKeys.js"
5
6
  export * from "./client/makeClient.js"
6
7
  // codegen:end