effect-app 4.0.0-beta.21 → 4.0.0-beta.211

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 (219) hide show
  1. package/CHANGELOG.md +954 -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 +7 -6
  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/Option.d.ts +1 -1
  31. package/dist/Option.d.ts.map +1 -1
  32. package/dist/Pure.d.ts +5 -5
  33. package/dist/Pure.d.ts.map +1 -1
  34. package/dist/Pure.js +13 -13
  35. package/dist/Schema/Class.d.ts +66 -20
  36. package/dist/Schema/Class.d.ts.map +1 -1
  37. package/dist/Schema/Class.js +189 -22
  38. package/dist/Schema/FastCheck.d.ts +1 -1
  39. package/dist/Schema/FastCheck.d.ts.map +1 -1
  40. package/dist/Schema/Methods.d.ts +1 -1
  41. package/dist/Schema/SchemaParser.d.ts +5 -0
  42. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  43. package/dist/Schema/SchemaParser.js +6 -0
  44. package/dist/Schema/SpecialJsonSchema.d.ts +33 -0
  45. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  46. package/dist/Schema/SpecialJsonSchema.js +122 -0
  47. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  48. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  49. package/dist/Schema/SpecialOpenApi.js +123 -0
  50. package/dist/Schema/brand.d.ts +4 -2
  51. package/dist/Schema/brand.d.ts.map +1 -1
  52. package/dist/Schema/brand.js +1 -1
  53. package/dist/Schema/email.d.ts +1 -1
  54. package/dist/Schema/email.d.ts.map +1 -1
  55. package/dist/Schema/email.js +7 -4
  56. package/dist/Schema/ext.d.ts +117 -45
  57. package/dist/Schema/ext.d.ts.map +1 -1
  58. package/dist/Schema/ext.js +131 -42
  59. package/dist/Schema/moreStrings.d.ts +37 -25
  60. package/dist/Schema/moreStrings.d.ts.map +1 -1
  61. package/dist/Schema/moreStrings.js +15 -16
  62. package/dist/Schema/numbers.d.ts +15 -15
  63. package/dist/Schema/numbers.d.ts.map +1 -1
  64. package/dist/Schema/numbers.js +10 -12
  65. package/dist/Schema/phoneNumber.d.ts +1 -1
  66. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  67. package/dist/Schema/phoneNumber.js +6 -3
  68. package/dist/Schema/schema.d.ts +1 -1
  69. package/dist/Schema/strings.d.ts +5 -5
  70. package/dist/Schema/strings.d.ts.map +1 -1
  71. package/dist/Schema/strings.js +1 -5
  72. package/dist/Schema.d.ts +147 -15
  73. package/dist/Schema.d.ts.map +1 -1
  74. package/dist/Schema.js +131 -16
  75. package/dist/Set.d.ts +1 -1
  76. package/dist/Set.d.ts.map +1 -1
  77. package/dist/TypeTest.d.ts +1 -1
  78. package/dist/Types.d.ts +1 -1
  79. package/dist/Widen.type.d.ts +1 -1
  80. package/dist/_ext/Array.d.ts +1 -1
  81. package/dist/_ext/Array.d.ts.map +1 -1
  82. package/dist/_ext/date.d.ts +1 -1
  83. package/dist/_ext/misc.d.ts +1 -1
  84. package/dist/_ext/ord.ext.d.ts +1 -1
  85. package/dist/_ext/ord.ext.d.ts.map +1 -1
  86. package/dist/builtin.d.ts +1 -1
  87. package/dist/builtin.d.ts.map +1 -1
  88. package/dist/client/InvalidationKeys.d.ts +29 -0
  89. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  90. package/dist/client/InvalidationKeys.js +33 -0
  91. package/dist/client/apiClientFactory.d.ts +20 -32
  92. package/dist/client/apiClientFactory.d.ts.map +1 -1
  93. package/dist/client/apiClientFactory.js +95 -32
  94. package/dist/client/clientFor.d.ts +51 -17
  95. package/dist/client/clientFor.d.ts.map +1 -1
  96. package/dist/client/clientFor.js +9 -1
  97. package/dist/client/errors.d.ts +49 -25
  98. package/dist/client/errors.d.ts.map +1 -1
  99. package/dist/client/errors.js +43 -17
  100. package/dist/client/makeClient.d.ts +481 -33
  101. package/dist/client/makeClient.d.ts.map +1 -1
  102. package/dist/client/makeClient.js +66 -24
  103. package/dist/client.d.ts +2 -1
  104. package/dist/client.d.ts.map +1 -1
  105. package/dist/client.js +2 -1
  106. package/dist/faker.d.ts +1 -1
  107. package/dist/faker.d.ts.map +1 -1
  108. package/dist/http/Request.d.ts +2 -2
  109. package/dist/http/Request.d.ts.map +1 -1
  110. package/dist/http/internal/lib.d.ts +1 -1
  111. package/dist/http.d.ts +1 -1
  112. package/dist/ids.d.ts +12 -12
  113. package/dist/ids.d.ts.map +1 -1
  114. package/dist/ids.js +3 -2
  115. package/dist/index.d.ts +5 -8
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +6 -8
  118. package/dist/logger.d.ts +1 -1
  119. package/dist/middleware.d.ts +14 -8
  120. package/dist/middleware.d.ts.map +1 -1
  121. package/dist/middleware.js +14 -8
  122. package/dist/rpc/Invalidation.d.ts +402 -0
  123. package/dist/rpc/Invalidation.d.ts.map +1 -0
  124. package/dist/rpc/Invalidation.js +150 -0
  125. package/dist/rpc/MiddlewareMaker.d.ts +5 -4
  126. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  127. package/dist/rpc/MiddlewareMaker.js +57 -37
  128. package/dist/rpc/RpcContextMap.d.ts +3 -3
  129. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  130. package/dist/rpc/RpcContextMap.js +4 -4
  131. package/dist/rpc/RpcMiddleware.d.ts +5 -4
  132. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  133. package/dist/rpc/RpcMiddleware.js +1 -1
  134. package/dist/rpc.d.ts +2 -2
  135. package/dist/rpc.d.ts.map +1 -1
  136. package/dist/rpc.js +2 -2
  137. package/dist/transform.d.ts +1 -1
  138. package/dist/transform.d.ts.map +1 -1
  139. package/dist/transform.js +3 -3
  140. package/dist/utils/effectify.d.ts +1 -1
  141. package/dist/utils/extend.d.ts +1 -1
  142. package/dist/utils/extend.d.ts.map +1 -1
  143. package/dist/utils/gen.d.ts +2 -2
  144. package/dist/utils/gen.d.ts.map +1 -1
  145. package/dist/utils/logLevel.d.ts +2 -2
  146. package/dist/utils/logLevel.d.ts.map +1 -1
  147. package/dist/utils/logger.d.ts +3 -3
  148. package/dist/utils/logger.d.ts.map +1 -1
  149. package/dist/utils/logger.js +3 -3
  150. package/dist/utils.d.ts +31 -38
  151. package/dist/utils.d.ts.map +1 -1
  152. package/dist/utils.js +12 -25
  153. package/dist/validation/validators.d.ts +1 -1
  154. package/dist/validation/validators.d.ts.map +1 -1
  155. package/dist/validation.d.ts +1 -1
  156. package/dist/validation.d.ts.map +1 -1
  157. package/package.json +46 -24
  158. package/src/Config/SecretURL.ts +2 -1
  159. package/src/Config.ts +14 -0
  160. package/src/ConfigProvider.ts +48 -0
  161. package/src/{ServiceMap.ts → Context.ts} +52 -59
  162. package/src/Effect.ts +12 -14
  163. package/src/Layer.ts +6 -5
  164. package/src/Pure.ts +17 -18
  165. package/src/Schema/Class.ts +268 -62
  166. package/src/Schema/SchemaParser.ts +12 -0
  167. package/src/Schema/SpecialJsonSchema.ts +137 -0
  168. package/src/Schema/SpecialOpenApi.ts +130 -0
  169. package/src/Schema/brand.ts +21 -1
  170. package/src/Schema/email.ts +7 -2
  171. package/src/Schema/ext.ts +204 -72
  172. package/src/Schema/moreStrings.ts +40 -37
  173. package/src/Schema/numbers.ts +14 -16
  174. package/src/Schema/phoneNumber.ts +5 -1
  175. package/src/Schema/strings.ts +4 -8
  176. package/src/Schema.ts +314 -20
  177. package/src/client/InvalidationKeys.ts +50 -0
  178. package/src/client/apiClientFactory.ts +223 -129
  179. package/src/client/clientFor.ts +95 -29
  180. package/src/client/errors.ts +52 -26
  181. package/src/client/makeClient.ts +572 -71
  182. package/src/client.ts +1 -0
  183. package/src/ids.ts +3 -2
  184. package/src/index.ts +5 -10
  185. package/src/middleware.ts +13 -9
  186. package/src/rpc/Invalidation.ts +226 -0
  187. package/src/rpc/MiddlewareMaker.ts +65 -60
  188. package/src/rpc/README.md +2 -2
  189. package/src/rpc/RpcContextMap.ts +6 -5
  190. package/src/rpc/RpcMiddleware.ts +5 -4
  191. package/src/rpc.ts +1 -1
  192. package/src/transform.ts +2 -2
  193. package/src/utils/gen.ts +1 -1
  194. package/src/utils/logger.ts +2 -2
  195. package/src/utils.ts +50 -132
  196. package/test/dist/rpc.test.d.ts.map +1 -1
  197. package/test/dist/secretURL.test.d.ts.map +1 -0
  198. package/test/dist/special.test.d.ts.map +1 -0
  199. package/test/dist/stream-error.types.d.ts +2 -0
  200. package/test/dist/stream-error.types.d.ts.map +1 -0
  201. package/test/dist/stream-error.types.js +27 -0
  202. package/test/rpc.test.ts +45 -6
  203. package/test/schema.test.ts +581 -7
  204. package/test/secretURL.test.ts +157 -0
  205. package/test/special.test.ts +1023 -0
  206. package/test/utils.test.ts +6 -6
  207. package/tsconfig.base.json +3 -4
  208. package/tsconfig.json +0 -1
  209. package/tsconfig.json.bak +2 -2
  210. package/tsconfig.src.json +29 -29
  211. package/tsconfig.test.json +2 -2
  212. package/dist/Operations.d.ts +0 -123
  213. package/dist/Operations.d.ts.map +0 -1
  214. package/dist/Operations.js +0 -29
  215. package/dist/ServiceMap.d.ts +0 -44
  216. package/dist/ServiceMap.d.ts.map +0 -1
  217. package/dist/ServiceMap.js +0 -91
  218. package/eslint.config.mjs +0 -26
  219. package/src/Operations.ts +0 -55
