effect-app 4.0.0-beta.195 → 4.0.0-beta.197

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/src/Schema.ts CHANGED
@@ -1,10 +1,13 @@
1
1
  import { SchemaAST, type Tracer } from "effect"
2
2
  import * as S from "effect/Schema"
3
+ import { type Simplify } from "effect/Struct"
4
+ import type { RequiredKeys } from "effect/Types"
3
5
  import type { NonEmptyReadonlyArray } from "./Array.js"
4
6
  import { fakerArb } from "./faker.js"
5
7
  import { Email as EmailT, type Email as EmailType } from "./Schema/email.js"
6
8
  import { concurrencyUnbounded, withDefaultMake, withDefaultParseOptions } from "./Schema/ext.js"
7
9
  import { PhoneNumber as PhoneNumberT, type PhoneNumber as PhoneNumberType } from "./Schema/phoneNumber.js"
10
+ import { type AST } from "./Schema/schema.js"
8
11
  import { copy, extendM, type StructuralCopyOrigin } from "./utils.js"
9
12
 
10
13
  export * from "effect/Schema"
@@ -41,18 +44,9 @@ export { Void as Void_ } from "effect/Schema"
41
44
  // Struct / NonEmptyArray / Record
42
45
  // ---------------------------------------------------------------------------
43
46
 
44
- type WithSchemaCopy<Self extends S.Top & { readonly Type: object }> = Self & {
45
- readonly copy: StructuralCopyOrigin<Self["Type"]>
46
- }
47
-
48
- type OptionalMakeInput<Fields extends S.Struct.Fields> = {} extends S.Struct.MakeIn<Fields> ? {
49
- make(input?: S.Struct.MakeIn<Fields>, options?: S.MakeOptions): S.Struct.Type<Fields>
50
- }
51
- : {}
52
-
53
47
  export function Struct<const Fields extends S.Struct.Fields>(
54
48
  fields: Fields
55
- ): Struct<Fields> & OptionalMakeInput<Fields> {
49
+ ): Struct<Fields> {
56
50
  const result = S.Struct(fields).annotate(concurrencyUnbounded)
57
51
  const allowVoidMake = (schema: any): any => {
58
52
  // Normalize omitted input to an empty object so optional/default-only structs can be constructed with make().
@@ -107,27 +101,79 @@ export function Struct<const Fields extends S.Struct.Fields>(
107
101
  }
108
102
  ;(result as any).copy = copy
109
103
  allowVoidMake(result)
110
- return result as Struct<Fields> & OptionalMakeInput<Fields>
104
+ return result as Struct<Fields>
111
105
  }
112
- export interface Struct<Fields extends S.Struct.Fields> extends WithSchemaCopy<S.Struct<Fields>> {
113
- annotate(
114
- annotations: S.Annotations.Bottom<S.Struct.Type<Fields>, S.Struct<Fields>["~type.parameters"]>
115
- ): Struct<Fields>
116
- annotateKey(annotations: S.Annotations.Key<S.Struct.Type<Fields>>): Struct<Fields>
117
- mapFields<To extends S.Struct.Fields>(
106
+
107
+ export interface Struct<Fields extends S.Struct.Fields> extends
108
+ S.Bottom<
109
+ Struct.Type<Fields>,
110
+ Struct.Encoded<Fields>,
111
+ Struct.DecodingServices<Fields>,
112
+ Struct.EncodingServices<Fields>,
113
+ AST.Objects,
114
+ // Rebuild is what's returned from annotate etc
115
+ Struct<Fields>,
116
+ Struct.MakeIn<Fields>,
117
+ Struct.Iso<Fields>
118
+ >
119
+ {
120
+ /**
121
+ * The field definitions of this struct. Spread them into a new struct to
122
+ * reuse fields across schemas.
123
+ *
124
+ * **Example** (Reusing fields across structs)
125
+ *
126
+ * ```ts
127
+ * import { Schema } from "effect"
128
+ *
129
+ * const Timestamped = Schema.Struct({
130
+ * createdAt: Schema.Date,
131
+ * updatedAt: Schema.Date
132
+ * })
133
+ *
134
+ * const User = Schema.Struct({
135
+ * ...Timestamped.fields,
136
+ * name: Schema.String,
137
+ * email: Schema.String
138
+ * })
139
+ * ```
140
+ */
141
+ readonly fields: Fields
142
+ /**
143
+ * Returns a new struct with the fields modified by the provided function.
144
+ *
145
+ * **Options**
146
+ *
147
+ * - `unsafePreserveChecks` - if `true`, keep any `.check(...)` constraints
148
+ * that were attached to the original union. Defaults to `false`.
149
+ *
150
+ * **Warning**: This is an unsafe operation. Since `mapFields`
151
+ * transformations change the schema type, the original refinement functions
152
+ * may no longer be valid or safe to apply to the transformed schema. Only
153
+ * use this option if you have verified that your refinements remain correct
154
+ * after the transformation.
155
+ */
156
+ mapFields<To extends Struct.Fields>(
118
157
  f: (fields: Fields) => To,
119
158
  options?: {
120
159
  readonly unsafePreserveChecks?: boolean | undefined
121
- }
122
- ): Struct<Readonly<To>>
160
+ } | undefined
161
+ ): Struct<Simplify<Readonly<To>>>
162
+
163
+ // added copy
164
+ readonly copy: StructuralCopyOrigin<Struct.Type<Fields>>
123
165
  }
166
+
124
167
  export declare namespace Struct {
125
168
  export type Fields = S.Struct.Fields
126
169
  export type Type<F extends S.Struct.Fields> = S.Struct.Type<F>
127
170
  export type Encoded<F extends S.Struct.Fields> = S.Struct.Encoded<F>
128
171
  export type DecodingServices<F extends S.Struct.Fields> = S.Struct.DecodingServices<F>
129
172
  export type EncodingServices<F extends S.Struct.Fields> = S.Struct.EncodingServices<F>
130
- export type MakeIn<F extends S.Struct.Fields> = S.Struct.MakeIn<F>
173
+ // changed; all optional allows void
174
+ export type MakeIn<F extends S.Struct.Fields> = RequiredKeys<S.Struct.MakeIn<F>> extends never
175
+ ? void | S.Struct.MakeIn<F>
176
+ : S.Struct.MakeIn<F>
131
177
  export type Iso<F extends S.Struct.Fields> = S.Struct.Iso<F>
132
178
  }
133
179
 
@@ -151,11 +197,32 @@ export function TaggedStruct<const Tag extends SchemaAST.LiteralValue, const Fie
151
197
  ): TaggedStruct<Tag, Fields> {
152
198
  return Struct({ _tag: S.tag(value), ...fields }) as any
153
199
  }
