effect-app 4.0.0-beta.13 → 4.0.0-beta.131

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 (139) hide show
  1. package/CHANGELOG.md +503 -0
  2. package/dist/Config/SecretURL.js +2 -2
  3. package/dist/Config.d.ts +7 -0
  4. package/dist/Config.d.ts.map +1 -0
  5. package/dist/Config.js +6 -0
  6. package/dist/ConfigProvider.d.ts +39 -0
  7. package/dist/ConfigProvider.d.ts.map +1 -0
  8. package/dist/ConfigProvider.js +42 -0
  9. package/dist/{ServiceMap.d.ts → Context.d.ts} +14 -18
  10. package/dist/Context.d.ts.map +1 -0
  11. package/dist/Context.js +66 -0
  12. package/dist/Effect.d.ts +8 -9
  13. package/dist/Effect.d.ts.map +1 -1
  14. package/dist/Effect.js +3 -6
  15. package/dist/Layer.d.ts +5 -4
  16. package/dist/Layer.d.ts.map +1 -1
  17. package/dist/Layer.js +1 -1
  18. package/dist/Operations.d.ts +198 -33
  19. package/dist/Operations.d.ts.map +1 -1
  20. package/dist/Pure.d.ts +2 -2
  21. package/dist/Pure.d.ts.map +1 -1
  22. package/dist/Pure.js +13 -13
  23. package/dist/Schema/Class.d.ts +48 -10
  24. package/dist/Schema/Class.d.ts.map +1 -1
  25. package/dist/Schema/Class.js +120 -16
  26. package/dist/Schema/SpecialJsonSchema.d.ts +33 -0
  27. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  28. package/dist/Schema/SpecialJsonSchema.js +122 -0
  29. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  30. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  31. package/dist/Schema/SpecialOpenApi.js +123 -0
  32. package/dist/Schema/brand.d.ts +10 -1
  33. package/dist/Schema/brand.d.ts.map +1 -1
  34. package/dist/Schema/brand.js +1 -1
  35. package/dist/Schema/email.d.ts.map +1 -1
  36. package/dist/Schema/email.js +9 -4
  37. package/dist/Schema/ext.d.ts +112 -47
  38. package/dist/Schema/ext.d.ts.map +1 -1
  39. package/dist/Schema/ext.js +115 -53
  40. package/dist/Schema/moreStrings.d.ts +110 -10
  41. package/dist/Schema/moreStrings.d.ts.map +1 -1
  42. package/dist/Schema/moreStrings.js +19 -10
  43. package/dist/Schema/numbers.d.ts +126 -14
  44. package/dist/Schema/numbers.d.ts.map +1 -1
  45. package/dist/Schema/numbers.js +10 -9
  46. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  47. package/dist/Schema/phoneNumber.js +8 -3
  48. package/dist/Schema/strings.d.ts +36 -4
  49. package/dist/Schema/strings.d.ts.map +1 -1
  50. package/dist/Schema/strings.js +1 -1
  51. package/dist/Schema.d.ts +74 -55
  52. package/dist/Schema.d.ts.map +1 -1
  53. package/dist/Schema.js +85 -64
  54. package/dist/client/apiClientFactory.d.ts +12 -28
  55. package/dist/client/apiClientFactory.d.ts.map +1 -1
  56. package/dist/client/apiClientFactory.js +16 -17
  57. package/dist/client/clientFor.d.ts +6 -5
  58. package/dist/client/clientFor.d.ts.map +1 -1
  59. package/dist/client/errors.d.ts +18 -9
  60. package/dist/client/errors.d.ts.map +1 -1
  61. package/dist/client/errors.js +35 -10
  62. package/dist/client/makeClient.d.ts +73 -28
  63. package/dist/client/makeClient.d.ts.map +1 -1
  64. package/dist/client/makeClient.js +49 -23
  65. package/dist/http/Request.d.ts.map +1 -1
  66. package/dist/http/Request.js +5 -5
  67. package/dist/ids.d.ts +2 -2
  68. package/dist/ids.d.ts.map +1 -1
  69. package/dist/ids.js +3 -2
  70. package/dist/index.d.ts +3 -7
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +4 -8
  73. package/dist/middleware.d.ts +2 -2
  74. package/dist/middleware.d.ts.map +1 -1
  75. package/dist/middleware.js +3 -3
  76. package/dist/rpc/MiddlewareMaker.d.ts +4 -3
  77. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  78. package/dist/rpc/MiddlewareMaker.js +23 -24
  79. package/dist/rpc/RpcContextMap.d.ts +2 -2
  80. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  81. package/dist/rpc/RpcContextMap.js +4 -4
  82. package/dist/rpc/RpcMiddleware.d.ts +4 -3
  83. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  84. package/dist/rpc/RpcMiddleware.js +1 -1
  85. package/dist/utils/gen.d.ts +1 -1
  86. package/dist/utils/gen.d.ts.map +1 -1
  87. package/dist/utils/logger.d.ts +2 -2
  88. package/dist/utils/logger.d.ts.map +1 -1
  89. package/dist/utils/logger.js +3 -3
  90. package/dist/utils.d.ts +7 -1
  91. package/dist/utils.d.ts.map +1 -1
  92. package/dist/utils.js +8 -2
  93. package/package.json +30 -14
  94. package/src/Config/SecretURL.ts +1 -1
  95. package/src/Config.ts +14 -0
  96. package/src/ConfigProvider.ts +48 -0
  97. package/src/{ServiceMap.ts → Context.ts} +51 -59
  98. package/src/Effect.ts +11 -14
  99. package/src/Layer.ts +5 -4
  100. package/src/Pure.ts +17 -18
  101. package/src/Schema/Class.ts +157 -30
  102. package/src/Schema/SpecialJsonSchema.ts +137 -0
  103. package/src/Schema/SpecialOpenApi.ts +130 -0
  104. package/src/Schema/brand.ts +18 -3
  105. package/src/Schema/email.ts +10 -2
  106. package/src/Schema/ext.ts +196 -87
  107. package/src/Schema/moreStrings.ts +31 -17
  108. package/src/Schema/numbers.ts +14 -13
  109. package/src/Schema/phoneNumber.ts +8 -1
  110. package/src/Schema/strings.ts +4 -4
  111. package/src/Schema.ts +195 -104
  112. package/src/client/apiClientFactory.ts +104 -112
  113. package/src/client/clientFor.ts +6 -1
  114. package/src/client/errors.ts +42 -17
  115. package/src/client/makeClient.ts +150 -61
  116. package/src/http/Request.ts +7 -4
  117. package/src/ids.ts +2 -1
  118. package/src/index.ts +3 -10
  119. package/src/middleware.ts +2 -2
  120. package/src/rpc/MiddlewareMaker.ts +33 -44
  121. package/src/rpc/RpcContextMap.ts +6 -5
  122. package/src/rpc/RpcMiddleware.ts +5 -4
  123. package/src/utils/gen.ts +1 -1
  124. package/src/utils/logger.ts +2 -2
  125. package/src/utils.ts +8 -4
  126. package/test/dist/moreStrings.test.d.ts.map +1 -0
  127. package/test/dist/rpc.test.d.ts.map +1 -1
  128. package/test/dist/secretURL.test.d.ts.map +1 -0
  129. package/test/dist/special.test.d.ts.map +1 -0
  130. package/test/moreStrings.test.ts +17 -0
  131. package/test/rpc.test.ts +30 -6
  132. package/test/schema.test.ts +517 -4
  133. package/test/secretURL.test.ts +157 -0
  134. package/test/special.test.ts +862 -0
  135. package/test/utils.test.ts +2 -2
  136. package/tsconfig.base.json +0 -1
  137. package/tsconfig.json +0 -1
  138. package/dist/ServiceMap.d.ts.map +0 -1
  139. package/dist/ServiceMap.js +0 -91
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import * as Config from "effect/Config"
3
2
  import { flow } from "effect/Function"