@@ -1,110 +1,611 @@
1
- import { type GetContextConfig, type GetEffectError, type RequestContextMapTagAny } from "../rpc/RpcContextMap.js"
1
+ import { SchemaTransformation } from "effect"
2
+ import type * as Exit from "effect/Exit"
3
+ import { type GetContextConfig, type RpcContextMap } from "../rpc/RpcContextMap.js"
2
4
  import * as S from "../Schema.js"
3
5
  import { AST } from "../Schema.js"
4
6
 
7
+ /**
8
+ * Minimal structural shape for an rpc-client middleware tag.
9
+ * Captures only what `makeRpcClient` and routing/client factory consume from it
10
+ * (no `Default` layer required — that is provided to `makeRouter`).
11
+ */
12
+ export interface ClientMiddleware<RequestContextMap extends Record<string, RpcContextMap.Any>> {
13
+ readonly requestContextMap: RequestContextMap
14
+ readonly requestContext: unknown
15
+ readonly provides?: unknown
16
+ readonly requires?: unknown
17
+ }
18
+
5
19
  const merge = (a: any, b: Array<any>) =>
6
20
  a !== undefined && b.length ? S.Union([a, ...b]) : a !== undefined ? a : b.length ? S.Union(b) : S.Never
7
21
 
8
22
  /**
9
23
  * Whatever the input, we will only decode or encode to void
10
24
  */
