effect-app 3.16.0 → 4.0.0-beta.1

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 (174) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/Array.js +1 -1
  3. package/dist/Chunk.d.ts +2 -4
  4. package/dist/Chunk.d.ts.map +1 -1
  5. package/dist/Chunk.js +2 -2
  6. package/dist/Config/SecretURL.d.ts +2 -12
  7. package/dist/Config/SecretURL.d.ts.map +1 -1
  8. package/dist/Config/SecretURL.js +2 -4
  9. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  10. package/dist/Config/internal/configSecretURL.js +3 -4
  11. package/dist/Effect.d.ts +12 -10
  12. package/dist/Effect.d.ts.map +1 -1
  13. package/dist/Effect.js +6 -15
  14. package/dist/Layer.d.ts +15 -9
  15. package/dist/Layer.d.ts.map +1 -1
  16. package/dist/Layer.js +2 -2
  17. package/dist/Operations.d.ts +37 -47
  18. package/dist/Operations.d.ts.map +1 -1
  19. package/dist/Option.js +3 -3
  20. package/dist/Pure.d.ts +17 -6
  21. package/dist/Pure.d.ts.map +1 -1
  22. package/dist/Pure.js +35 -17
  23. package/dist/Schema/Class.d.ts +13 -16
  24. package/dist/Schema/Class.d.ts.map +1 -1
  25. package/dist/Schema/Class.js +5 -27
  26. package/dist/Schema/brand.d.ts +7 -10
  27. package/dist/Schema/brand.d.ts.map +1 -1
  28. package/dist/Schema/brand.js +3 -2
  29. package/dist/Schema/email.d.ts +1 -1
  30. package/dist/Schema/email.d.ts.map +1 -1
  31. package/dist/Schema/email.js +2 -2
  32. package/dist/Schema/ext.d.ts +42 -45
  33. package/dist/Schema/ext.d.ts.map +1 -1
  34. package/dist/Schema/ext.js +49 -63
  35. package/dist/Schema/moreStrings.d.ts +17 -17
  36. package/dist/Schema/moreStrings.d.ts.map +1 -1
  37. package/dist/Schema/moreStrings.js +10 -10
  38. package/dist/Schema/numbers.d.ts +14 -14
  39. package/dist/Schema/numbers.js +5 -5
  40. package/dist/Schema/phoneNumber.d.ts +1 -1
  41. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  42. package/dist/Schema/phoneNumber.js +2 -2
  43. package/dist/Schema/schema.d.ts +2 -3
  44. package/dist/Schema/schema.d.ts.map +1 -1
  45. package/dist/Schema/schema.js +3 -4
  46. package/dist/Schema/strings.d.ts +4 -4
  47. package/dist/Schema/strings.d.ts.map +1 -1
  48. package/dist/Schema/strings.js +4 -4
  49. package/dist/Schema.d.ts +27 -25
  50. package/dist/Schema.d.ts.map +1 -1
  51. package/dist/Schema.js +22 -21
  52. package/dist/ServiceMap.d.ts +44 -0
  53. package/dist/ServiceMap.d.ts.map +1 -0
  54. package/dist/ServiceMap.js +91 -0
  55. package/dist/Set.d.ts +4 -4
  56. package/dist/Set.d.ts.map +1 -1
  57. package/dist/Set.js +14 -14
  58. package/dist/Struct.d.ts +4 -4
  59. package/dist/Struct.d.ts.map +1 -1
  60. package/dist/_ext/Array.d.ts.map +1 -1
  61. package/dist/_ext/Array.js +4 -4
  62. package/dist/_ext/misc.d.ts +2 -2
  63. package/dist/_ext/misc.js +4 -4
  64. package/dist/_ext/ord.ext.js +2 -2
  65. package/dist/builtin.d.ts +0 -8
  66. package/dist/builtin.d.ts.map +1 -1
  67. package/dist/builtin.js +3 -1
  68. package/dist/client/apiClientFactory.d.ts +14 -16
  69. package/dist/client/apiClientFactory.d.ts.map +1 -1
  70. package/dist/client/apiClientFactory.js +38 -23
  71. package/dist/client/clientFor.d.ts +7 -4
  72. package/dist/client/clientFor.d.ts.map +1 -1
  73. package/dist/client/errors.d.ts +36 -48
  74. package/dist/client/errors.d.ts.map +1 -1
  75. package/dist/client/errors.js +19 -9
  76. package/dist/client/makeClient.d.ts +34 -50
  77. package/dist/client/makeClient.d.ts.map +1 -1
  78. package/dist/client/makeClient.js +28 -18
  79. package/dist/http/Request.d.ts +3 -3
  80. package/dist/http/Request.d.ts.map +1 -1
  81. package/dist/http/Request.js +5 -8
  82. package/dist/http/internal/lib.d.ts +12 -13
  83. package/dist/http/internal/lib.d.ts.map +1 -1
  84. package/dist/http/internal/lib.js +14 -14
  85. package/dist/ids.d.ts +9 -9
  86. package/dist/ids.d.ts.map +1 -1
  87. package/dist/ids.js +1 -1
  88. package/dist/index.d.ts +7 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +8 -2
  91. package/dist/logger.d.ts +1 -1
  92. package/dist/middleware.d.ts +2 -2
  93. package/dist/middleware.d.ts.map +1 -1
  94. package/dist/middleware.js +3 -3
  95. package/dist/rpc/MiddlewareMaker.d.ts +17 -16
  96. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  97. package/dist/rpc/MiddlewareMaker.js +27 -18
  98. package/dist/rpc/RpcContextMap.d.ts +4 -4
  99. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  100. package/dist/rpc/RpcContextMap.js +4 -4
  101. package/dist/rpc/RpcMiddleware.d.ts +24 -40
  102. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  103. package/dist/rpc/RpcMiddleware.js +3 -10
  104. package/dist/utils/effectify.js +2 -2
  105. package/dist/utils/gen.d.ts +4 -5
  106. package/dist/utils/gen.d.ts.map +1 -1
  107. package/dist/utils/logLevel.d.ts +1 -1
  108. package/dist/utils/logLevel.d.ts.map +1 -1
  109. package/dist/utils/logLevel.js +6 -7
  110. package/dist/utils/logger.d.ts +4 -3
  111. package/dist/utils/logger.d.ts.map +1 -1
  112. package/dist/utils/logger.js +10 -9
  113. package/dist/utils.d.ts +4 -5
  114. package/dist/utils.d.ts.map +1 -1
  115. package/dist/utils.js +10 -9
  116. package/package.json +12 -21
  117. package/src/Array.ts +1 -1
  118. package/src/Chunk.ts +2 -2
  119. package/src/Config/SecretURL.ts +3 -18
  120. package/src/Config/internal/configSecretURL.ts +2 -3
  121. package/src/Effect.ts +17 -37
  122. package/src/Layer.ts +16 -11
  123. package/src/Option.ts +2 -2
  124. package/src/Pure.ts +60 -26
  125. package/src/Schema/Class.ts +17 -73
  126. package/src/Schema/brand.ts +11 -12
  127. package/src/Schema/email.ts +2 -2
  128. package/src/Schema/ext.ts +114 -167
  129. package/src/Schema/moreStrings.ts +20 -23
  130. package/src/Schema/numbers.ts +4 -4
  131. package/src/Schema/phoneNumber.ts +2 -2
  132. package/src/Schema/schema.ts +2 -3
  133. package/src/Schema/strings.ts +3 -3
  134. package/src/Schema.ts +49 -47
  135. package/src/ServiceMap.ts +187 -0
  136. package/src/Set.ts +19 -19
  137. package/src/Struct.ts +4 -4
  138. package/src/_ext/Array.ts +4 -5
  139. package/src/_ext/misc.ts +4 -4
  140. package/src/_ext/ord.ext.ts +2 -2
  141. package/src/builtin.ts +2 -8
  142. package/src/client/apiClientFactory.ts +74 -59
  143. package/src/client/clientFor.ts +10 -7
  144. package/src/client/errors.ts +28 -22
  145. package/src/client/makeClient.ts +75 -100
  146. package/src/http/Request.ts +5 -8
  147. package/src/http/internal/lib.ts +13 -13
  148. package/src/ids.ts +1 -1
  149. package/src/index.ts +10 -1
  150. package/src/middleware.ts +2 -2
  151. package/src/rpc/MiddlewareMaker.ts +76 -47
  152. package/src/rpc/RpcContextMap.ts +7 -7
  153. package/src/rpc/RpcMiddleware.ts +28 -54
  154. package/src/utils/effectify.ts +1 -1
  155. package/src/utils/gen.ts +8 -6
  156. package/src/utils/logLevel.ts +6 -6
  157. package/src/utils/logger.ts +15 -20
  158. package/src/utils.ts +12 -12
  159. package/test/dist/rpc.test.d.ts.map +1 -1
  160. package/test/schema.test.ts +8 -8
  161. package/test/utils.test.ts +2 -2
  162. package/tsconfig.json +1 -27
  163. package/dist/Context.d.ts +0 -67
  164. package/dist/Context.d.ts.map +0 -1
  165. package/dist/Context.js +0 -207
  166. package/dist/Tag.d.ts +0 -6
  167. package/dist/Tag.d.ts.map +0 -1
  168. package/dist/Tag.js +0 -9
  169. package/dist/Unify.d.ts +0 -27
  170. package/dist/Unify.d.ts.map +0 -1
  171. package/dist/Unify.js +0 -15
  172. package/src/Context.ts +0 -351
  173. package/src/Tag.ts +0 -11
  174. package/src/Unify.ts +0 -40