4
3
  import * as Layer from "effect/Layer"
5
4
  import * as ManagedRuntime from "effect/ManagedRuntime"
@@ -7,13 +6,14 @@ import * as Predicate from "effect/Predicate"
7
6
  import * as Schema from "effect/Schema"
8
7
  import * as Struct from "effect/Struct"
9
8
  import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/unstable/rpc"
9
+ import * as Config from "../Config.js"
10
+ import * as Context from "../Context.js"
10
11
  import * as Effect from "../Effect.js"
11
12
  import { HttpClient, HttpClientRequest } from "../http.js"
12
13
  import * as Option from "../Option.js"
13
14
  import type * as S from "../Schema.js"
14
- import * as ServiceMap from "../ServiceMap.js"
15
15
  import { typedKeysOf, typedValuesOf } from "../utils.js"
16
- import type { Client, ClientForOptions, Requests, RequestsAny } from "./clientFor.js"
16
+ import type { Client, ClientForOptions, ExtractModuleName, RequestsAny } from "./clientFor.js"
17
17
 
18
18
  export interface ApiConfig {
19
19
  url: string
@@ -37,10 +37,13 @@ export type Req = S.Top & {
37
37
  success: S.Top
38
38
  error: S.Top
39
39
  config?: Record<string, any>
40
+ readonly id: string
41
+ readonly moduleName: string
42
+ readonly type: "command" | "query"
40
43
  readonly "~decodingServices"?: unknown
41
44
  }
42
45
 
43
- class RequestName extends ServiceMap.Reference("RequestName", {
46
+ class RequestName extends Context.Reference("RequestName", {
44
47
  defaultValue: () => ({ requestName: "Unspecified", moduleName: "Error" })
45
48
  }) {}
46
49
 
@@ -84,7 +87,7 @@ type RpcHandlers<M extends RequestsAny> = {
84
87
  [K in keyof M]: Rpc.Rpc<M[K]["_tag"], M[K], M[K]["success"], M[K]["error"]>
85
88
  }
86
89
 
87
- const getFiltered = <M extends Requests>(resource: M) => {
90
+ const getFiltered = <M extends RequestsAny>(resource: M) => {
88
91
  type Filtered = {
89
92
  [K in keyof M as M[K] extends Req ? K : never]: M[K] extends Req ? M[K] : never
90
93
  }
@@ -102,13 +105,13 @@ const getFiltered = <M extends Requests>(resource: M) => {
102
105
  return filtered as unknown as Filtered
103
106
  }
104
107
 
105
- export const getMeta = <M extends Requests>(resource: M) => {
106
- const meta = (resource as any).meta as { moduleName: string }
107
- if (!meta) throw new Error("No meta defined in Resource!")
108
- return meta as M["meta"]
108
+ export const getMeta = <M extends RequestsAny>(resource: M): { moduleName: ExtractModuleName<M> } => {
109
+ const first = typedValuesOf(getFiltered(resource))[0]
110
+ if (first && "moduleName" in first) return { moduleName: first.moduleName }
111
+ throw new Error("No moduleName on requests!")
109
112
  }
110
113
 
111
- export const makeRpcGroupFromRequestsAndModuleName = <M extends Requests, const ModuleName extends string>(
114
+ export const makeRpcGroupFromRequestsAndModuleName = <M extends RequestsAny, const ModuleName extends string>(
112
115
  resource: M,
113
116
  moduleName: ModuleName
114
117
  ) => {
@@ -126,20 +129,13 @@ export const makeRpcGroupFromRequestsAndModuleName = <M extends Requests, const
126
129
  return rpcs
127
130
  }
128
131
 
129
- export const makeRpcGroup = <
130
- M extends Requests,
131
- const ModuleName extends string
132
- >(
133
- resource: M & { meta: { moduleName: ModuleName } }
134
- ) => makeRpcGroupFromRequestsAndModuleName(resource, resource.meta.moduleName)
135
-
136
- const makeRpcTag = <M extends Requests>(resource: M) => {
132
+ const makeRpcTag = <M extends RequestsAny>(resource: M) => {
137
133
  const meta = getMeta(resource)
138
134
  const rpcs = makeRpcGroupFromRequestsAndModuleName(resource, meta.moduleName)
139
135
 
140
136
  // Use Object.assign instead of class extension to avoid TS2509 with complex generic return types.
141
137
  // The first type arg is `any` because this is a dynamically created tag — its identity is the string key.
142
- const TheClient = ServiceMap.Opaque<
138
+ const TheClient = Context.Opaque<
143
139
  any,
144
140
  RpcClient.RpcClient<RpcGroup.Rpcs<typeof rpcs>>
145
141
  >()(`RpcClient.${meta.moduleName}`)
@@ -153,99 +149,98 @@ const makeRpcTag = <M extends Requests>(resource: M) => {
153
149
 
154
150
  const makeApiClientFactory = Effect
155
151
  .gen(function*() {
156
- const ctx = yield* Effect.services<RpcSerialization.RpcSerialization | HttpClient.HttpClient>()
157
- const makeClientFor = <M extends Requests>(
152
+ const ctx = yield* Effect.context<RpcSerialization.RpcSerialization | HttpClient.HttpClient>()
153
+ const makeClientFor = Effect.fnUntraced(function*<M extends RequestsAny>(
158
154
  resource: M,
159
155
  requestLevelLayers = Layer.empty,
160
156
  options?: ClientForOptions
161
- ) =>
162
- Effect.gen(function*() {
163
- const TheClient = makeRpcTag(resource)
164
-
165
- const meta = getMeta(resource)
166
-
167
- // TODO: somehow we need a protocol per REQUEST kind of it seems ...
168
- // otherwise it locks up on the client, navigation remains empty...
169
- const clientLayer = TheClient.layer.pipe(
170
- // add ApiClientFactory for nested schemas
171
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
172
- Layer.provide(Layer.succeed(ApiClientFactory, makeClientForCached as any)),
173
- Layer.provide(
174
- RpcClient
175
- .layerProtocolHttp({
176
- url: "" // why not here set meta.moduleName as root?
177
- })
178
- .pipe(
179
- Layer.provideMerge(Layer.succeedServices(ctx))
180
- )
181
- )
157
+ ) {
158
+ const TheClient = makeRpcTag(resource)
159
+
160
+ const meta = getMeta(resource)
161
+
162
+ // TODO: somehow we need a protocol per REQUEST kind of it seems ...
163
+ // otherwise it locks up on the client, navigation remains empty...
164
+ const clientLayer = TheClient.layer.pipe(
165
+ // add ApiClientFactory for nested schemas
166
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
167
+ Layer.provide(Layer.succeed(ApiClientFactory, makeClientForCached as any)),
168
+ Layer.provide(
169
+ RpcClient
170
+ .layerProtocolHttp({
171
+ url: "" // why not here set meta.moduleName as root?
172
+ })
173
+ .pipe(
174
+ Layer.provideMerge(Layer.succeedContext(ctx))
175
+ )
182
176
  )
183
- const mr = ManagedRuntime.make(clientLayer)
184
-
185
- const filtered = getFiltered(resource)
186
- return {
187
- mr,
188
- client: typedKeysOf(filtered)
189
- .reduce((prev, cur) => {
190
- const h = filtered[cur]!
191
-
192
- const Request = h
193
-
194
- const id = `${meta.moduleName}.${cur as string}`
195
- .replaceAll(".js", "")
196
-
197
- const requestMeta = {
198
- Request,
199
- id,
200
- options
177
+ )
178
+ const mr = ManagedRuntime.make(clientLayer)
179
+
180
+ const filtered = getFiltered(resource)
181
+ return {
182
+ mr,
183
+ client: typedKeysOf(filtered)
184
+ .reduce((prev, cur) => {
185
+ const h = filtered[cur]!
186
+
187
+ const Request = h
188
+
189
+ const id = `${meta.moduleName}.${cur as string}`
190
+ .replaceAll(".js", "")
191
+
192
+ const requestMeta = {
193
+ Request,
194
+ id,
195
+ options
196
+ }
197
+
198
+ const requestNameLayer = Layer.succeed(RequestName, {
199
+ requestName: cur as string,
200
+ moduleName: meta.moduleName
201
+ })
202
+
203
+ const layers = requestLevelLayers.pipe(Layer.provideMerge(requestNameLayer))
204
+
205
+ const fields = Struct.omit(Request.fields, ["_tag"] as const)
206
+ const requestAttr = `${meta.moduleName}.${h._tag}`
207
+ // @ts-expect-error doc
208
+ prev[cur] = Object.keys(fields).length === 0
209
+ ? {
210
+ handler: mr.contextEffect.pipe(
211
+ Effect.flatMap((svcs) =>
212
+ TheClient
213
+ .use((client) => (client as any)[requestAttr]!(new Request()) as Effect.Effect<any, any, never>)
214
+ .pipe(
215
+ Effect.provide(layers),
216
+ Effect.provide(svcs)
217
+ )
218
+ )
219
+ ),
220
+ ...requestMeta
201
221
  }
202
-
203
- const requestNameLayer = Layer.succeed(RequestName, {
204
- requestName: cur as string,
205
- moduleName: meta.moduleName
206
- })
207
-
208
- const layers = requestLevelLayers.pipe(Layer.provideMerge(requestNameLayer))
209
-
210
- const fields = Struct.omit(Request.fields, ["_tag"] as const)
211
- const requestAttr = `${meta.moduleName}.${h._tag}`
212
- // @ts-expect-error doc
213
- prev[cur] = Object.keys(fields).length === 0
214
- ? {
215
- handler: mr.servicesEffect.pipe(
222
+ : {
223
+ handler: (req: any) =>
224
+ mr.contextEffect.pipe(
216
225
  Effect.flatMap((svcs) =>
217
226
  TheClient
218
- .use((client) => (client as any)[requestAttr]!(new Request()) as Effect.Effect<any, any, never>)
227
+ .use((client) =>
228
+ (client as any)[requestAttr]!(new Request(req)) as Effect.Effect<any, any, never>
229
+ )
219
230
  .pipe(
220
231
  Effect.provide(layers),
221
232
  Effect.provide(svcs)
222
233
  )
223
234
  )
224
235
  ),
225
- ...requestMeta
226
- }
227
- : {
228
- handler: (req: any) =>
229
- mr.servicesEffect.pipe(
230
- Effect.flatMap((svcs) =>
231
- TheClient
232
- .use((client) =>
233
- (client as any)[requestAttr]!(new Request(req)) as Effect.Effect<any, any, never>
234
- )
235
- .pipe(
236
- Effect.provide(layers),
237
- Effect.provide(svcs)
238
- )
239
- )
240
- ),
241
236
 
242
- ...requestMeta
243
- }
237
+ ...requestMeta
238
+ }
244
239
 
245
- return prev
246
- }, {} as Client<M, M["meta"]["moduleName"]>)
247
- }
248
- })
240
+ return prev
241
+ }, {} as Client<M, ExtractModuleName<M>>)
242
+ }
243
+ })
249
244
 
250
245
  const register: ManagedRuntime.ManagedRuntime<any, any>[] = []
251
246
  yield* Effect.addFinalizer(() => Effect.forEach(register, (mr) => mr.disposeEffect))
@@ -259,19 +254,16 @@ const makeApiClientFactory = Effect
259
254
  cacheL.set(requestLevelLayers, cache)
260
255
  }
261
256
 
262
- return <M extends Requests>(
263
- models: M
264
- ): Effect.Effect<Client<M, M["meta"]["moduleName"]>> =>
265
- Effect.gen(function*() {
266
- const found = cache.get(models)
267
- if (found) {
268
- return found
269
- }
270
- const m = yield* makeClientFor(models, requestLevelLayers, options)
271
- cache.set(models, m.client)
272
- register.push(m.mr)
273
- return m.client
274
- })
257
+ return Effect.fnUntraced(function*<M extends RequestsAny>(models: M) {
258
+ const found = cache.get(models) as Client<M, ExtractModuleName<M>> | undefined
259
+ if (found) {
260
+ return found
261
+ }
262
+ const m = yield* makeClientFor(models, requestLevelLayers, options)
263
+ cache.set(models, m.client)
264
+ register.push(m.mr)
265
+ return m.client
266
+ })
275
267
  }
276
268
 
277
269
  return makeClientForCached
@@ -281,7 +273,7 @@ const makeApiClientFactory = Effect
281
273
  * Used to create clients for resource modules.
282
274
  */
283
275
  export class ApiClientFactory
284
- extends ServiceMap.Opaque<ApiClientFactory, Effect.Success<typeof makeApiClientFactory>>()("ApiClientFactory")
276
+ extends Context.Opaque<ApiClientFactory, Effect.Success<typeof makeApiClientFactory>>()("ApiClientFactory")
285
277
  {
286
278
  static readonly layer = (config: ApiConfig) =>
287
279
  ApiClientFactory.toLayer(makeApiClientFactory).pipe(Layer.provide(RpcSerializationLayer(config)))
@@ -294,7 +286,7 @@ export class ApiClientFactory
294
286
 
295
287
  static readonly makeFor =
296
288
  (requestLevelLayers: Layer.Layer<never, never, never>, options?: ClientForOptions) =>
297
- <M extends Requests>(
289
+ <M extends RequestsAny>(
298
290
  resource: M
299
291
  ) =>
300
292
  ApiClientFactory.use((apiClientFactory) => {
@@ -48,9 +48,14 @@ export function makePathWithBody(
48
48
  return path.build(pars, { ignoreSearch: true, ignoreConstraints: true })
49
49
  }
50
50
 
51
- export type Requests<ModuleName extends string = string> = { meta: { moduleName: ModuleName } } & RequestsAny
51
+ export type Requests = RequestsAny
52
52
  export type RequestsAny = Record<string, any>
53
53
 
54
+ export type ExtractModuleName<M extends RequestsAny> =
55
+ { [K in keyof M]: M[K] extends { moduleName: infer N extends string } ? N : never }[keyof M] extends
56
+ infer R extends string ? R
57
+ : string
58
+
54
59
  export type Client<M extends RequestsAny, ModuleName extends string> = RequestHandlers<
55
60
  never,
56
61
  never,
@@ -1,5 +1,5 @@
1
1
  /** @effect-diagnostics overriddenSchemaConstructor:skip-file */
2
- import { TaggedError } from "effect-app/Schema"
2
+ import { TaggedErrorClass } from "effect-app/Schema"
3
3
  import * as Cause from "effect/Cause"
4
4
  import * as S from "../Schema.js"
5
5
 
@@ -21,7 +21,7 @@ export const tryToJson = (error: { toJSON(): unknown; toString(): string }) => {
21
21
 
22
22
  // eslint-disable-next-line unused-imports/no-unused-vars
23
23
  // @ts-expect-error type not used
24
- export class NotFoundError<ItemType = string> extends TaggedError<NotFoundError<ItemType>>()("NotFoundError", {
24
+ export class NotFoundError<ItemType = string> extends TaggedErrorClass<NotFoundError<ItemType>>()("NotFoundError", {
25
25
  type: S.String,
26
26
  id: S.Unknown
27
27
  }) {
@@ -29,76 +29,97 @@ export class NotFoundError<ItemType = string> extends TaggedError<NotFoundError<
29
29
  props: { type: string; id: unknown; cause?: unknown },
30
30
  disableValidation?: boolean
31
31
  ) {
32
- super(props as any, disableValidation as any)
32
+ super(props, disableValidation as any)
33
33
  }
34
34
  override get message() {
35
35
  return `Didn't find ${(this as any).type}#${JSON.stringify((this as any).id)}`
36
36
  }
37
+ override toString() {
38
+ return `NotFoundError: ${this.message}`
39
+ }
37
40
  }
38
41
 
39
42
  const messageFallback = (messageOrObject?: string | { message: string }) =>
40
43
  typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject ?? "" }
41
44
 
42
- export class InvalidStateError extends TaggedError<InvalidStateError>()("InvalidStateError", {
45
+ export class InvalidStateError extends TaggedErrorClass<InvalidStateError>()("InvalidStateError", {
43
46
  message: S.String
44
47
  }) {
45
48
  constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
46
49
  super(
47
- typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject } as any,
50
+ typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject },
48
51
  disableValidation as any
49
52
  )
50
53
  }
54
+ override toString() {
55
+ return `InvalidStateError: ${this.message}`
56
+ }
51
57
  }
52
58
 
53
- export class ServiceUnavailableError extends TaggedError<ServiceUnavailableError>()("ServiceUnavailableError", {
59
+ export class ServiceUnavailableError extends TaggedErrorClass<ServiceUnavailableError>()("ServiceUnavailableError", {
54
60
  message: S.String
55
61
  }) {
56
62
  constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
57
63
  super(
58
- typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject } as any,
64
+ typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject },
59
65
  disableValidation as any
60
66
  )
61
67
  }
68
+ override toString() {
69
+ return `ServiceUnavailableError: ${this.message}`
70
+ }
62
71
  }
63
72
 
64
- export class ValidationError extends TaggedError<ValidationError>()("ValidationError", {
73
+ export class ValidationError extends TaggedErrorClass<ValidationError>()("ValidationError", {
65
74
  errors: S.Array(S.Unknown)
66
75
  }) {
67
76
  constructor(
68
77
  props: { errors: ReadonlyArray<unknown>; cause?: unknown },
69
78
  disableValidation?: boolean
70
79
  ) {
71
- super(props as any, disableValidation as any)
80
+ super(props, disableValidation as any)
72
81
  }
73
82
  override get message() {
74
83
  return `Validation failed: ${(this as any).errors.map((e: any) => JSON.stringify(e, undefined, 2)).join(",\n")}`
75
84
  }
85
+ override toString() {
86
+ return `ValidationError: ${this.message}`
87
+ }
76
88
  }
77
89
 
78
- export class NotLoggedInError extends TaggedError<NotLoggedInError>()("NotLoggedInError", {
90
+ export class NotLoggedInError extends TaggedErrorClass<NotLoggedInError>()("NotLoggedInError", {
79
91
  message: S.String
80
92
  }) {
81
93
  constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
82
- super(messageFallback(messageOrObject) as any, disableValidation as any)
94
+ super(messageFallback(messageOrObject), disableValidation as any)
95
+ }
96
+ override toString() {
97
+ return `NotLoggedInError: ${this.message}`
83
98
  }
84
99
  }
85
100
 
86
101
  /**
87
102
  * The user carries a valid Userprofile, but there is a problem with the login none the less.
88
103
  */
89
- export class LoginError extends TaggedError<LoginError>()("NotLoggedInError", {
104
+ export class LoginError extends TaggedErrorClass<LoginError>()("NotLoggedInError", {
90
105
  message: S.String
91
106
  }) {
92
107
  constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
93
- super(messageFallback(messageOrObject) as any, disableValidation as any)
108
+ super(messageFallback(messageOrObject), disableValidation as any)
109
+ }
110
+ override toString() {
111
+ return `LoginError: ${this.message}`
94
112
  }
95
113
  }
96
114
 
97
- export class UnauthorizedError extends TaggedError<UnauthorizedError>()("UnauthorizedError", {
115
+ export class UnauthorizedError extends TaggedErrorClass<UnauthorizedError>()("UnauthorizedError", {
98
116
  message: S.String
99
117
  }) {
100
118
  constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) {
101
- super(messageFallback(messageOrObject) as any, disableValidation as any)
119
+ super(messageFallback(messageOrObject), disableValidation as any)
120
+ }
121
+ override toString() {
122
+ return `UnauthorizedError: ${this.message}`
102
123
  }
103
124
  }
104
125
 
@@ -110,7 +131,7 @@ type OptimisticConcurrencyDetails = {
110
131
  readonly found?: string | undefined
111
132
  }
112
133
 
113
- export class OptimisticConcurrencyException extends TaggedError<OptimisticConcurrencyException>()(
134
+ export class OptimisticConcurrencyException extends TaggedErrorClass<OptimisticConcurrencyException>()(
114
135
  "OptimisticConcurrencyException",
115
136
  { message: S.String }
116
137
  ) {
@@ -123,13 +144,16 @@ export class OptimisticConcurrencyException extends TaggedError<OptimisticConcur
123
144
  disableValidation?: boolean
124
145
  ) {
125
146
  super(
126
- "message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` } as any,
147
+ "message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` },
127
148
  disableValidation as any
128
149
  )
129
150
  if (!("message" in args)) {
130
151
  this.details = args
131
152
  }
132
153
  }
154
+ override toString() {
155
+ return `OptimisticConcurrencyException: ${this.message}`
156
+ }
133
157
  }
134
158
 
135
159
  const MutationOnlyErrors = [
@@ -183,6 +207,7 @@ export class CauseException<E> extends Error {
183
207
  Error.stackTraceLimit = 0
184
208
  super()
185
209
  Error.stackTraceLimit = limit
210
+ this.cause = Cause.squash(originalCause)
186
211
  // v4: makeFiberFailure removed — use Cause.prettyErrors instead
187
212
  const errors = Cause.prettyErrors(originalCause)
188
213
  const first = errors[0]