11
- const ForceVoid: S.Codec<void> = S.Void as any
25
+ export const ForceVoid = S
26
+ .declare((_: unknown): _ is unknown => true)
27
+ .pipe(
28
+ S.decodeTo(S.Any, SchemaTransformation.transform<unknown, unknown>({ decode: () => void 0, encode: () => void 0 }))
29
+ )
12
30
 
13
31
  type SchemaOrFields<T> = T extends S.Top ? T : T extends S.Struct.Fields ? S.Struct<T> : S.Void
14
32
 
15
- type TaggedRequestResult<
33
+ type TaggedRequestSchema<Tag extends string, Payload extends S.Struct.Fields> = S.Struct<
34
+ { readonly _tag: S.tag<Tag> } & Payload
35
+ >
36
+
37
+ type QueryOnlyRequests<Resource> = {
38
+ [K in keyof Resource as Resource[K] extends { readonly type: "query" } ? K : never]: Resource[K]
39
+ }
40
+
41
+ type QueryOnlyResources<Resources> = {
42
+ [K in keyof Resources]: QueryOnlyRequests<Resources[K]>
43
+ }
44
+
45
+ type InputFromPayload<Payload extends S.Struct.Fields> = keyof Payload extends never ? void
46
+ : S.Schema.Type<S.Struct<Payload>>
47
+
48
+ type OutputFromSuccess<Success extends S.Top> = Success extends typeof ForceVoid ? void : S.Schema.Type<Success>
49
+
50
+ type InvalidationResources = Record<string, Record<string, unknown>>
51
+
52
+ export type InvalidateQueryInstruction = {
53
+ readonly filters?: Record<string, unknown>
54
+ readonly options?: Record<string, unknown>
55
+ }
56
+
57
+ export type InvalidationCallback<Resources, Input = unknown, Success = unknown, Failure = unknown> = (
58
+ queryKey: readonly string[],
59
+ resources: QueryOnlyResources<Resources>,
60
+ ...args: [Input] extends [void] ? [exit: Exit.Exit<Success, Failure>]
61
+ : [input: Input, exit: Exit.Exit<Success, Failure>]
62
+ ) => ReadonlyArray<InvalidateQueryInstruction>
63
+
64
+ export type InvalidationConfig<Resources, Input = unknown, Success = unknown, Failure = unknown> = {
65
+ readonly invalidatesQueries: InvalidationCallback<Resources, Input, Success, Failure>
66
+ readonly invalidationResources?: Resources
67
+ }
68
+
69
+ type InvalidationConfigForCommand<
70
+ Resources,
71
+ Payload extends S.Struct.Fields,
72
+ Success extends S.Top,
73
+ Error extends S.Top
74
+ > = InvalidationConfig<
75
+ Resources,
76
+ InputFromPayload<Payload>,
77
+ OutputFromSuccess<Success>,
78
+ S.Schema.Type<Error>
79
+ >
80
+
81
+ export const configureInvalidation = <Resources>() =>
82
+ <Input, Success, Failure>(
83
+ invalidatesQueries: InvalidationCallback<Resources, NoInfer<Input>, NoInfer<Success>, NoInfer<Failure>>
84
+ ): InvalidationConfig<Resources, Input, Success, Failure> => ({ invalidatesQueries })
85
+
86
+ export const configureInvalidationCallback = <Resources>() =>
87
+ <Input, Success, Failure>(
88
+ invalidatesQueries: InvalidationCallback<Resources, NoInfer<Input>, NoInfer<Success>, NoInfer<Failure>>
89
+ ): InvalidationCallback<Resources, Input, Success, Failure> => invalidatesQueries
90
+
91
+ export const configureInvalidationResources = <Resources>() =>
92
+ ({}) as Pick<InvalidationConfig<Resources>, "invalidationResources">
93
+
94
+ type TaggedRequestForResult<
95
+ Self,
16
96
  Tag extends string,