154
- export type TaggedStruct<Tag extends SchemaAST.LiteralValue, Fields extends S.Struct.Fields> =
155
- & WithSchemaCopy<
156
- S.TaggedStruct<Tag, Fields>
200
+ export interface TaggedStruct<Tag extends SchemaAST.LiteralValue, Fields extends S.Struct.Fields>
201
+ extends Struct<{ readonly _tag: S.tag<Tag> } & Fields>
202
+ {}
203
+ export declare namespace TaggedStruct {
204
+ export type Fields = S.Struct.Fields
205
+ export type Type<Tag extends SchemaAST.LiteralValue, F extends S.Struct.Fields> = S.Struct.Type<
206
+ { readonly _tag: S.tag<Tag> } & F
207
+ >
208
+ export type Encoded<Tag extends SchemaAST.LiteralValue, F extends S.Struct.Fields> = S.Struct.Encoded<
209
+ { readonly _tag: S.tag<Tag> } & F
157
210
  >
158
- & OptionalMakeInput<Readonly<{ readonly _tag: S.tag<Tag> } & Fields>>
211
+ export type DecodingServices<Tag extends SchemaAST.LiteralValue, F extends S.Struct.Fields> =
212
+ S.Struct.DecodingServices<
213
+ { readonly _tag: S.tag<Tag> } & F
214
+ >
215
+ export type EncodingServices<Tag extends SchemaAST.LiteralValue, F extends S.Struct.Fields> =
216
+ S.Struct.EncodingServices<
217
+ { readonly _tag: S.tag<Tag> } & F
218
+ >
219
+ export type MakeIn<Tag extends SchemaAST.LiteralValue, F extends S.Struct.Fields> = S.Struct.MakeIn<
220
+ { readonly _tag: S.tag<Tag> } & F
221
+ >
222
+ export type Iso<Tag extends SchemaAST.LiteralValue, F extends S.Struct.Fields> = S.Struct.Iso<
223
+ { readonly _tag: S.tag<Tag> } & F
224
+ >
225
+ }
159
226
 