@@ -1,45 +1,46 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "@effect/rpc"
3
2
  import * as Config from "effect/Config"
4
3
  import { flow } from "effect/Function"
5
- import * as HashMap from "effect/HashMap"
6
4
  import * as Layer from "effect/Layer"
7
5
  import * as ManagedRuntime from "effect/ManagedRuntime"
8
6
  import * as Predicate from "effect/Predicate"
7
+ import * as Schema from "effect/Schema"
9
8
  import * as Struct from "effect/Struct"
10
- import * as Context from "../Context.js"
9
+ import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/unstable/rpc"
11
10
  import * as Effect from "../Effect.js"
12
11
  import { HttpClient, HttpClientRequest } from "../http.js"
13
12
  import * as Option from "../Option.js"
14
13
  import type * as S from "../Schema.js"
14
+ import * as ServiceMap from "../ServiceMap.js"
15
15
  import { typedKeysOf, typedValuesOf } from "../utils.js"
16
16
  import type { Client, ClientForOptions, Requests, RequestsAny } from "./clientFor.js"
17
17
 
18
18
  export interface ApiConfig {
19
19
  url: string
20
- headers: Option.Option<HashMap.HashMap<string, string>>
20
+ headers: Option.Option<Record<string, string>>
21
21
  }
22
22
 