17
97
  Payload extends S.Struct.Fields,
18
98
  Success extends S.Top,
19
99
  Error extends S.Top,
20
- Config = Record<string, never>
100
+ Config,
101
+ ModuleName extends string,
102
+ Type extends "command" | "query",
103
+ Stream extends boolean,
104
+ Resources = never,
105
+ Final extends S.Top = never,
106
+ Middleware = unknown
21
107
  > =
22
- & S.TaggedStruct<Tag, Payload>
108
+ & S.Opaque<Self, S.ExtendedSchemaNoEncoded, TaggedRequestSchema<Tag, Payload>, {}>
23
109
  & {
24
- new(...args: any[]): any
110
+ readonly fields: TaggedRequestSchema<Tag, Payload>["fields"]
25
111
  readonly _tag: Tag
26
- readonly fields: { readonly _tag: S.tag<Tag> } & Payload
27
112
  readonly success: Success
28
113
  readonly error: Error
29
114
  readonly config: Config
30
- readonly "~decodingServices": S.Codec.DecodingServices<Success> | S.Codec.DecodingServices<Error>
115
+ readonly id: `${ModuleName}.${Tag}`
116
+ readonly moduleName: ModuleName
117
+ readonly type: Type
118
+ readonly stream: Stream
119
+ readonly middleware?: Middleware
120
+ readonly "~invalidationResources"?: Resources
31
121
  }
122
+ & ([Final] extends [never] ? {} : { readonly final: Final })
32
123
 
33
124
  export const makeRpcClient = <
34
- RequestContextMap extends RequestContextMapTagAny,
125
+ Middleware extends ClientMiddleware<Record<string, RpcContextMap.Any>>,
35
126
  GeneralErrors extends S.Top = never