160
227
  export function Record<Key extends S.Record.Key, Value extends S.Top>(
161
228
  key: Key,
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { flow } from "effect/Function"
2
+ import { constant, flow } from "effect/Function"
3
3
  import * as Layer from "effect/Layer"
4
4
  import * as ManagedRuntime from "effect/ManagedRuntime"
5
5
  import * as Option from "effect/Option"
@@ -44,8 +44,8 @@ export type Req = S.Top & {
44
44
  config?: Record<string, any>
45
45
  readonly id: string
46
46
  readonly moduleName: string
47
- readonly type: "command" | "query" | "stream"
48
- readonly "~decodingServices"?: unknown
47
+ readonly type: "command" | "query"
48
+ readonly stream: boolean
49
49
  }
50
50
 
51
51
  class RequestName extends Context.Reference("RequestName", {
@@ -126,18 +126,18 @@ export const makeRpcGroupFromRequestsAndModuleName = <M extends RequestsAny, con
126
126
  .make(
127
127
  ...typedValuesOf(filtered).map((_) => {
128
128
  const r = _ as any
129
- const isStream = r.type === "stream"
129
+ const isStream = r.stream
130
130
  const isCommand = r.type === "command"
131
131
  return (isCommand
132
- ? Invalidation.makeCommandRpc(r._tag, { payload: r, success: r.success, error: r.error })
133
- : isStream
134
- ? Invalidation.makeStreamRpc(r._tag, {
135
- payload: r,
136
- success: r.success,
137
- error: r.error,
138
- stream: true as const
139
- })
140
- : Rpc.make(r._tag, { payload: r, success: r.success, error: r.error })) as any
132
+ ? isStream
133
+ ? Invalidation.makeStreamRpc(r._tag, {
134
+ payload: r,
135
+ success: r.success,
136
+ error: r.error,
137
+ stream: true as const
138
+ })
139
+ : Invalidation.makeCommandRpc(r._tag, { payload: r, success: r.success, error: r.error })
140
+ : Rpc.make(r._tag, { payload: r, success: r.success, error: r.error, stream: isStream })) as any
141
141
  })
142
142
  )
143
143
  .prefix(`${moduleName}.`) as unknown as RpcGroup.RpcGroup<
@@ -245,7 +245,7 @@ const makeApiClientFactory = Effect
245
245
  const fields = Struct.omit(Request.fields, ["_tag"] as const)
246
246
  const requestAttr = `${meta.moduleName}.${h._tag}`
247
247
  const isCommand = h.type === "command"
248
- const isStream = h.type === "stream"
248
+ const isStream = h.stream
249
249
 
250
250
  const buildEffect = (input: any) =>
251
251
  mr.contextEffect.pipe(
@@ -314,7 +314,7 @@ const makeApiClientFactory = Effect
314
314
  // @ts-expect-error doc
315
315
  prev[cur] = Object.keys(fields).length === 0
316
316
  ? {
317
- handler: isStream ? buildStream({}) : buildEffect({}),
317
+ handler: isStream ? constant(buildStream({})) : constant(buildEffect({})),
318
318
  ...requestMeta
319
319
  }
320
320
  : {
@@ -85,13 +85,6 @@ export const makeQueryKey = ({ id, options }: { id: string; options?: ClientForO
85
85
  .join(".")
86
86
  .split(".")
87
87
 
88
- export interface RequestHandler<A, E, R, Request extends Req, Id extends string> {
89
- handler: Effect.Effect<A, E, R>
90
- id: Id
91
- options?: ClientForOptions
92
- Request: Request
93
- }
94
-
95
88
  export interface RequestHandlerWithInput<I, A, E, R, Request extends Req, Id extends string> {
96
89
  handler: (i: I) => Effect.Effect<A, E, R>
97
90
  id: Id
@@ -99,20 +92,15 @@ export interface RequestHandlerWithInput<I, A, E, R, Request extends Req, Id ext
99
92
  Request: Request
100
93
  }
101
94
 
102
- export interface RequestStreamHandler<A, E, R, Request extends Req, Id extends string, Final = A> {
103
- handler: Stream.Stream<A, E, R>
104
- id: Id
105
- options?: ClientForOptions
106
- Request: Request
107
- /**
108
- * Phantom type property (never set at runtime) that carries the `Final` type to
109
- * `StreamMutationWithExtensions`. The tilde prefix follows the Effect convention for
110
- * phantom/virtual properties and prevents accidental runtime access.
111
- * Stream failures bubble through the execute effect's typed error channel `E`;
112
- * the reactive `AsyncResult` ref also mirrors the failure for live progress UI.
113
- */
114
- readonly "~final"?: Final
115
- }
95
+ /** Type alias: a no-input handler is simply `RequestHandlerWithInput<void, …>`. */
96
+ export type RequestHandler<A, E, R, Request extends Req, Id extends string> = RequestHandlerWithInput<
97
+ void,
98
+ A,
99
+ E,
100
+ R,
101
+ Request,
102
+ Id
103
+ >
116
104
 
117
105
  export interface RequestStreamHandlerWithInput<I, A, E, R, Request extends Req, Id extends string, Final = A> {
118
106
  handler: (i: I) => Stream.Stream<A, E, R>
@@ -129,9 +117,11 @@ export interface RequestStreamHandlerWithInput<I, A, E, R, Request extends Req,
129
117
  readonly "~final"?: Final
130
118
  }
131
119
 
132
- // make sure this is exported or d.ts of apiClientFactory breaks?!
133
- type ReqDecodingServices<M> = M extends { readonly "~decodingServices": infer DS } ? DS : never
120
+ /** Type alias: a no-input stream handler is simply `RequestStreamHandlerWithInput<void, …>`. */
121
+ export type RequestStreamHandler<A, E, R, Request extends Req, Id extends string, Final = A> =
122
+ RequestStreamHandlerWithInput<void, A, E, R, Request, Id, Final>
134
123
 
124
+ // make sure this is exported or d.ts of apiClientFactory breaks?!
135
125
  export type RequestInputFromMake<I extends { readonly make: (...args: any[]) => any }> = Parameters<I["make"]> extends
136
126
  [] ? void : Parameters<I["make"]>[0]
137
127
 
@@ -154,36 +144,21 @@ export type HandlerInput<I extends { readonly make: (...args: any[]) => any }> =
154
144
  type FinalTypeOf<T extends Req> = T extends { readonly final: infer F extends S.Top } ? S.Schema.Type<F>
155
145
  : S.Schema.Type<T["success"]>
156
146
 
157
- type RequestHandlerFor<R, E, T extends Req, Id extends string> = T["type"] extends "stream"
158
- ? HasNoFields<T> extends true ? RequestStreamHandler<
159
- S.Schema.Type<T["success"]>,
160
- S.Schema.Type<T["error"]> | E,
161
- R | ReqDecodingServices<T>,
162
- T,
163
- Id,
164
- FinalTypeOf<T>
165
- >
166
- : RequestStreamHandlerWithInput<
167
- RequestInput<T>,
147
+ type RequestHandlerFor<R, E, T extends Req, Id extends string> = T["stream"] extends true
148
+ ? RequestStreamHandlerWithInput<
149
+ HandlerInput<T>,
168
150
  S.Schema.Type<T["success"]>,
169
151
  S.Schema.Type<T["error"]> | E,
170
- R | ReqDecodingServices<T>,
152
+ R | S.Codec.DecodingServices<T["success"]> | S.Codec.DecodingServices<T["error"]>,
171
153
  T,
172
154
  Id,
173
155
  FinalTypeOf<T>
174
156
  >
175
- : HasNoFields<T> extends true ? RequestHandler<
176
- S.Schema.Type<T["success"]>,
177
- S.Schema.Type<T["error"]> | E,
178
- R | ReqDecodingServices<T>,
179
- T,
180
- Id
181
- >
182
157
  : RequestHandlerWithInput<
183
- RequestInput<T>,
158
+ HandlerInput<T>,
184
159
  S.Schema.Type<T["success"]>,
185
160
  S.Schema.Type<T["error"]> | E,
186
- R | ReqDecodingServices<T>,
161
+ R | S.Codec.DecodingServices<T["success"]> | S.Codec.DecodingServices<T["error"]>,
187
162
  T,
188
163
  Id
189
164
  >
@@ -87,21 +87,22 @@ type TaggedRequestForResult<
87
87
  Error extends S.Top,
88
88
  Config,
89
89
  ModuleName extends string,
90
- Type extends "command" | "query" | "stream",
90
+ Type extends "command" | "query",
91
+ Stream extends boolean,
91
92
  Resources = never,
92
93
  Final extends S.Top = never
93
94
  > =
94
- & S.EnhancedClass<Self, TaggedRequestSchema<Tag, Payload>, {}>
95
+ & S.Opaque<Self, S.ExtendedSchemaNoEncoded, TaggedRequestSchema<Tag, Payload>, {}>
95
96
  & {
97
+ readonly fields: TaggedRequestSchema<Tag, Payload>["fields"]
96
98
  readonly _tag: Tag
97
99
  readonly success: Success
98
100
  readonly error: Error
99
101
  readonly config: Config
100
- readonly "~decodingServices": S.Codec.DecodingServices<Success> | S.Codec.DecodingServices<Error>
101
- readonly "~encodingServices": S.Codec.EncodingServices<Success> | S.Codec.EncodingServices<Error>
102
102
  readonly id: `${ModuleName}.${Tag}`
103
103
  readonly moduleName: ModuleName
104
104
  readonly type: Type
105
+ readonly stream: Stream
105
106
  readonly "~invalidationResources"?: Resources
106
107
  }
107
108
  & ([Final] extends [never] ? {} : { readonly final: Final })
@@ -115,6 +116,7 @@ export const makeRpcClient = <
115
116
  success: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
116
117
  error: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
117
118
  final?: S.Top | S.Struct.Fields // optional final-value schema for stream requests
119
+ stream?: boolean // request metadata — stripped from stored config
118
120
  }
119
121
 
120
122
  type RequestConfig = GetContextConfig<RequestContextMap["config"]>
@@ -145,23 +147,124 @@ export const makeRpcClient = <
145
147
  const finalConfig = (config as any)?.final
146
148
  const finalSchema = finalConfig && S.isSchema(finalConfig) ? finalConfig : undefined
147
149
 
148
- const RequestClass = S.TaggedClass<any>()(tag, fields)
150
+ // Strip stream from the stored config — it's request metadata, not handler config
151
+ const { stream: _stream, ...restConfig } = config ?? ({} as C)
152
+
153
+ const RequestClass = S.Opaque()(S.TaggedStruct(tag, fields))
149
154
  Object.assign(RequestClass, {
150
155
  _tag: tag,
151
156
  success: successSchema,
152
157
  error: failureSchema,
153
158
  ...(finalSchema !== undefined ? { final: finalSchema } : {}),
154
- config
159
+ config: restConfig
155
160
  })
156
161
 
157
162
  return RequestClass
158
163
  }
159
164
 
160
- function makeTaggedRequestWithMeta<ModuleName extends string, Type extends "command" | "query" | "stream">(
165
+ function makeTaggedRequestWithMeta<
166
+ ModuleName extends string,
167
+ Type extends "command" | "query"
168
+ >(
161
169
  moduleName: ModuleName,
162
170
  type: Type
163
171
  ) {
164
172
  function TaggedRequestWithMeta<Self, Resources extends InvalidationResources = never>(): {
173
+ // ─── stream: true overloads (must come before non-stream so TypeScript picks them) ───────────
174
+ <
175
+ Tag extends string,
176
+ Payload extends S.Struct.Fields,
177
+ Success extends S.Top | S.Struct.Fields,
178
+ Error extends S.Top | S.Struct.Fields,
179
+ Final extends S.Top | S.Struct.Fields = never,
180
+ C extends RequestConfig & Record<string, any> = RequestConfig & Record<string, any>
181
+ >(
182
+ tag: Tag,
183
+ fields: Payload,
184
+ config:
185
+ & Omit<C, "invalidatesQueries">
186
+ & { stream: true; success: Success; error: Error; final?: Final },
187
+ invalidatesQueries?: InvalidationCallback<
188
+ Resources,
189
+ InputFromPayload<Payload>,
190
+ OutputFromSuccess<SchemaOrFields<Success>>,
191
+ S.Schema.Type<ErrorResult<C & { success: Success; error: Error }>>
192
+ >
193
+ ): TaggedRequestForResult<
194
+ Self,
195
+ Tag,
196
+ Payload,
197
+ SchemaOrFields<Success>,
198
+ ErrorResult<C & { success: Success; error: Error }>,
199
+ Omit<
200
+ & Omit<C, "invalidatesQueries">
201
+ & {
202
+ success: Success
203
+ error: Error
204
+ }
205
+ & Partial<
206
+ InvalidationConfigForCommand<
207
+ Resources,
208
+ Payload,
209
+ SchemaOrFields<Success>,
210
+ ErrorResult<C & { success: Success; error: Error }>
211
+ >
212
+ >,
213
+ "success" | "error" | "stream"
214
+ >,
215
+ ModuleName,
216
+ Type,
217
+ true,
218
+ Resources,
219
+ [Final] extends [never] ? never : SchemaOrFields<Final>
220
+ >
221
+ <
222
+ Tag extends string,
223
+ Payload extends S.Struct.Fields,
224
+ Success extends S.Top | S.Struct.Fields,
225
+ Final extends S.Top | S.Struct.Fields = never,
226
+ C extends RequestConfig & Record<string, any> & { error?: never } =
227
+ & RequestConfig
228
+ & Record<string, any>
229
+ & { error?: never }
230
+ >(
231
+ tag: Tag,
232
+ fields: Payload,
233
+ config:
234
+ & Omit<C, "invalidatesQueries">
235
+ & { stream: true; success: Success; final?: Final },
236
+ invalidatesQueries?: InvalidationCallback<
237
+ Resources,
238
+ InputFromPayload<Payload>,
239
+ OutputFromSuccess<SchemaOrFields<Success>>,
240
+ S.Schema.Type<ErrorResult<C & { success: Success }>>
241
+ >
242
+ ): TaggedRequestForResult<
243
+ Self,
244
+ Tag,
245
+ Payload,
246
+ SchemaOrFields<Success>,
247
+ ErrorResult<C & { success: Success }>,
248
+ Omit<
249
+ & Omit<C, "invalidatesQueries">
250
+ & { success: Success }
251
+ & Partial<
252
+ InvalidationConfigForCommand<
253
+ Resources,
254
+ Payload,
255
+ SchemaOrFields<Success>,
256
+ ErrorResult<C & { success: Success }>
257
+ >
258
+ >,
259
+ "success" | "error" | "stream"
260
+ >,
261
+ ModuleName,
262
+ Type,
263
+ true,
264
+ Resources,
265
+ [Final] extends [never] ? never : SchemaOrFields<Final>
266
+ >
267
+ // ─── non-stream overloads ────────────────────────────────────────────────────────────────────
165
268
  <
166
269
  Tag extends string,
167
270
  Payload extends S.Struct.Fields,
@@ -201,10 +304,11 @@ export const makeRpcClient = <
201
304
  ErrorResult<C & { success: Success; error: Error }>
202
305
  >
203
306
  >,
204
- "success" | "error"
307
+ "success" | "error" | "stream"
205
308
  >,
206
309
  ModuleName,
207
310
  Type,
311
+ false,
208
312
  Resources,
209
313
  [Final] extends [never] ? never : SchemaOrFields<Final>
210
314
  >
@@ -213,9 +317,12 @@ export const makeRpcClient = <
213
317
  Payload extends S.Struct.Fields,
214
318
  Success extends S.Top | S.Struct.Fields,
215
319
  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
- }
320
+ C extends RequestConfig & Record<string, any> & { error?: never } =
321
+ & RequestConfig
322
+ & Record<string, any>
323
+ & {
324
+ error?: never
325
+ }
219
326
  >(
220
327
  tag: Tag,
221
328
  fields: Payload,
@@ -247,10 +354,11 @@ export const makeRpcClient = <
247
354
  ErrorResult<C & { success: Success }>
248
355
  >
249
356
  >,
250
- "success" | "error"
357
+ "success" | "error" | "stream"
251
358
  >,
252
359
  ModuleName,
253
360
  Type,
361
+ false,
254
362
  Resources,
255
363
  [Final] extends [never] ? never : SchemaOrFields<Final>
256
364
  >
@@ -290,10 +398,11 @@ export const makeRpcClient = <
290
398
  ErrorResult<C & { error: Error }>
291
399
  >
292
400
  >,
293
- "success" | "error"
401
+ "success" | "error" | "stream"
294
402
  >,
295
403
  ModuleName,
296
404
  Type,
405
+ false,
297
406
  Resources
298
407
  >
299
408
  <
@@ -319,10 +428,11 @@ export const makeRpcClient = <
319
428
  Omit<
320
429
  & Omit<C, "invalidatesQueries">
321
430
  & Partial<InvalidationConfigForCommand<Resources, Payload, typeof ForceVoid, ErrorResult<C>>>,
322
- "success" | "error"
431
+ "success" | "error" | "stream"
323
432
  >,
324
433
  ModuleName,
325
434
  Type,
435
+ false,
326
436
  Resources
327
437
  >
328
438
  <Tag extends string, Payload extends S.Struct.Fields>(
@@ -336,7 +446,8 @@ export const makeRpcClient = <
336
446
  ErrorResult<{}>,
337
447
  Record<string, never>,
338
448
  ModuleName,
339
- Type
449
+ Type,
450
+ false
340
451
  >
341
452
  } {
342
453
  return (<Tag extends string, Fields extends S.Struct.Fields, C extends ServiceMap>(
@@ -345,9 +456,10 @@ export const makeRpcClient = <
345
456
  config?: C,
346
457
  invalidatesQueries?: InvalidationCallback<Resources>
347
458
  ) => {
459
+ const isStream = (config as any)?.stream === true
348
460
  const requestConfig = invalidatesQueries === undefined ? config : { ...config, invalidatesQueries }
349
461
  const cls = makeRequestClass(tag, fields, requestConfig)
350
- Object.assign(cls, { id: `${moduleName}.${tag}`, moduleName, type })
462
+ Object.assign(cls, { id: `${moduleName}.${tag}`, moduleName, type, stream: isStream })
351
463
  return cls
352
464
  }) as any
353
465
  }
@@ -357,26 +469,21 @@ export const makeRpcClient = <
357
469
  function TaggedRequestFor<ModuleName extends string>(moduleName: ModuleName) {
358
470
  const Query = makeTaggedRequestWithMeta(moduleName, "query")
359
471
  const Command = makeTaggedRequestWithMeta(moduleName, "command")
360
- const Stream = makeTaggedRequestWithMeta(moduleName, "stream")
361
472
 
362
473
  return {
363
474
  moduleName,
364
475
  /**
365
476
  * Create query request classes for this module.
366
477
  * Queries read state and should not mutate server state.
478
+ * Pass `stream: true` in the config to produce a Stream of `success` values (QueryStream behaviour).
367
479
  */
368
480
  Query,
369
481
  /**
370
482
  * Create command request classes for this module.
371
483
  * Commands mutate state and should avoid returning complex read models.
484
+ * Pass `stream: true` in the config to produce a Stream of `success` values (CommandStream behaviour).
372
485
  */
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
486
+ Command
380
487
  } as const
381
488
  }
382
489
 
@@ -1 +1 @@
1
- {"version":3,"file":"rpc.test.d.ts","sourceRoot":"","sources":["../rpc.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAErF,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;;;;;;;;;;;;;;;;;;;;;;;;AAE7C,qBAAa,iBAAkB,SAAQ,sBAIrC;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKL,qBAAa,KAAM,SAAQ,UAQzB;CAAG"}
1
+ {"version":3,"file":"rpc.test.d.ts","sourceRoot":"","sources":["../rpc.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAErF,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;;;;;;;;;;;;;;;;;;;;;;;;AAE7C,qBAAa,iBAAkB,SAAQ,sBAIrC;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKL,qBAAa,KAAM,SAAQ,UAQzB;CAAG"}