23
23
  export const DefaultApiConfig = Config.all({
24
24
  url: Config.string("apiUrl").pipe(Config.withDefault("/api")),
25
25
  headers: Config
26
- .hashMap(
27
- Config.string(),
26
+ .schema(
27
+ Config.Record(Schema.String, Schema.String),
28
28
  "headers"
29
29
  )
30
30
  .pipe(Config.option)
31
31
  })
32
32
 
33
- export type Req = S.Schema.All & {
33
+ export type Req = S.Top & {
34
34
  new(...args: any[]): any
35
35
  _tag: string
36
36
  fields: S.Struct.Fields
37
- success: S.Schema.All
38
- failure: S.Schema.All
37
+ success: S.Top
38
+ error: S.Top
39
39
  config?: Record<string, any>
40
+ readonly "~decodingServices"?: unknown
40
41
  }
41
42
 
42
- class RequestName extends Context.Reference<RequestName>()("RequestName", {
43
+ class RequestName extends ServiceMap.Reference("RequestName", {
43
44
  defaultValue: () => ({ requestName: "Unspecified", moduleName: "Error" })
44
45
  }) {}
45
46
 
@@ -49,29 +50,28 @@ export const HttpClientLayer = (config: ApiConfig) =>
49
50
  Effect
50
51
  .gen(function*() {
51
52
  const baseClient = yield* HttpClient.HttpClient
53
+ const ctx = yield* RequestName
52
54
  const client = baseClient.pipe(
53
55
  HttpClient.mapRequest(HttpClientRequest.prependUrl(config.url + "/rpc")),
54
56
  HttpClient.mapRequest(
55
- HttpClientRequest.setHeaders(config.headers.pipe(Option.getOrElse(() => HashMap.empty())))
57
+ HttpClientRequest.setHeaders(config.headers.pipe(Option.getOrElse(() => ({}))))
56
58
  ),
57
- HttpClient.mapRequestEffect((req) =>
58
- RequestName.pipe(
59
- Effect.map((ctx) =>
60
- flow(
61
- HttpClientRequest.appendUrlParam("action", ctx.requestName),
62
- HttpClientRequest.appendUrl("/" + ctx.moduleName)
63
- )(req)
64
- )
65
- )
59
+ HttpClient.mapRequest((req) =>
60
+ flow(
61
+ HttpClientRequest.appendUrlParam("action", ctx.requestName),
62
+ HttpClientRequest.appendUrl("/" + ctx.moduleName)
63
+ )(req)
66
64
  )
67
65
  )
68
66
  return client
69
67
  })
70
68
  )
71
69
 
72
- export const HttpClientFromConfigLayer = DefaultApiConfig.pipe(
73
- Effect.map(HttpClientLayer),
74
- Layer.unwrapEffect
70
+ export const HttpClientFromConfigLayer = Layer.unwrap(
71
+ Effect.gen(function*() {
72
+ const config = yield* DefaultApiConfig
73
+ return HttpClientLayer(config)
74
+ })
75
75
  )
76
76
 
77
77
  export const RpcSerializationLayer = (config: ApiConfig) =>
@@ -81,7 +81,7 @@ export const RpcSerializationLayer = (config: ApiConfig) =>
81
81
  )
82
82
 
83
83
  type RpcHandlers<M extends RequestsAny> = {
84
- [K in keyof M]: Rpc.Rpc<M[K]["_tag"], M[K], M[K]["success"], M[K]["failure"]>
84
+ [K in keyof M]: Rpc.Rpc<M[K]["_tag"], M[K], M[K]["success"], M[K]["error"]>
85
85
  }
86
86
 
87
87
  const getFiltered = <M extends Requests>(resource: M) => {
@@ -94,7 +94,7 @@ const getFiltered = <M extends Requests>(resource: M) => {
94
94
  Predicate.isObject(resource[cur])
95
95
  && (resource[cur].success)
96
96
  ) {
97
- acc[cur as keyof Filtered] = resource[cur]
97
+ acc[cur as keyof Filtered] = resource[cur] as any
98
98
  }
99
99
  return acc
100
100
  }, {} as Record<keyof Filtered, Req>)
@@ -117,7 +117,7 @@ export const makeRpcGroupFromRequestsAndModuleName = <M extends Requests, const
117
117
  const rpcs = RpcGroup
118
118
  .make(
119
119
  ...typedValuesOf(filtered).map((_) => {
120
- return Rpc.fromTaggedRequest(_ as any)
120
+ return Rpc.make((_ as any)._tag, { payload: _ as any, success: (_ as any).success, error: (_ as any).error })
121
121
  })
122
122
  )
123
123
  .prefix(`${moduleName}.`) as unknown as RpcGroup.RpcGroup<
@@ -137,23 +137,26 @@ const makeRpcTag = <M extends Requests>(resource: M) => {
137
137
  const meta = getMeta(resource)
138
138
  const rpcs = makeRpcGroupFromRequestsAndModuleName(resource, meta.moduleName)
139
139
 
140
- return class TheClient extends Context.Tag(`RpcClient.${meta.moduleName}`)<
141
- TheClient,
140
+ // Use Object.assign instead of class extension to avoid TS2509 with complex generic return types.
141
+ // The first type arg is `any` because this is a dynamically created tag — its identity is the string key.
142
+ const TheClient = ServiceMap.Opaque<
143
+ any,
142
144
  RpcClient.RpcClient<RpcGroup.Rpcs<typeof rpcs>>
143
- >() {
144
- static layer = Layer.scoped(
145
- TheClient,
146
- Effect.map(
147
- RpcClient.make(rpcs, { spanPrefix: "RpcClient." + meta.moduleName }),
148
- (cl) => (cl as any)[meta.moduleName]
149
- )
145
+ >()(`RpcClient.${meta.moduleName}`)
146
+ // Use Layer.effect directly (not TheClient.toLayer) so TypeScript properly excludes Scope
147
+ const layer = Layer.effect(
148
+ TheClient,
149
+ Effect.map(
150
+ RpcClient.make(rpcs, { spanPrefix: "RpcClient." + meta.moduleName }),
151
+ (cl) => (cl as any)[meta.moduleName]
150
152
  )
151
- }
153
+ )
154
+ return Object.assign(TheClient, { layer })
152
155
  }
153
156
 
154
157
  const makeApiClientFactory = Effect
155
158
  .gen(function*() {
156
- const ctx = yield* Effect.context<RpcSerialization.RpcSerialization | HttpClient.HttpClient>()
159
+ const ctx = yield* Effect.services<RpcSerialization.RpcSerialization | HttpClient.HttpClient>()
157
160
  const makeClientFor = <M extends Requests>(
158
161
  resource: M,
159
162
  requestLevelLayers = Layer.empty,
@@ -176,7 +179,7 @@ const makeApiClientFactory = Effect
176
179
  url: "" // why not here set meta.moduleName as root?
177
180
  })
178
181
  .pipe(
179
- Layer.provideMerge(Layer.succeedContext(ctx))
182
+ Layer.provideMerge(Layer.succeedServices(ctx))
180
183
  )
181
184
  )
182
185
  )
@@ -207,28 +210,36 @@ const makeApiClientFactory = Effect
207
210
 
208
211
  const layers = requestLevelLayers.pipe(Layer.provideMerge(requestNameLayer))
209
212
 
210
- const fields = Struct.omit(Request.fields, "_tag")
213
+ const fields = Struct.omit(Request.fields, ["_tag"] as const)
211
214
  const requestAttr = h._tag
212
215
  // @ts-expect-error doc
213
216
  prev[cur] = Object.keys(fields).length === 0
214
217
  ? {
215
- handler: TheClient.pipe(
216
- Effect.flatMap((client) =>
217
- (client as any)[requestAttr]!(new Request()) as Effect.Effect<any, any, never>
218
- ),
219
- Effect.provide(layers),
220
- Effect.provide(mr)
218
+ handler: mr.servicesEffect.pipe(
219
+ Effect.flatMap((svcs) =>
220
+ TheClient
221
+ .use((client) => (client as any)[requestAttr]!(new Request()) as Effect.Effect<any, any, never>)
222
+ .pipe(
223
+ Effect.provide(layers),
224
+ Effect.provide(svcs)
225
+ )
226
+ )
221
227
  ),
222
228
  ...requestMeta
223
229
  }
224
230
  : {
225
231
  handler: (req: any) =>
226
- TheClient.pipe(
227
- Effect.flatMap((client) =>
228
- (client as any)[requestAttr]!(new Request(req)) as Effect.Effect<any, any, never>
229
- ),
230
- Effect.provide(layers),
231
- Effect.provide(mr)
232
+ mr.servicesEffect.pipe(
233
+ Effect.flatMap((svcs) =>
234
+ TheClient
235
+ .use((client) =>
236
+ (client as any)[requestAttr]!(new Request(req)) as Effect.Effect<any, any, never>
237
+ )
238
+ .pipe(
239
+ Effect.provide(layers),
240
+ Effect.provide(svcs)
241
+ )
242
+ )
232
243
  ),
233
244
 
234
245
  ...requestMeta
@@ -273,20 +284,24 @@ const makeApiClientFactory = Effect
273
284
  * Used to create clients for resource modules.
274
285
  */
275
286
  export class ApiClientFactory
276
- extends Context.TagId("ApiClientFactory")<ApiClientFactory, Effect.Effect.Success<typeof makeApiClientFactory>>()
287
+ extends ServiceMap.Opaque<ApiClientFactory, Effect.Success<typeof makeApiClientFactory>>()("ApiClientFactory")
277
288
  {
278
289
  static readonly layer = (config: ApiConfig) =>
279
- this.toLayerScoped(makeApiClientFactory).pipe(Layer.provide(RpcSerializationLayer(config)))
280
- static readonly layerFromConfig = DefaultApiConfig.pipe(Effect.map(this.layer), Layer.unwrapEffect)
290
+ ApiClientFactory.toLayer(makeApiClientFactory).pipe(Layer.provide(RpcSerializationLayer(config)))
291
+ static readonly layerFromConfig = Layer.unwrap(
292
+ Effect.gen(function*() {
293
+ const config = yield* DefaultApiConfig
294
+ return ApiClientFactory.layer(config)
295
+ })
296
+ )
281
297
 
282
298
  static readonly makeFor =
283
299
  (requestLevelLayers: Layer.Layer<never, never, never>, options?: ClientForOptions) =>
284
300
  <M extends Requests>(
285
301
  resource: M
286
302
  ) =>
287
- this
288
- .use((apiClientFactory) => apiClientFactory(requestLevelLayers, options))
289
- .pipe(
290
- Effect.flatMap((f) => f(resource))
291
- ) // don't rename f to clientFor or integration in vue project linked fucks up
303
+ ApiClientFactory.use((apiClientFactory) => {
304
+ const f = apiClientFactory(requestLevelLayers, options)
305
+ return f(resource)
306
+ })
292
307
  }
@@ -58,18 +58,19 @@ export type Client<M extends RequestsAny, ModuleName extends string> = RequestHa
58
58
  ModuleName
59
59
  >
60
60
 
61
- export type ExtractResponse<T> = T extends S.Schema<any, any, any> ? S.Schema.Type<T>
61
+ export type ExtractResponse<T> = T extends S.Schema<any> ? S.Schema.Type<T>
62
62
  : T extends unknown ? void
63
63
  : never
64
64
 
65
- export type ExtractEResponse<T> = T extends S.Schema<any, any, any> ? S.Schema.Encoded<T>
65
+ export type ExtractEResponse<T> = T extends S.Schema<any> ? S.Codec.Encoded<T>
66
66
  : T extends unknown ? void
67
67
  : never
68
68
 
69
69
  type IsEmpty<T> = keyof T extends never ? true
70
70
  : false
71
71
 
72
- type Cruft = "_tag" | Request.RequestTypeId | typeof S.symbolSerializable | typeof S.symbolWithResult
72
+ // v4: Request.RequestTypeId, S.symbolSerializable, S.symbolWithResult removed — use keyof Request to filter internal props
73
+ type Cruft = "_tag" | keyof Request.Request<any, any, any>
73
74
 
74
75
  export interface ClientForOptions {
75
76
  readonly skipQueryKey?: readonly string[]
@@ -90,20 +91,22 @@ export interface RequestHandlerWithInput<I, A, E, R, Request extends Req, Id ext
90
91
  }
91
92
 
92
93
  // make sure this is exported or d.ts of apiClientFactory breaks?!
94
+ type ReqDecodingServices<M> = M extends { readonly "~decodingServices": infer DS } ? DS : never
95
+
93
96
  export type RequestHandlers<R, E, M extends RequestsAny, ModuleName extends string> = {
94
97
  [K in keyof M as M[K] extends Req ? K : never]: IsEmpty<Omit<S.Schema.Type<M[K]>, Cruft>> extends true
95
98
  ? RequestHandler<
96
99
  S.Schema.Type<M[K]["success"]>,
97
- S.Schema.Type<M[K]["failure"]> | E,
98
- R | S.Schema.Context<M[K]["success"]> | S.Schema.Context<M[K]["failure"]>,
100
+ S.Schema.Type<M[K]["error"]> | E,
101
+ R | ReqDecodingServices<M[K]>,
99
102
  M[K],
100
103
  `${ModuleName}.${K & string}`
101
104
  >
102
105
  : RequestHandlerWithInput<
103
106
  Omit<S.Schema.Type<M[K]>, Cruft>,
104
107
  S.Schema.Type<M[K]["success"]>,
105
- S.Schema.Type<M[K]["failure"]> | E,
106
- R | S.Schema.Context<M[K]["success"]> | S.Schema.Context<M[K]["failure"]>,
108
+ S.Schema.Type<M[K]["error"]> | E,
109
+ R | ReqDecodingServices<M[K]>,
107
110
  M[K],
108
111
  `${ModuleName}.${K & string}`
109
112
  >
@@ -1,7 +1,6 @@
1
1
  /** @effect-diagnostics overriddenSchemaConstructor:skip-file */
2
2
  import { TaggedError } from "effect-app/Schema"
3
3
  import * as Cause from "effect/Cause"
4
- import { makeFiberFailure } from "effect/Runtime"
5
4
  import * as S from "../Schema.js"
6
5
 
7
6
  export const tryToJson = (error: { toJSON(): unknown; toString(): string }) => {
@@ -27,13 +26,13 @@ export class NotFoundError<ItemType = string> extends TaggedError<NotFoundError<
27
26
  id: S.Unknown
28
27
  }) {
29
28
  constructor(
30
- props: S.Struct.Constructor<typeof NotFoundError.fields> & { cause?: unknown },
29
+ props: { type: string; id: unknown; cause?: unknown },
31
30
  disableValidation?: boolean
32
31
  ) {
33
- super(props, disableValidation)
32
+ super(props as any, disableValidation as any)
34
33
  }
35
34
  override get message() {
36
- return `Didn't find ${this.type}#${JSON.stringify(this.id)}`
35
+ return `Didn't find ${(this as any).type}#${JSON.stringify((this as any).id)}`
37
36
  }
38
37
  }
39
38
 
@@ -44,7 +43,7 @@ export class InvalidStateError extends TaggedError<InvalidStateError>()("Invalid
44
43
  message: S.String
45
44
  }) {
46
45
  constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
47
- super(typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject }, disableValidation)
46
+ super(typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject } as any, disableValidation as any)
48
47
  }
49
48
  }
50
49
 
@@ -52,7 +51,7 @@ export class ServiceUnavailableError extends TaggedError<ServiceUnavailableError
52
51
  message: S.String
53
52
  }) {
54
53
  constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
55
- super(typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject }, disableValidation)
54
+ super(typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject } as any, disableValidation as any)
56
55
  }