36
- >(rcs: RequestContextMap, generalErrors?: GeneralErrors) => {
37
- // Long way around ServiceMap/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??)
127
+ >(middleware: Middleware, generalErrors?: GeneralErrors) => {
128
+ // Long way around Context/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??)
38
129
  type ServiceMap = {
39
130
  success: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
40
131
  error: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
132
+ final?: S.Top | S.Struct.Fields // optional final-value schema for stream requests
133
+ stream?: boolean // request metadata — stripped from stored config
41
134
  }
42
135
 
43
- type RequestConfig = GetContextConfig<RequestContextMap["config"]>
136
+ type RequestConfig = GetContextConfig<Middleware["requestContextMap"]>
44
137
 
138
+ // Errors raised by RPC middleware (e.g. `NotLoggedInError` from auth) used to
139
+ // be merged into `resource.error` here so they would surface in the wire
140
+ // failure schema. That merging is gone — the canonical source for middleware
141
+ // errors is now the middleware tag attached to the rpc on both server and
142
+ // client (see `ApiClientFactory.makeFor({ middleware })`). `Rpc.exitSchema`
143
+ // unions in `rpc.middlewares[*].error` automatically.
45
144
  type MergeError<E> = [GeneralErrors] extends [never] ? SchemaOrFields<E> : S.Union<[SchemaOrFields<E>, GeneralErrors]>
46
145
  type ErrorResult<C> = C extends { error: infer E } ? MergeError<E>
47
- : [GeneralErrors] extends [never] ? GetEffectError<RequestContextMap["config"], C>
48
- : MergeError<GetEffectError<RequestContextMap["config"], C>>
49
-
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<{}>, 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
146
+ : [GeneralErrors] extends [never] ? typeof S.Never
147
+ : GeneralErrors
148
+
149
+ function makeRequestClass<Tag extends string, Fields extends S.Struct.Fields, C extends Partial<ServiceMap>>(
150
+ tag: Tag,
151
+ fields: Fields,
152
+ config?: C
153
+ ) {
154
+ const failureSchema = merge(
155
+ config?.error ? S.isSchema(config.error) ? config.error : S.Struct(config.error) : undefined,
156
+ [generalErrors].filter(Boolean)
157
+ )
158
+ const successSchema = config?.success
159
+ ? S.isSchema(config.success)
160
+ ? AST.isVoid(config.success.ast) ? ForceVoid : config.success
161
+ : S.Struct(config.success)
162
+ : ForceVoid
163
+
164
+ const finalConfig = (config as any)?.final
165
+ const finalSchema = finalConfig && S.isSchema(finalConfig) ? finalConfig : undefined
166
+
167
+ // Strip stream from the stored config — it's request metadata, not handler config
168
+ const { stream: _stream, ...restConfig } = config ?? ({} as C)
169
+
170
+ const RequestClass = S.Opaque()(S.TaggedStruct(tag, fields))
171
+ Object.assign(RequestClass, {
172
+ _tag: tag,
173
+ success: successSchema,
174
+ error: failureSchema,
175
+ ...(finalSchema !== undefined ? { final: finalSchema } : {}),
176
+ config: restConfig
177
+ })
178
+
179
+ return RequestClass
180
+ }
181
+
182
+ function makeTaggedRequestWithMeta<
183
+ ModuleName extends string,
184
+ Type extends "command" | "query"
185
+ >(
186
+ moduleName: ModuleName,
187
+ type: Type
188
+ ) {
189
+ function TaggedRequestWithMeta<Self, Resources extends InvalidationResources = never>(): {
190
+ // ─── stream: true overloads (must come before non-stream so TypeScript picks them) ───────────
191
+ <
192
+ Tag extends string,
193
+ Payload extends S.Struct.Fields,
194
+ Success extends S.Top | S.Struct.Fields,
195
+ Error extends S.Top | S.Struct.Fields,
196
+ Final extends S.Top | S.Struct.Fields = never,
197
+ C extends RequestConfig & Record<string, any> = RequestConfig & Record<string, any>
198
+ >(
199
+ tag: Tag,
200
+ fields: Payload,
201
+ config:
202
+ & Omit<C, "invalidatesQueries">
203
+ & { stream: true; success: Success; error: Error; final?: Final },
204
+ invalidatesQueries?: InvalidationCallback<
205
+ Resources,
206
+ InputFromPayload<Payload>,
207
+ OutputFromSuccess<SchemaOrFields<Success>>,
208
+ S.Schema.Type<ErrorResult<C & { success: Success; error: Error }>>
209
+ >
210
+ ): TaggedRequestForResult<
211
+ Self,
212
+ Tag,
213
+ Payload,
214
+ SchemaOrFields<Success>,
215
+ ErrorResult<C & { success: Success; error: Error }>,
216
+ Omit<
217
+ & Omit<C, "invalidatesQueries">
218
+ & {
219
+ success: Success
220
+ error: Error
221
+ }
222
+ & Partial<
223
+ InvalidationConfigForCommand<
224
+ Resources,
225
+ Payload,
226
+ SchemaOrFields<Success>,
227
+ ErrorResult<C & { success: Success; error: Error }>
228
+ >
229
+ >,
230
+ "success" | "error" | "stream"
231
+ >,
232
+ ModuleName,
233
+ Type,
234
+ true,
235
+ Resources,
236
+ [Final] extends [never] ? never : SchemaOrFields<Final>,
237
+ Middleware
238
+ >
239
+ <
240
+ Tag extends string,
241
+ Payload extends S.Struct.Fields,
242
+ Success extends S.Top | S.Struct.Fields,
243
+ Final extends S.Top | S.Struct.Fields = never,
244
+ C extends RequestConfig & Record<string, any> & { error?: never } =
245
+ & RequestConfig
246
+ & Record<string, any>
247
+ & { error?: never }
248
+ >(
249
+ tag: Tag,
250
+ fields: Payload,
251
+ config:
252
+ & Omit<C, "invalidatesQueries">
253
+ & { stream: true; success: Success; final?: Final },
254
+ invalidatesQueries?: InvalidationCallback<
255
+ Resources,
256
+ InputFromPayload<Payload>,
257
+ OutputFromSuccess<SchemaOrFields<Success>>,
258
+ S.Schema.Type<ErrorResult<C & { success: Success }>>
259
+ >
260
+ ): TaggedRequestForResult<
261
+ Self,
262
+ Tag,
263
+ Payload,
264
+ SchemaOrFields<Success>,
265
+ ErrorResult<C & { success: Success }>,
266
+ Omit<
267
+ & Omit<C, "invalidatesQueries">
268
+ & { success: Success }
269
+ & Partial<
270
+ InvalidationConfigForCommand<
271
+ Resources,
272
+ Payload,
273
+ SchemaOrFields<Success>,
274
+ ErrorResult<C & { success: Success }>
275
+ >
276
+ >,
277
+ "success" | "error" | "stream"
278
+ >,
279
+ ModuleName,
280
+ Type,
281
+ true,
282
+ Resources,
283
+ [Final] extends [never] ? never : SchemaOrFields<Final>,
284
+ Middleware
285
+ >
286
+ // ─── stream: true without `success` overloads ────────────────────────────────────────────────
287
+ <
288
+ Tag extends string,
289
+ Payload extends S.Struct.Fields,
290
+ Error extends S.Top | S.Struct.Fields,
291
+ C extends RequestConfig & Record<string, any> & { success?: never } =
292
+ & RequestConfig
293
+ & Record<string, any>
294
+ & { success?: never }
295
+ >(
296
+ tag: Tag,
297
+ fields: Payload,
298
+ config:
299
+ & Omit<C, "invalidatesQueries">
300
+ & { stream: true; error: Error },
301
+ invalidatesQueries?: InvalidationCallback<
302
+ Resources,
303
+ InputFromPayload<Payload>,
304
+ void,
305
+ S.Schema.Type<ErrorResult<C & { error: Error }>>
306
+ >
307
+ ): TaggedRequestForResult<
308
+ Self,
309
+ Tag,
310
+ Payload,
311
+ typeof ForceVoid,
312
+ ErrorResult<C & { error: Error }>,
313
+ Omit<
314
+ & Omit<C, "invalidatesQueries">
315
+ & { error: Error }
316
+ & Partial<
317
+ InvalidationConfigForCommand<
318
+ Resources,
319
+ Payload,
320
+ typeof ForceVoid,
321
+ ErrorResult<C & { error: Error }>
322
+ >
323
+ >,
324
+ "success" | "error" | "stream"
325
+ >,
326
+ ModuleName,
327
+ Type,
328
+ true,
329
+ Resources,
330
+ never,
331
+ Middleware
332
+ >
333
+ <
334
+ Tag extends string,
335
+ Payload extends S.Struct.Fields,
336
+ C extends RequestConfig & Record<string, any> & { success?: never; error?: never } =
337
+ & RequestConfig
338
+ & Record<string, any>
339
+ & { success?: never; error?: never }
340
+ >(
341
+ tag: Tag,
342
+ fields: Payload,
343
+ config:
344
+ & Omit<C, "invalidatesQueries">
345
+ & { stream: true },
346
+ invalidatesQueries?: InvalidationCallback<
347
+ Resources,
348
+ InputFromPayload<Payload>,
349
+ void,
350
+ S.Schema.Type<ErrorResult<C>>
351
+ >
352
+ ): TaggedRequestForResult<
353
+ Self,
354
+ Tag,
355
+ Payload,
356
+ typeof ForceVoid,
357
+ ErrorResult<C>,
358
+ Omit<
359
+ & Omit<C, "invalidatesQueries">
360
+ & Partial<InvalidationConfigForCommand<Resources, Payload, typeof ForceVoid, ErrorResult<C>>>,
361
+ "success" | "error" | "stream"
362
+ >,
363
+ ModuleName,
364
+ Type,
365
+ true,
366
+ Resources,
367
+ never,
368
+ Middleware
369
+ >
370
+ // ─── non-stream overloads ────────────────────────────────────────────────────────────────────
371
+ <
372
+ Tag extends string,
373
+ Payload extends S.Struct.Fields,
374
+ Success extends S.Top | S.Struct.Fields,
375
+ Error extends S.Top | S.Struct.Fields,
376
+ Final extends S.Top | S.Struct.Fields = never,
377
+ C extends RequestConfig & Record<string, any> = RequestConfig & Record<string, any>
378
+ >(
379
+ tag: Tag,
380
+ fields: Payload,
381
+ config:
382
+ & Omit<C, "invalidatesQueries">
383
+ & { success: Success; error: Error; final?: Final },
384
+ invalidatesQueries?: InvalidationCallback<
385
+ Resources,
386
+ InputFromPayload<Payload>,
387
+ OutputFromSuccess<SchemaOrFields<Success>>,
388
+ S.Schema.Type<ErrorResult<C & { success: Success; error: Error }>>
389
+ >
390
+ ): TaggedRequestForResult<
391
+ Self,
392
+ Tag,
393
+ Payload,
394
+ SchemaOrFields<Success>,
395
+ ErrorResult<C & { success: Success; error: Error }>,
396
+ Omit<
397
+ & Omit<C, "invalidatesQueries">
398
+ & {
399
+ success: Success
400
+ error: Error
401
+ }
402
+ & Partial<
403
+ InvalidationConfigForCommand<
404
+ Resources,
405
+ Payload,
406
+ SchemaOrFields<Success>,
407
+ ErrorResult<C & { success: Success; error: Error }>
408
+ >
409
+ >,
410
+ "success" | "error" | "stream"
411
+ >,
412
+ ModuleName,
413
+ Type,
414
+ false,
415
+ Resources,
416
+ [Final] extends [never] ? never : SchemaOrFields<Final>,
417
+ Middleware
418
+ >
419
+ <
420
+ Tag extends string,
421
+ Payload extends S.Struct.Fields,
422
+ Success extends S.Top | S.Struct.Fields,
423
+ Final extends S.Top | S.Struct.Fields = never,
424
+ C extends RequestConfig & Record<string, any> & { error?: never } =
425
+ & RequestConfig
426
+ & Record<string, any>
427
+ & {
428
+ error?: never
429
+ }
430
+ >(
431
+ tag: Tag,
432
+ fields: Payload,
433
+ config:
434
+ & Omit<C, "invalidatesQueries">
435
+ & { success: Success; final?: Final },
436
+ invalidatesQueries?: InvalidationCallback<
437
+ Resources,
438
+ InputFromPayload<Payload>,
439
+ OutputFromSuccess<SchemaOrFields<Success>>,
440
+ S.Schema.Type<ErrorResult<C & { success: Success }>>
441
+ >
442
+ ): TaggedRequestForResult<
443
+ Self,
444
+ Tag,
445
+ Payload,
446
+ SchemaOrFields<Success>,
447
+ ErrorResult<C & { success: Success }>,
448
+ Omit<
449
+ & Omit<C, "invalidatesQueries">
450
+ & {
451
+ success: Success
452
+ }
453
+ & Partial<
454
+ InvalidationConfigForCommand<
455
+ Resources,
456
+ Payload,
457
+ SchemaOrFields<Success>,
458
+ ErrorResult<C & { success: Success }>
459
+ >
460
+ >,
461
+ "success" | "error" | "stream"
462
+ >,
463
+ ModuleName,
464
+ Type,
465
+ false,
466
+ Resources,
467
+ [Final] extends [never] ? never : SchemaOrFields<Final>,
468
+ Middleware
469
+ >
470
+ <
471
+ Tag extends string,
472
+ Payload extends S.Struct.Fields,
473
+ Error extends S.Top | S.Struct.Fields,
474
+ C extends RequestConfig & Record<string, any> & { success?: never }
475
+ >(
476
+ tag: Tag,
477
+ fields: Payload,
478
+ config:
479
+ & Omit<C, "invalidatesQueries">
480
+ & { error: Error },
481
+ invalidatesQueries?: InvalidationCallback<
482
+ Resources,
483
+ InputFromPayload<Payload>,
484
+ void,
485
+ S.Schema.Type<ErrorResult<C & { error: Error }>>
486
+ >
487
+ ): TaggedRequestForResult<
488
+ Self,
489
+ Tag,
490
+ Payload,
491
+ typeof ForceVoid,
492
+ ErrorResult<C & { error: Error }>,
493
+ Omit<
494
+ & Omit<C, "invalidatesQueries">
495
+ & {
496
+ error: Error
497
+ }
498
+ & Partial<
499
+ InvalidationConfigForCommand<
500
+ Resources,
501
+ Payload,
502
+ typeof ForceVoid,
503
+ ErrorResult<C & { error: Error }>
504
+ >
505
+ >,
506
+ "success" | "error" | "stream"
507
+ >,
508
+ ModuleName,
509
+ Type,
510
+ false,
511
+ Resources,
512
+ never,
513
+ Middleware
514
+ >
515
+ <
516
+ Tag extends string,
517
+ Payload extends S.Struct.Fields,
518
+ C extends RequestConfig & Record<string, any> & { success?: never; error?: never }
519
+ >(
520
+ tag: Tag,
521
+ fields: Payload,
522
+ config: Omit<C, "invalidatesQueries">,
523
+ invalidatesQueries?: InvalidationCallback<
524
+ Resources,
525
+ InputFromPayload<Payload>,
526
+ void,
527
+ S.Schema.Type<ErrorResult<C>>
528
+ >
529
+ ): TaggedRequestForResult<
530
+ Self,
531
+ Tag,
532
+ Payload,
533
+ typeof ForceVoid,
534
+ ErrorResult<C>,
535
+ Omit<
536
+ & Omit<C, "invalidatesQueries">
537
+ & Partial<InvalidationConfigForCommand<Resources, Payload, typeof ForceVoid, ErrorResult<C>>>,
538
+ "success" | "error" | "stream"
539
+ >,
540
+ ModuleName,
541
+ Type,
542
+ false,
543
+ Resources,
544
+ never,
545
+ Middleware
546
+ >
547
+ <Tag extends string, Payload extends S.Struct.Fields>(
548
+ tag: Tag,
549
+ fields: Payload
550
+ ): TaggedRequestForResult<
551
+ Self,
552
+ Tag,
553
+ Payload,
554
+ typeof ForceVoid,
555
+ ErrorResult<{}>,
556
+ Record<string, never>,
557
+ ModuleName,
558
+ Type,
559
+ false,
560
+ never,
561
+ never,
562
+ Middleware
563
+ >
564
+ } {
565
+ return (<Tag extends string, Fields extends S.Struct.Fields, C extends ServiceMap>(
566
+ tag: Tag,
567
+ fields: Fields,
568
+ config?: C,
569
+ invalidatesQueries?: InvalidationCallback<Resources>
570
+ ) => {
571
+ const isStream = (config as any)?.stream === true
572
+ const requestConfig = invalidatesQueries === undefined ? config : { ...config, invalidatesQueries }
573
+ const cls = makeRequestClass(tag, fields, requestConfig)
574
+ Object.assign(cls, {
575
+ id: `${moduleName}.${tag}`,
576
+ moduleName,
577
+ type,
578
+ stream: isStream,
579
+ middleware
580
+ })
581
+ return cls
582
+ }) as any
583
+ }
584
+ return Object.assign(TaggedRequestWithMeta, { moduleName, type } as const)
585
+ }
586
+
587
+ function TaggedRequestFor<ModuleName extends string>(moduleName: ModuleName) {
588
+ const Query = makeTaggedRequestWithMeta(moduleName, "query")
589
+ const Command = makeTaggedRequestWithMeta(moduleName, "command")
590
+
591
+ return {
592
+ moduleName,
593
+ /**
594
+ * Create query request classes for this module.
595
+ * Queries read state and should not mutate server state.
596
+ * Pass `stream: true` in the config to produce a Stream of `success` values (QueryStream behaviour).
597
+ */
598
+ Query,
599
+ /**
600
+ * Create command request classes for this module.
601
+ * Commands mutate state and should avoid returning complex read models.
602
+ * Pass `stream: true` in the config to produce a Stream of `success` values (CommandStream behaviour).
603
+ */
604
+ Command
605
+ } as const
105
606
  }
106
607
 
107
608
  return {
108
- TaggedRequest
609
+ TaggedRequestFor
109
610
  }
110
611
  }
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