57
56
  }
58
57
 
@@ -60,13 +59,13 @@ export class ValidationError extends TaggedError<ValidationError>()("ValidationE
60
59
  errors: S.Array(S.Unknown)
61
60
  }) {
62
61
  constructor(
63
- props: S.Struct.Constructor<typeof ValidationError.fields> & { cause?: unknown },
62
+ props: { errors: ReadonlyArray<unknown>; cause?: unknown },
64
63
  disableValidation?: boolean
65
64
  ) {
66
- super(props, disableValidation)
65
+ super(props as any, disableValidation as any)
67
66
  }
68
67
  override get message() {
69
- return `Validation failed: ${this.errors.map((e) => JSON.stringify(e, undefined, 2)).join(",\n")}`
68
+ return `Validation failed: ${(this as any).errors.map((e: any) => JSON.stringify(e, undefined, 2)).join(",\n")}`
70
69
  }
71
70
  }
72
71
 
@@ -74,7 +73,7 @@ export class NotLoggedInError extends TaggedError<NotLoggedInError>()("NotLogged
74
73
  message: S.String
75
74
  }) {
76
75
  constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
77
- super(messageFallback(messageOrObject), disableValidation)
76
+ super(messageFallback(messageOrObject) as any, disableValidation as any)
78
77
  }
79
78
  }
80
79
 
@@ -85,7 +84,7 @@ export class LoginError extends TaggedError<LoginError>()("NotLoggedInError", {
85
84
  message: S.String
86
85
  }) {
87
86
  constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
88
- super(messageFallback(messageOrObject), disableValidation)
87
+ super(messageFallback(messageOrObject) as any, disableValidation as any)
89
88
  }
90
89
  }
91
90
 
@@ -93,7 +92,7 @@ export class UnauthorizedError extends TaggedError<UnauthorizedError>()("Unautho
93
92
  message: S.String
94
93
  }) {
95
94
  constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
96
- super(messageFallback(messageOrObject), disableValidation)
95
+ super(messageFallback(messageOrObject) as any, disableValidation as any)
97
96
  }
98
97
  }
99
98
 
@@ -114,10 +113,10 @@ export class OptimisticConcurrencyException extends TaggedError<OptimisticConcur
114
113
  constructor(
115
114
  args:
116
115
  | OptimisticConcurrencyDetails
117
- | (S.Struct.Constructor<typeof OptimisticConcurrencyException.fields> & { cause?: unknown; raw?: unknown }),
116
+ | ({ message: string; cause?: unknown; raw?: unknown }),
118
117
  disableValidation?: boolean
119
118
  ) {
120
- super("message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` }, disableValidation)
119
+ super("message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` } as any, disableValidation as any)
121
120
  if (!("message" in args)) {
122
121
  this.details = args
123
122
  }
@@ -138,10 +137,10 @@ const GeneralErrors = [
138
137
  ServiceUnavailableError
139
138
  ] as const
140
139
 
141
- export const SupportedErrors = S.Union(
140
+ export const SupportedErrors = S.Union([
142
141
  ...MutationOnlyErrors,
143
142
  ...GeneralErrors
144
- )
143
+ ])
145
144
  // .pipe(named("SupportedErrors"))
146
145
  // .pipe(withDefaultMake)
147
146
  export type SupportedErrors = S.Schema.Type<typeof SupportedErrors>
@@ -175,11 +174,18 @@ export class CauseException<E> extends Error {
175
174
  Error.stackTraceLimit = 0
176
175
  super()
177
176
  Error.stackTraceLimit = limit
178
- const ff = makeFiberFailure(originalCause)
179
- this.name = ff.name
180
- this.message = ff.message
181
- if (ff.stack) {
182
- this.stack = ff.stack
177
+ // v4: makeFiberFailure removed — use Cause.prettyErrors instead
178
+ const errors = Cause.prettyErrors(originalCause)
179
+ const first = errors[0]
180
+ if (first) {
181
+ this.name = first.name
182
+ this.message = first.message
183
+ if (first.stack) {
184
+ this.stack = first.stack
185
+ }
186
+ } else {
187
+ this.name = "CauseException"
188
+ this.message = Cause.pretty(originalCause)
183
189
  }
184
190
  }
185
191
  toReport() {
@@ -203,7 +209,7 @@ export class CauseException<E> extends Error {
203
209
  return this.toJSON()
204
210
  }
205
211
  override toString() {
206
- return `[${this._tag}] ` + Cause.pretty(this.originalCause, { renderErrorCause: true })
212
+ return `[${this._tag}] ` + Cause.pretty(this.originalCause)
207
213
  }
208
214
  }
209
215
 
@@ -1,144 +1,119 @@
1
- import { type GetContextConfig, type GetEffectError, type RequestContextMapTagAny } from "../rpc/RpcContextMap.js"
1
+ import { type GetContextConfig, type RequestContextMapTagAny } from "../rpc/RpcContextMap.js"
2
2
  import * as S from "../Schema.js"
3
3
  import { AST } from "../Schema.js"
4
4
 
5
- // TODO: Fix error types... (?)
6
- type JoinSchema<T> = T extends ReadonlyArray<S.Schema.All> ? S.Union<T> : typeof S.Never
7
-
8
5
  const merge = (a: any, b: Array<any>) =>
9
- a !== undefined && b.length ? S.Union(a, ...b) : a !== undefined ? a : b.length ? S.Union(...b) : S.Never
10
-
11
- /**
12
- * Converts struct fields to TypeLiteral schema, or returns existing schema.
13
- *
14
- * @example
15
- * ```typescript
16
- * type Fields = { name: S.String; age: S.Number }
17
- * type Schema = SchemaOrFields<Fields>
18
- * // Result: S.TypeLiteral<Fields, []>
19
- *
20
- * type Existing = S.String
21
- * type Same = SchemaOrFields<Existing>
22
- * // Result: S.String
23
- * ```
24
- */
25
- type SchemaOrFields<T> = T extends S.Struct.Fields ? S.TypeLiteral<T, []> : T extends S.Schema.Any ? T : never
6
+ a !== undefined && b.length ? S.Union([a, ...b]) : a !== undefined ? a : b.length ? S.Union(b) : S.Never
26
7
 
27
8
  /**
28
9
  * Whatever the input, we will only decode or encode to void
29
10
  */
30
- const ForceVoid: S.Schema<void> = S.transform(S.Any, S.Void, { decode: () => void 0, encode: () => void 0 })
11
+ const ForceVoid: S.Schema<void> = S.Void as any
12
+
13
+ type SchemaOrFields<T> = T extends S.Top ? T : T extends S.Struct.Fields ? S.Struct<T> : S.Void
14
+
15
+ type TaggedRequestResult<
16
+ Tag extends string,
17
+ Payload extends S.Struct.Fields,
18
+ Success extends S.Top,
19
+ Error extends S.Top,
20
+ Config = Record<string, never>
21
+ > =
22
+ & S.TaggedStruct<Tag, Payload>
23
+ & {
24
+ new(...args: any[]): any
25
+ readonly _tag: Tag
26
+ readonly fields: { readonly _tag: S.tag<Tag> } & Payload
27
+ readonly success: Success
28
+ readonly error: Error
29
+ readonly config: Config
30
+ readonly "~decodingServices": S.Codec.DecodingServices<Success> | S.Codec.DecodingServices<Error>
31
+ }
31
32
 
32
33
  export const makeRpcClient = <
33
34
  RequestContextMap extends RequestContextMapTagAny,
34
- GeneralErrors extends S.Schema.All = never
35
+ GeneralErrors extends S.Top = never
35
36
  >(rcs: RequestContextMap, generalErrors?: GeneralErrors) => {
36
- // Long way around Context/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??)
37
- type Context = {
38
- success: S.Schema.Any | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
39
- failure: S.Schema.Any | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
37
+ // Long way around ServiceMap/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??)
38
+ type ServiceMap = {
39
+ success: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
40
+ error: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields
40
41
  }
41
42
 
42
43
  type RequestConfig = GetContextConfig<RequestContextMap["config"]>
43
44
 
44
- function TaggedRequest<Self>(): {
45
- <Tag extends string, Payload extends S.Struct.Fields, C extends Context>(
45
+ type MergeError<E> = [GeneralErrors] extends [never] ? SchemaOrFields<E> : S.Union<[SchemaOrFields<E>, GeneralErrors]>
46
+ type ErrorResult<C> = C extends { error: infer E } ? MergeError<E>
47
+ : [GeneralErrors] extends [never] ? S.Void
48
+ : GeneralErrors
49
+
50
+ function TaggedRequest<_Self>(): {
51
+ <Tag extends string, Payload extends S.Struct.Fields, C extends ServiceMap>(
46
52
  tag: Tag,
47
53
  fields: Payload,
48
54
  config: RequestConfig & C
49
- ):
50
- & S.TaggedRequestClass<
51
- Self,
52
- Tag,
53
- { readonly _tag: S.tag<Tag> } & Payload,
54
- SchemaOrFields<typeof config["success"]>,
55
- JoinSchema<
56
- [SchemaOrFields<typeof config["failure"]> | GetEffectError<RequestContextMap["config"], C> | GeneralErrors]
57
- >
58
- >
59
- & { config: Omit<C, "success" | "failure"> }
60
- <Tag extends string, Payload extends S.Struct.Fields, C extends Pick<Context, "success">>(
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">>(
61
57
  tag: Tag,
62
58
  fields: Payload,
63
59
  config: RequestConfig & C
64
- ):
65
- & S.TaggedRequestClass<
66
- Self,
67
- Tag,
68
- { readonly _tag: S.tag<Tag> } & Payload,
69
- SchemaOrFields<typeof config["success"]>,
70
- JoinSchema<[GetEffectError<RequestContextMap["config"], C> | GeneralErrors]>
71
- >
72
- & { config: Omit<C, "success" | "failure"> }
73
- <Tag extends string, Payload extends S.Struct.Fields, C extends Pick<Context, "failure">>(
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">>(
74
62
  tag: Tag,
75
63
  fields: Payload,
76
64
  config: RequestConfig & C
77
- ):
78
- & S.TaggedRequestClass<
79
- Self,
80
- Tag,
81
- { readonly _tag: S.tag<Tag> } & Payload,
82
- typeof S.Void,
83
- JoinSchema<
84
- [SchemaOrFields<typeof config["failure"]> | GetEffectError<RequestContextMap["config"], C> | GeneralErrors]
85
- >
86
- >
87
- & { config: Omit<C, "success" | "failure"> }
65
+ ): TaggedRequestResult<Tag, Payload, S.Schema<void>, ErrorResult<C>, Omit<C, "success" | "error">>
88
66
  <Tag extends string, Payload extends S.Struct.Fields, C extends Record<string, any>>(
89
67
  tag: Tag,
90
68
  fields: Payload,
91
69
  config: C & RequestConfig
92
- ):
93
- & S.TaggedRequestClass<
94
- Self,
95
- Tag,
96
- { readonly _tag: S.tag<Tag> } & Payload,
97
- typeof S.Void,
98
- JoinSchema<[GetEffectError<RequestContextMap["config"], C> | GeneralErrors]>
99
- >
100
- & { config: Omit<C, "success" | "failure"> }
70
+ ): TaggedRequestResult<Tag, Payload, S.Schema<void>, ErrorResult<C>, Omit<C, "success" | "error">>
101
71
  <Tag extends string, Payload extends S.Struct.Fields>(
102
72
  tag: Tag,
103
73
  fields: Payload
104
- ):
105
- & S.TaggedRequestClass<
106
- Self,
107
- Tag,
108
- { readonly _tag: S.tag<Tag> } & Payload,
109
- typeof S.Void,
110
- GeneralErrors extends never ? typeof S.Never : GeneralErrors
111
- >
112
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
113
- & { config: {} }
74
+ ): TaggedRequestResult<Tag, Payload, S.Schema<void>, ErrorResult<never>, Record<string, never>>
114
75
  } {
115
76
  // TODO: filter errors based on config + take care of inversion
116
77
  const errorSchemas = Object.values(rcs.config).map((_) => _.error)
117
- return (<Tag extends string, Fields extends S.Struct.Fields, C extends Context>(
78
+ return (<Tag extends string, Fields extends S.Struct.Fields, C extends ServiceMap>(
118
79
  tag: Tag,
119
80
  fields: Fields,
120
81
  config?: C
121
82
  ) => {
122
- // S.TaggedRequest is a factory function that creates a TaggedRequest class
123
- const req = S.TaggedRequest<Self>()(tag, {
124
- payload: fields,
125
- // ensure both failure and success are schemas
126
- failure: merge(
127
- config?.failure ? S.isSchema(config.failure) ? config.failure : S.Struct(config.failure) : undefined,
128
- [...errorSchemas, generalErrors].filter(Boolean)
129
- ),
130
- success: config?.success
131
- ? S.isSchema(config.success)
132
- ? AST.isVoidKeyword(config.success.ast) ? ForceVoid : config.success
133
- : S.Struct(config.success)
134
- : ForceVoid
135
- })
136
- return class extends (Object.assign(req, { config }) as any) {
137
- constructor(payload: any, disableValidation: any = true) {
138
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
139
- super(payload, disableValidation)
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 payloadSchema = S.Struct({ _tag: S.tag(tag), ...fields })
96
+
97
+ const taggedFields = { _tag: S.tag(tag), ...fields }
98
+
99
+ const RequestClass = class {
100
+ constructor(payload?: any) {
101
+ if (payload) {
102
+ Object.assign(this, payload)
103
+ }
104
+ ;(this as any)._tag = tag
140
105
  }
141
106
  }
107
+
108
+ Object.assign(RequestClass, payloadSchema, {
109
+ _tag: tag,
110
+ fields: taggedFields,
111
+ success: successSchema,
112
+ error: failureSchema,
113
+ config
114
+ })
115
+
116
+ return RequestClass
142
117
  }) as any
143
118
  }
144
119