effect-app 4.0.0-beta.27 → 4.0.0-beta.272

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 (342) hide show
  1. package/CHANGELOG.md +1275 -0
  2. package/dist/Array.d.ts +2 -1
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +4 -4
  5. package/dist/Chunk.d.ts.map +1 -1
  6. package/dist/Config/SecretURL.d.ts +3 -1
  7. package/dist/Config/SecretURL.d.ts.map +1 -1
  8. package/dist/Config/SecretURL.js +3 -6
  9. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  10. package/dist/Config/internal/configSecretURL.js +2 -2
  11. package/dist/Config.d.ts +2 -0
  12. package/dist/Config.d.ts.map +1 -0
  13. package/dist/Config.js +8 -0
  14. package/dist/ConfigProvider.d.ts +2 -0
  15. package/dist/ConfigProvider.d.ts.map +1 -0
  16. package/dist/ConfigProvider.js +6 -0
  17. package/dist/{ServiceMap.d.ts → Context.d.ts} +18 -20
  18. package/dist/Context.d.ts.map +1 -0
  19. package/dist/Context.js +67 -0
  20. package/dist/Effect.d.ts +10 -9
  21. package/dist/Effect.d.ts.map +1 -1
  22. package/dist/Effect.js +5 -8
  23. package/dist/Emailer.d.ts +51 -0
  24. package/dist/Emailer.d.ts.map +1 -0
  25. package/dist/Emailer.js +7 -0
  26. package/dist/Function.d.ts.map +1 -1
  27. package/dist/Layer.d.ts +10 -6
  28. package/dist/Layer.d.ts.map +1 -1
  29. package/dist/Layer.js +3 -2
  30. package/dist/Model/Repository/Registry.d.ts +22 -0
  31. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  32. package/dist/Model/Repository/Registry.js +18 -0
  33. package/dist/Model/Repository/ext.d.ts +60 -0
  34. package/dist/Model/Repository/ext.d.ts.map +1 -0
  35. package/dist/Model/Repository/ext.js +122 -0
  36. package/dist/Model/Repository/internal/internal.d.ts +63 -0
  37. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  38. package/dist/Model/Repository/internal/internal.js +430 -0
  39. package/dist/Model/Repository/legacy.d.ts +21 -0
  40. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  41. package/dist/Model/Repository/legacy.js +2 -0
  42. package/dist/Model/Repository/makeRepo.d.ts +54 -0
  43. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  44. package/dist/Model/Repository/makeRepo.js +27 -0
  45. package/dist/Model/Repository/service.d.ts +121 -0
  46. package/dist/Model/Repository/service.d.ts.map +1 -0
  47. package/dist/Model/Repository/service.js +2 -0
  48. package/dist/Model/Repository/validation.d.ts +58 -0
  49. package/dist/Model/Repository/validation.d.ts.map +1 -0
  50. package/dist/Model/Repository/validation.js +32 -0
  51. package/dist/Model/Repository.d.ts +7 -0
  52. package/dist/Model/Repository.d.ts.map +1 -0
  53. package/dist/Model/Repository.js +7 -0
  54. package/dist/Model/dsl.d.ts +33 -0
  55. package/dist/Model/dsl.d.ts.map +1 -0
  56. package/dist/Model/dsl.js +43 -0
  57. package/dist/Model/filter/filterApi.d.ts +30 -0
  58. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  59. package/dist/Model/filter/filterApi.js +2 -0
  60. package/dist/Model/filter/types/errors.d.ts +29 -0
  61. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  62. package/dist/Model/filter/types/errors.js +2 -0
  63. package/dist/Model/filter/types/fields.d.ts +15 -0
  64. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  65. package/dist/Model/filter/types/fields.js +2 -0
  66. package/dist/Model/filter/types/path/common.d.ts +316 -0
  67. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  68. package/dist/Model/filter/types/path/common.js +2 -0
  69. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  70. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  71. package/dist/Model/filter/types/path/eager.js +36 -0
  72. package/dist/Model/filter/types/path/index.d.ts +4 -0
  73. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  74. package/dist/Model/filter/types/path/index.js +3 -0
  75. package/dist/Model/filter/types/utils.d.ts +79 -0
  76. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  77. package/dist/Model/filter/types/utils.js +2 -0
  78. package/dist/Model/filter/types/validator.d.ts +30 -0
  79. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  80. package/dist/Model/filter/types/validator.js +2 -0
  81. package/dist/Model/filter/types.d.ts +5 -0
  82. package/dist/Model/filter/types.d.ts.map +1 -0
  83. package/dist/Model/filter/types.js +7 -0
  84. package/dist/Model/query/dsl.d.ts +493 -0
  85. package/dist/Model/query/dsl.d.ts.map +1 -0
  86. package/dist/Model/query/dsl.js +376 -0
  87. package/dist/Model/query/new-kid-interpreter.d.ts +136 -0
  88. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  89. package/dist/Model/query/new-kid-interpreter.js +336 -0
  90. package/dist/Model/query.d.ts +15 -0
  91. package/dist/Model/query.d.ts.map +1 -0
  92. package/dist/Model/query.js +3 -0
  93. package/dist/Model.d.ts +5 -0
  94. package/dist/Model.d.ts.map +1 -0
  95. package/dist/Model.js +5 -0
  96. package/dist/NonEmptySet.d.ts +3 -1
  97. package/dist/NonEmptySet.d.ts.map +1 -1
  98. package/dist/NonEmptySet.js +2 -2
  99. package/dist/Option.d.ts +1 -0
  100. package/dist/Option.d.ts.map +1 -1
  101. package/dist/Option.js +3 -1
  102. package/dist/Pure.d.ts +7 -5
  103. package/dist/Pure.d.ts.map +1 -1
  104. package/dist/Pure.js +17 -14
  105. package/dist/QueueMaker.d.ts +13 -0
  106. package/dist/QueueMaker.d.ts.map +1 -0
  107. package/dist/QueueMaker.js +4 -0
  108. package/dist/RequestContext.d.ts +154 -0
  109. package/dist/RequestContext.d.ts.map +1 -0
  110. package/dist/RequestContext.js +54 -0
  111. package/dist/Schema/Class.d.ts +160 -19
  112. package/dist/Schema/Class.d.ts.map +1 -1
  113. package/dist/Schema/Class.js +260 -17
  114. package/dist/Schema/FastCheck.d.ts.map +1 -1
  115. package/dist/Schema/SchemaParser.d.ts +5 -0
  116. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  117. package/dist/Schema/SchemaParser.js +6 -0
  118. package/dist/Schema/SpecialJsonSchema.d.ts +34 -0
  119. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  120. package/dist/Schema/SpecialJsonSchema.js +118 -0
  121. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  122. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  123. package/dist/Schema/SpecialOpenApi.js +123 -0
  124. package/dist/Schema/brand.d.ts +4 -2
  125. package/dist/Schema/brand.d.ts.map +1 -1
  126. package/dist/Schema/brand.js +3 -1
  127. package/dist/Schema/email.d.ts.map +1 -1
  128. package/dist/Schema/email.js +7 -4
  129. package/dist/Schema/ext.d.ts +338 -55
  130. package/dist/Schema/ext.d.ts.map +1 -1
  131. package/dist/Schema/ext.js +358 -53
  132. package/dist/Schema/moreStrings.d.ts +82 -36
  133. package/dist/Schema/moreStrings.d.ts.map +1 -1
  134. package/dist/Schema/moreStrings.js +49 -42
  135. package/dist/Schema/numbers.d.ts +34 -21
  136. package/dist/Schema/numbers.d.ts.map +1 -1
  137. package/dist/Schema/numbers.js +55 -12
  138. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  139. package/dist/Schema/phoneNumber.js +6 -3
  140. package/dist/Schema/strings.d.ts +18 -4
  141. package/dist/Schema/strings.d.ts.map +1 -1
  142. package/dist/Schema/strings.js +1 -5
  143. package/dist/Schema.d.ts +213 -7
  144. package/dist/Schema.d.ts.map +1 -1
  145. package/dist/Schema.js +190 -11
  146. package/dist/Set.d.ts +4 -1
  147. package/dist/Set.d.ts.map +1 -1
  148. package/dist/Set.js +3 -2
  149. package/dist/Store.d.ts +170 -0
  150. package/dist/Store.d.ts.map +1 -0
  151. package/dist/Store.js +121 -0
  152. package/dist/_ext/Array.d.ts +1 -1
  153. package/dist/_ext/Array.d.ts.map +1 -1
  154. package/dist/_ext/Array.js +4 -2
  155. package/dist/_ext/misc.d.ts +4 -1
  156. package/dist/_ext/misc.d.ts.map +1 -1
  157. package/dist/_ext/misc.js +4 -2
  158. package/dist/_ext/ord.ext.d.ts +2 -1
  159. package/dist/_ext/ord.ext.d.ts.map +1 -1
  160. package/dist/_ext/ord.ext.js +2 -2
  161. package/dist/client/InvalidationKeys.d.ts +29 -0
  162. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  163. package/dist/client/InvalidationKeys.js +33 -0
  164. package/dist/client/apiClientFactory.d.ts +19 -31
  165. package/dist/client/apiClientFactory.d.ts.map +1 -1
  166. package/dist/client/apiClientFactory.js +104 -34
  167. package/dist/client/clientFor.d.ts +52 -18
  168. package/dist/client/clientFor.d.ts.map +1 -1
  169. package/dist/client/clientFor.js +9 -1
  170. package/dist/client/errors.d.ts +82 -27
  171. package/dist/client/errors.d.ts.map +1 -1
  172. package/dist/client/errors.js +75 -19
  173. package/dist/client/makeClient.d.ts +494 -32
  174. package/dist/client/makeClient.d.ts.map +1 -1
  175. package/dist/client/makeClient.js +66 -24
  176. package/dist/client.d.ts +1 -0
  177. package/dist/client.d.ts.map +1 -1
  178. package/dist/client.js +2 -1
  179. package/dist/faker.d.ts.map +1 -1
  180. package/dist/http/Request.d.ts +1 -1
  181. package/dist/http/Request.d.ts.map +1 -1
  182. package/dist/http/Request.js +2 -2
  183. package/dist/ids.d.ts +42 -14
  184. package/dist/ids.d.ts.map +1 -1
  185. package/dist/ids.js +30 -5
  186. package/dist/index.d.ts +6 -7
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +8 -8
  189. package/dist/middleware.d.ts +13 -7
  190. package/dist/middleware.d.ts.map +1 -1
  191. package/dist/middleware.js +14 -8
  192. package/dist/rpc/Invalidation.d.ts +420 -0
  193. package/dist/rpc/Invalidation.d.ts.map +1 -0
  194. package/dist/rpc/Invalidation.js +168 -0
  195. package/dist/rpc/MiddlewareMaker.d.ts +11 -7
  196. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  197. package/dist/rpc/MiddlewareMaker.js +59 -38
  198. package/dist/rpc/RpcContextMap.d.ts +3 -3
  199. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  200. package/dist/rpc/RpcContextMap.js +4 -4
  201. package/dist/rpc/RpcMiddleware.d.ts +14 -10
  202. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  203. package/dist/rpc/RpcMiddleware.js +1 -1
  204. package/dist/rpc.d.ts +1 -1
  205. package/dist/rpc.d.ts.map +1 -1
  206. package/dist/rpc.js +2 -2
  207. package/dist/runtime.d.ts +19 -0
  208. package/dist/runtime.d.ts.map +1 -0
  209. package/dist/runtime.js +40 -0
  210. package/dist/setupRequest.d.ts +19 -0
  211. package/dist/setupRequest.d.ts.map +1 -0
  212. package/dist/setupRequest.js +69 -0
  213. package/dist/toast.d.ts +51 -0
  214. package/dist/toast.d.ts.map +1 -0
  215. package/dist/toast.js +34 -0
  216. package/dist/transform.d.ts +1 -1
  217. package/dist/transform.d.ts.map +1 -1
  218. package/dist/transform.js +4 -5
  219. package/dist/utils/effectify.d.ts +1 -1
  220. package/dist/utils/effectify.d.ts.map +1 -1
  221. package/dist/utils/effectify.js +2 -2
  222. package/dist/utils/extend.d.ts.map +1 -1
  223. package/dist/utils/gen.d.ts +4 -4
  224. package/dist/utils/gen.d.ts.map +1 -1
  225. package/dist/utils/logLevel.d.ts +2 -2
  226. package/dist/utils/logLevel.d.ts.map +1 -1
  227. package/dist/utils/logger.d.ts +4 -3
  228. package/dist/utils/logger.d.ts.map +1 -1
  229. package/dist/utils/logger.js +4 -4
  230. package/dist/utils.d.ts +34 -39
  231. package/dist/utils.d.ts.map +1 -1
  232. package/dist/utils.js +33 -37
  233. package/dist/validation/validators.d.ts.map +1 -1
  234. package/dist/validation.d.ts.map +1 -1
  235. package/dist/withToast.d.ts +30 -0
  236. package/dist/withToast.d.ts.map +1 -0
  237. package/dist/withToast.js +64 -0
  238. package/package.json +22 -247
  239. package/src/Array.ts +5 -5
  240. package/src/Chunk.ts +3 -3
  241. package/src/Config/SecretURL.ts +6 -3
  242. package/src/Config/internal/configSecretURL.ts +2 -2
  243. package/src/Config.ts +7 -0
  244. package/src/ConfigProvider.ts +5 -0
  245. package/src/{ServiceMap.ts → Context.ts} +56 -63
  246. package/src/Effect.ts +14 -16
  247. package/src/Emailer.ts +51 -0
  248. package/src/Inputify.type.ts +1 -1
  249. package/src/Layer.ts +11 -7
  250. package/src/Model/Repository/Registry.ts +35 -0
  251. package/src/Model/Repository/ext.ts +375 -0
  252. package/src/Model/Repository/internal/internal.ts +741 -0
  253. package/src/Model/Repository/legacy.ts +29 -0
  254. package/src/Model/Repository/makeRepo.ts +145 -0
  255. package/src/Model/Repository/service.ts +676 -0
  256. package/src/Model/Repository/validation.ts +31 -0
  257. package/src/Model/Repository.ts +6 -0
  258. package/src/Model/dsl.ts +129 -0
  259. package/src/Model/filter/filterApi.ts +60 -0
  260. package/src/Model/filter/types/errors.ts +47 -0
  261. package/src/Model/filter/types/fields.ts +50 -0
  262. package/src/Model/filter/types/path/common.ts +404 -0
  263. package/src/Model/filter/types/path/eager.ts +329 -0
  264. package/src/Model/filter/types/path/index.ts +4 -0
  265. package/src/Model/filter/types/utils.ts +128 -0
  266. package/src/Model/filter/types/validator.ts +46 -0
  267. package/src/Model/filter/types.ts +6 -0
  268. package/src/Model/query/dsl.ts +2694 -0
  269. package/src/Model/query/new-kid-interpreter.ts +484 -0
  270. package/src/Model/query.ts +13 -0
  271. package/src/Model.ts +4 -0
  272. package/src/NonEmptySet.ts +6 -4
  273. package/src/Option.ts +2 -0
  274. package/src/Pure.ts +22 -20
  275. package/src/QueueMaker.ts +19 -0
  276. package/src/RequestContext.ts +95 -0
  277. package/src/Schema/Class.ts +593 -59
  278. package/src/Schema/SchemaParser.ts +12 -0
  279. package/src/Schema/SpecialJsonSchema.ts +139 -0
  280. package/src/Schema/SpecialOpenApi.ts +130 -0
  281. package/src/Schema/brand.ts +22 -2
  282. package/src/Schema/email.ts +9 -4
  283. package/src/Schema/ext.ts +446 -91
  284. package/src/Schema/moreStrings.ts +147 -68
  285. package/src/Schema/numbers.ts +97 -28
  286. package/src/Schema/phoneNumber.ts +9 -5
  287. package/src/Schema/strings.ts +23 -14
  288. package/src/Schema.ts +389 -25
  289. package/src/Set.ts +6 -2
  290. package/src/Store.ts +277 -0
  291. package/src/_ext/Array.ts +4 -2
  292. package/src/_ext/misc.ts +4 -1
  293. package/src/_ext/ord.ext.ts +2 -1
  294. package/src/client/InvalidationKeys.ts +50 -0
  295. package/src/client/apiClientFactory.ts +234 -135
  296. package/src/client/clientFor.ts +105 -34
  297. package/src/client/errors.ts +100 -29
  298. package/src/client/makeClient.ts +594 -73
  299. package/src/client.ts +5 -4
  300. package/src/http/Request.ts +3 -3
  301. package/src/http.ts +1 -1
  302. package/src/ids.ts +33 -6
  303. package/src/index.ts +20 -23
  304. package/src/middleware.ts +13 -9
  305. package/src/rpc/Invalidation.ts +261 -0
  306. package/src/rpc/MiddlewareMaker.ts +88 -80
  307. package/src/rpc/README.md +2 -2
  308. package/src/rpc/RpcContextMap.ts +7 -6
  309. package/src/rpc/RpcMiddleware.ts +19 -13
  310. package/src/rpc.ts +4 -4
  311. package/src/runtime.ts +56 -0
  312. package/src/setupRequest.ts +134 -0
  313. package/src/toast.ts +54 -0
  314. package/src/transform.ts +4 -4
  315. package/src/utils/effectify.ts +1 -1
  316. package/src/utils/gen.ts +8 -8
  317. package/src/utils/logLevel.ts +1 -1
  318. package/src/utils/logger.ts +4 -3
  319. package/src/utils.ts +85 -158
  320. package/src/validation.ts +2 -2
  321. package/src/withToast.ts +133 -0
  322. package/test/dist/rpc.test.d.ts.map +1 -1
  323. package/test/dist/secretURL.test.d.ts.map +1 -0
  324. package/test/dist/special.test.d.ts.map +1 -0
  325. package/test/moreStrings.test.ts +1 -1
  326. package/test/rpc.test.ts +46 -6
  327. package/test/schema.test.ts +459 -30
  328. package/test/secretURL.test.ts +160 -0
  329. package/test/special.test.ts +1258 -0
  330. package/test/utils.test.ts +7 -7
  331. package/tsconfig.base.json +6 -5
  332. package/tsconfig.json +3 -1
  333. package/tsconfig.json.bak +2 -2
  334. package/tsconfig.src.json +29 -29
  335. package/tsconfig.test.json +2 -2
  336. package/dist/Operations.d.ts +0 -123
  337. package/dist/Operations.d.ts.map +0 -1
  338. package/dist/Operations.js +0 -29
  339. package/dist/ServiceMap.d.ts.map +0 -1
  340. package/dist/ServiceMap.js +0 -91
  341. package/eslint.config.mjs +0 -26
  342. package/src/Operations.ts +0 -55
@@ -1,95 +1,629 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { pipe, Struct as Struct2 } from "effect"
3
- import type { Struct } from "effect/Schema"
2
+ import type * as Cause from "effect/Cause"
3
+ import * as Effect from "effect/Effect"
4
+ import * as Option from "effect/Option"
4
5
  import * as S from "effect/Schema"
6
+ import * as SchemaAST from "effect/SchemaAST"
7
+ import * as SchemaGetter from "effect/SchemaGetter"
8
+ import * as SchemaIssue from "effect/SchemaIssue"
9
+ import * as SchemaTransformation from "effect/SchemaTransformation"
10
+ import { copyOrigin } from "../utils.ts"
11
+ import { concurrencyUnbounded } from "./ext.ts"
12
+ import * as SchemaParser from "./SchemaParser.ts"
5
13
 
6
14
  type ClassAnnotations<Self> = S.Annotations.Declaration<Self, readonly [any]>
7
15
 
8
- export interface EnhancedClass<Self, SchemaS extends S.Top & { readonly fields: Struct.Fields }, Inherited>
9
- extends S.Class<Self, SchemaS, Inherited>, /* Reason for enhancement */ PropsExtensions<SchemaS["fields"]>
16
+ export interface EnhancedClass<Self, SchemaS extends S.Top & { readonly fields: S.Struct.Fields }, Inherited>
17
+ extends S.Class<Self, SchemaS, Inherited>
10
18
  {
19
+ /**
20
+ * See `copyOrigin` docs in `utils.ts` for return-type design details.
21
+ */
22
+ readonly copy: ReturnType<typeof copyOrigin<new(_: any) => Self>>
11
23
  }
12
24
  type MissingSelfGeneric<Usage extends string, Params extends string = ""> =
13
25
  `Missing \`Self\` generic - use \`class Self extends ${Usage}<Self>()(${Params}{ ... })\``
14
26
 
15
- export interface PropsExtensions<Fields> {
16
- // include: <NewProps extends S.Struct.Fields>(
17
- // fnc: (fields: Fields) => NewProps
18
- // ) => NewProps
19
- pick: <P extends keyof Fields>(...keys: readonly P[]) => Pick<Fields, P>
20
- omit: <P extends keyof Fields>(...keys: readonly P[]) => Omit<Fields, P>
21
- }
22
-
23
- type HasFields<Fields extends Struct.Fields> = {
27
+ type HasFields<Fields extends S.Struct.Fields> = {
24
28
  readonly fields: Fields
25
29
  } | {
26
30
  readonly from: HasFields<Fields>
27
31
  }
28
32
 
29
- export const Class: <Self = never>(identifier: string) => <Fields extends S.Struct.Fields>(
33
+ type ClassOptions = {
34
+ readonly strict?: boolean
35
+ }
36
+
37
+ export declare const ExtendedSchemaNoEncoded: unique symbol
38
+
39
+ export type ExtendedSchemaNoEncoded = typeof ExtendedSchemaNoEncoded
40
+
41
+ type WithEncoded<SchemaS extends S.Top, Encoded> = Omit<SchemaS, "Encoded"> & { readonly Encoded: Encoded }
42
+
43
+ type ExtendedSchema<SchemaS extends S.Top, Encoded> = [Encoded] extends [ExtendedSchemaNoEncoded] ? SchemaS
44
+ : WithEncoded<SchemaS, Encoded>
45
+
46
+ export type Class<Self, S extends S.Top & { readonly fields: S.Struct.Fields }, Inherited> = EnhancedClass<
47
+ Self,
48
+ S,
49
+ Inherited
50
+ >
51
+
52
+ /**
53
+ * Build a modified Declaration that accepts struct-matching values during
54
+ * encoding, given the original Declaration and the class's fields.
55
+ */
56
+ function makeRelaxedDeclaration(
57
+ ast: SchemaAST.Declaration,
58
+ fields: S.Struct.Fields,
59
+ cls: any
60
+ ): SchemaAST.Declaration {
61
+ const parseOptions = ast.annotations?.["parseOptions"] as SchemaAST.ParseOptions | undefined
62
+ const structSchema = S.Struct(fields)
63
+ const annotatedStruct = parseOptions ? S.toType(structSchema).annotate({ parseOptions }) : S.toType(structSchema)
64
+ const decodeStruct = SchemaParser.decodeUnknownEffect(annotatedStruct)
65
+
66
+ return new SchemaAST.Declaration(
67
+ ast.typeParameters,
68
+ () => (input: unknown, self: SchemaAST.Declaration, options: SchemaAST.ParseOptions) => {
69
+ if (input instanceof cls) {
70
+ return Effect.succeed(input)
71
+ }
72
+ if (input !== null && typeof input === "object") {
73
+ return decodeStruct(input, options)
74
+ }
75
+ return Effect.fail(new SchemaIssue.InvalidType(self, Option.some(input)))
76
+ },
77
+ ast.annotations,
78
+ ast.checks,
79
+ ast.encoding,
80
+ ast.context
81
+ )
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Class — like Schema.Class but with relaxed encoding
86
+ // ---------------------------------------------------------------------------
87
+
88
+ /**
89
+ * Like `Schema.Class`, but the resulting class accepts plain objects matching
90
+ * the struct schema during encoding — not only `instanceof` or type-id
91
+ * checks.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * import * as Schema from "effect/Schema"
96
+ * import { Class } from "./Class.ts"
97
+ *
98
+ * class A extends Class<A>("A")({ a: Schema.String }) {}
99
+ *
100
+ * // Construction works as normal:
101
+ * new A({ a: "hello" })
102
+ *
103
+ * // Encoding accepts plain objects:
104
+ * Schema.encodeUnknownSync(A)({ a: "hello" }) // { a: "hello" }
105
+ * ```
106
+ */
107
+ export const Class: <Self = never, Encoded = ExtendedSchemaNoEncoded, Brand = {}>(
108
+ identifier: string
109
+ ) => <Fields extends S.Struct.Fields>(
30
110
  fieldsOr: Fields | HasFields<Fields>,
31
- annotations?: ClassAnnotations<Self>
111
+ annotations?: ClassAnnotations<Self>,
112
+ options?: ClassOptions
32
113
  ) => [Self] extends [never] ? MissingSelfGeneric<"Class">
33
114
  : EnhancedClass<
34
115
  Self,
35
- S.Struct<Fields>,
36
- {}
37
- > = (identifier) => (fields, annotations) => {
38
- const cls = S.Class as any
39
- return class extends cls(identifier)(fields, annotations) {
40
- // static readonly include = include(fields)
41
- static readonly pick = (...selection: any[]) => pipe(this["fields"], Struct2.pick(selection))
42
- static readonly omit = (...selection: any[]) => pipe(this["fields"], Struct2.omit(selection))
116
+ ExtendedSchema<S.Struct<Fields>, Encoded>,
117
+ Brand
118
+ > = (identifier) => (fields, annotations, options) => {
119
+ const relaxed = options?.strict === false
120
+ // Build the original Schema.Class
121
+ const Base = (S.Class as any)(identifier)(fields, { ...concurrencyUnbounded, ...annotations })
122
+ // Get the original ast getter from the base class
123
+ const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")!
124
+
125
+ // Cache per-class to avoid recomputing
126
+ const astCache = new WeakMap<any, SchemaAST.Declaration>()
127
+ const copyCache = new WeakMap<any, ReturnType<typeof copyOrigin>>()
128
+
129
+ return class extends Base {
130
+ static get copy() {
131
+ let cached = copyCache.get(this)
132
+ if (cached === undefined) {
133
+ cached = copyOrigin(this)
134
+ copyCache.set(this, cached)
135
+ }
136
+ return cached
137
+ }
138
+ static get ast(): SchemaAST.Declaration {
139
+ let cached = astCache.get(this)
140
+ if (cached !== undefined) return cached
141
+ // Call the original getter with `this` bound to the actual user class,
142
+ // so getClassSchema(this) creates a schema that uses `new this(...)`.
143
+ const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration
144
+ cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst
145
+ astCache.set(this, cached)
146
+ return cached
147
+ }
148
+ static mapFields(f: any, options?: any) {
149
+ return Base.mapFields(f, options).annotate(concurrencyUnbounded)
150
+ }
43
151
  } as any
44
152
  }
45
153
 
46
- export const TaggedClass: <Self = never>(identifier?: string) => <Tag extends string, Fields extends S.Struct.Fields>(
154
+ // ---------------------------------------------------------------------------
155
+ // TaggedClass — like Schema.TaggedClass but with relaxed encoding
156
+ // ---------------------------------------------------------------------------
157
+
158
+ /**
159
+ * Like `Schema.TaggedClass`, but the resulting class accepts plain objects
160
+ * matching the struct schema during encoding.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * import * as Schema from "effect/Schema"
165
+ * import { TaggedClass } from "./Class.ts"
166
+ *
167
+ * class Circle extends TaggedClass<Circle>()("Circle", {
168
+ * radius: Schema.Number
169
+ * }) {}
170
+ *
171
+ * Schema.encodeUnknownSync(Circle)({ _tag: "Circle", radius: 5 })
172
+ * ```
173
+ */
174
+ export const TaggedClass: <Self = never, Encoded = ExtendedSchemaNoEncoded, Brand = {}>(
175
+ identifier?: string
176
+ ) => <Tag extends string, Fields extends S.Struct.Fields>(
47
177
  tag: Tag,
48
178
  fieldsOr: Fields | HasFields<Fields>,
49
- annotations?: ClassAnnotations<Self>
50
- ) => [Self] extends [never] ? MissingSelfGeneric<"Class">
179
+ annotations?: ClassAnnotations<Self>,
180
+ options?: ClassOptions
181
+ ) => [Self] extends [never] ? MissingSelfGeneric<"TaggedClass">
51
182
  : EnhancedClass<
52
183
  Self,
53
- S.Struct<{ readonly _tag: S.tag<Tag> } & Fields>,
54
- {}
55
- > = (identifier) => (tag, fields, annotations) => {
56
- const cls = S.TaggedClass as any
57
- return class extends cls(identifier)(tag, fields, annotations) {
58
- // static readonly include = include(fields)
59
- static readonly pick = (...selection: any[]) => pipe(this["fields"], Struct2.pick(selection))
60
- static readonly omit = (...selection: any[]) => pipe(this["fields"], Struct2.omit(selection))
184
+ ExtendedSchema<S.Struct<{ readonly _tag: S.tag<Tag> } & Fields>, Encoded>,
185
+ Brand
186
+ > = (identifier) => (tag, fields, annotations, options) => {
187
+ const relaxed = options?.strict === false
188
+ const Base = (S.TaggedClass as any)(identifier)(tag, fields, { ...concurrencyUnbounded, ...annotations })
189
+ const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")!
190
+ const astCache = new WeakMap<any, SchemaAST.Declaration>()
191
+ const copyCache = new WeakMap<any, ReturnType<typeof copyOrigin>>()
192
+
193
+ return class extends Base {
194
+ static get copy() {
195
+ let cached = copyCache.get(this)
196
+ if (cached === undefined) {
197
+ cached = copyOrigin(this)
198
+ copyCache.set(this, cached)
199
+ }
200
+ return cached
201
+ }
202
+ static get ast(): SchemaAST.Declaration {
203
+ let cached = astCache.get(this)
204
+ if (cached !== undefined) return cached
205
+ const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration
206
+ cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst
207
+ astCache.set(this, cached)
208
+ return cached
209
+ }
210
+ static mapFields(f: any, options?: any) {
211
+ return Base.mapFields(f, options).annotate(concurrencyUnbounded)
212
+ }
61
213
  } as any
62
214
  }
63
215
 
64
- export const ExtendedClass: <Self, _SelfFrom>(identifier: string) => <Fields extends S.Struct.Fields>(
216
+ // ---------------------------------------------------------------------------
217
+ // ErrorClass — like Schema.ErrorClass but with relaxed encoding
218
+ // ---------------------------------------------------------------------------
219
+
220
+ export const ErrorClass: <Self = never, Encoded = ExtendedSchemaNoEncoded, Brand = {}>(
221
+ identifier: string
222
+ ) => <Fields extends S.Struct.Fields>(
65
223
  fieldsOr: Fields | HasFields<Fields>,
66
- annotations?: ClassAnnotations<Self>
67
- ) => EnhancedClass<
68
- Self,
69
- S.Struct<Fields>,
70
- {}
71
- > = Class as any
72
-
73
- export interface EnhancedTaggedClass<Self, Tag extends string, Fields extends Struct.Fields, SelfFrom>
74
- extends
75
- EnhancedClass<
76
- Self,
77
- S.Struct<Fields> & { readonly Encoded: SelfFrom },
78
- {}
79
- >
80
- {
81
- readonly _tag: Tag
82
- }
224
+ annotations?: ClassAnnotations<Self>,
225
+ options?: ClassOptions
226
+ ) => [Self] extends [never] ? MissingSelfGeneric<"ErrorClass">
227
+ : EnhancedClass<
228
+ Self,
229
+ ExtendedSchema<S.Struct<Fields>, Encoded>,
230
+ Cause.YieldableError & Brand
231
+ > = (identifier) => (fields, annotations, options) => {
232
+ const relaxed = options?.strict === false
233
+ const Base = (S.ErrorClass as any)(identifier)(fields, { ...concurrencyUnbounded, ...annotations })
234
+ const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")!
235
+ const astCache = new WeakMap<any, SchemaAST.Declaration>()
236
+ const copyCache = new WeakMap<any, ReturnType<typeof copyOrigin>>()
237
+
238
+ return class extends Base {
239
+ static get copy() {
240
+ let cached = copyCache.get(this)
241
+ if (cached === undefined) {
242
+ cached = copyOrigin(this)
243
+ copyCache.set(this, cached)
244
+ }
245
+ return cached
246
+ }
247
+ static get ast(): SchemaAST.Declaration {
248
+ let cached = astCache.get(this)
249
+ if (cached !== undefined) return cached
250
+ const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration
251
+ cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst
252
+ astCache.set(this, cached)
253
+ return cached
254
+ }
255
+ static mapFields(f: any, options?: any) {
256
+ return Base.mapFields(f, options).annotate(concurrencyUnbounded)
257
+ }
258
+ } as any
259
+ }
260
+
261
+ // ---------------------------------------------------------------------------
262
+ // TaggedErrorClass — like Schema.TaggedErrorClass but with relaxed encoding
263
+ // ---------------------------------------------------------------------------
83
264
 
84
- export const ExtendedTaggedClass: <Self, SelfFrom>(
265
+ export const TaggedErrorClass: <Self = never, Encoded = ExtendedSchemaNoEncoded, Brand = {}>(
85
266
  identifier?: string
86
267
  ) => <Tag extends string, Fields extends S.Struct.Fields>(
87
268
  tag: Tag,
88
269
  fieldsOr: Fields | HasFields<Fields>,
89
- annotations?: ClassAnnotations<Self>
90
- ) => EnhancedTaggedClass<
270
+ annotations?: ClassAnnotations<Self>,
271
+ options?: ClassOptions
272
+ ) => [Self] extends [never] ? MissingSelfGeneric<"TaggedErrorClass">
273
+ : EnhancedClass<
274
+ Self,
275
+ ExtendedSchema<S.Struct<{ readonly _tag: S.tag<Tag> } & Fields>, Encoded>,
276
+ Cause.YieldableError & Brand
277
+ > = (identifier) => (tag, fields, annotations, options) => {
278
+ const relaxed = options?.strict === false
279
+ const Base = (S.TaggedErrorClass as any)(identifier)(tag, fields, { ...concurrencyUnbounded, ...annotations })
280
+ const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")!
281
+ const astCache = new WeakMap<any, SchemaAST.Declaration>()
282
+ const copyCache = new WeakMap<any, ReturnType<typeof copyOrigin>>()
283
+
284
+ return class extends Base {
285
+ static get copy() {
286
+ let cached = copyCache.get(this)
287
+ if (cached === undefined) {
288
+ cached = copyOrigin(this)
289
+ copyCache.set(this, cached)
290
+ }
291
+ return cached
292
+ }
293
+ static get ast(): SchemaAST.Declaration {
294
+ let cached = astCache.get(this)
295
+ if (cached !== undefined) return cached
296
+ const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration
297
+ cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst
298
+ astCache.set(this, cached)
299
+ return cached
300
+ }
301
+ static mapFields(f: any, options?: any) {
302
+ return Base.mapFields(f, options).annotate(concurrencyUnbounded)
303
+ }
304
+ } as any
305
+ }
306
+
307
+ export interface Opaque<Self, Encoded, SchemaS extends S.Top, Brand>
308
+ extends S.Opaque<Self, ExtendedSchema<SchemaS, Encoded>, Brand>
309
+ {}
310
+
311
+ export const Opaque: <Self, Encoded = ExtendedSchemaNoEncoded, Brand = {}>() => <S extends S.Top>(
312
+ schema: S
313
+ ) => Opaque<Self, Encoded, S, Brand> & Omit<S, keyof S.Top> = S.Opaque as any
314
+
315
+ /**
316
+ * Like {@link Opaque}, but the class **instance type is exactly `Self`** (the supplied
317
+ * decoded `Type`) instead of the structurally-computed `struct["Type"] & Brand`.
318
+ *
319
+ * Stock `Opaque` types the instance as `struct["Type"] & Brand` and only overrides the
320
+ * schema's `Type`/`Encoded` *members* with `Self`/`Encoded`. So `make`/`copy`/consumers
321
+ * still resolve the struct's mapped `Type`. With a codegen-supplied pre-expanded literal
322
+ * `Type` interface, `OpaqueType` lets all of those resolve a single **named** interface
323
+ * (resolved once per checker) instead of re-deriving the mapped `Type` — cutting
324
+ * instantiation on `Type`-touching consumers.
325
+ *
326
+ * Use with `class X extends OpaqueType<X.Type, X.Encoded>()(struct) {}` where `X.Type`
327
+ * and `X.Encoded` are generated literal interfaces (see `@effect-app/eslint-codegen-model`,
328
+ * `static` + `type` mode).
329
+ *
330
+ * KNOWN GAP — **no branding**: the instance type is a plain structural `Self`, so opaque
331
+ * types of identical shape are mutually assignable. (Stock `Opaque` is also structural by
332
+ * default — `Brand` defaults to `{}` — so this only differs if you passed a non-default
333
+ * `Brand`.) Re-introducing a nominal brand on top of a supplied `Self` (e.g. branding the
334
+ * generated `Type` interface) is not yet implemented.
335
+ *
336
+ * NOTE: only `Type` (via `Self`) and `Encoded` are supplied statically here; `make`'s input
337
+ * (`~type.make.in`) and other derived members are still computed from the struct. See
338
+ * a future `OpaqueShape`-style helper if those also need to be supplied.
339
+ */
340
+ export interface OpaqueType<Self, Encoded, SchemaS extends S.Top, Brand>
341
+ extends S.Opaque<Self, ExtendedSchema<SchemaS, Encoded>, Brand>
342
+ {
343
+ new(_: never): Self
344
+ }
345
+
346
+ export const OpaqueType: <Self, Encoded = ExtendedSchemaNoEncoded, Brand = {}>() => <S extends S.Top>(
347
+ schema: S
348
+ ) => OpaqueType<Self, Encoded, S, Brand> & Omit<S, keyof S.Top> = S.Opaque as any
349
+
350
+ // Override both the `Encoded` and make-input (`~type.make.in`) members in one go,
351
+ // like `ExtendedSchema` does for `Encoded` alone.
352
+ type ExtendedShape<SchemaS extends S.Top, Encoded, MakeIn> =
353
+ & Omit<SchemaS, "Encoded" | "~type.make.in">
354
+ & { readonly Encoded: Encoded; readonly "~type.make.in": MakeIn }
355
+
356
+ type OpaqueFacadeConstructorArgs<MakeIn> = {} extends MakeIn ? [props?: MakeIn, options?: S.MakeOptions]
357
+ : [props: MakeIn, options?: S.MakeOptions]
358
+
359
+ // Only the codec channels are required. `copy`/`fields`/`mapFields` are NOT
360
+ // required here: transformed schemas (`.pipe(S.encodeKeys/annotate/filter/...)`)
361
+ // don't expose them at the static level, and requiring them would reject those
362
+ // models from facading. When present they still flow through via
363
+ // `OpaqueFacadeStatics`; when absent the facade simply doesn't offer them.
364
+ type OpaqueFacadeInput<DecodingServices, EncodingServices> = S.Top & {
365
+ readonly DecodingServices: DecodingServices
366
+ readonly EncodingServices: EncodingServices
367
+ }
368
+
369
+ type OpaqueClassFacadeInput<DecodingServices, EncodingServices> =
370
+ & OpaqueFacadeInput<
371
+ DecodingServices,
372
+ EncodingServices
373
+ >
374
+ & (abstract new(...args: Array<never>) => unknown)
375
+
376
+ type PrototypeFunction = Function & { prototype: object }
377
+
378
+ const ClassAnnotationId = "~effect/Schema/Class"
379
+
380
+ const getOwnOrInheritedPropertyDescriptor = (value: object, property: PropertyKey): PropertyDescriptor | undefined => {
381
+ let current: object | null = value
382
+ while (current !== null) {
383
+ const descriptor = Object.getOwnPropertyDescriptor(current, property)
384
+ if (descriptor !== undefined) return descriptor
385
+ current = Object.getPrototypeOf(current)
386
+ }
387
+ }
388
+
389
+ const isClassSchemaConstructor = (value: unknown): value is PrototypeFunction => {
390
+ if (typeof value !== "function") return false
391
+ const ast = (value as { readonly ast?: unknown }).ast
392
+ return SchemaAST.isAST(ast) && SchemaAST.isDeclaration(ast) && ast.annotations?.[ClassAnnotationId] !== undefined
393
+ }
394
+
395
+ const getFacadeClassSchema = (schema: OpaqueFacadeInput<any, any>): PrototypeFunction | undefined => {
396
+ if (isClassSchemaConstructor(schema)) return schema
397
+ const target = "to" in schema ? schema.to : undefined
398
+ return isClassSchemaConstructor(target) ? target : undefined
399
+ }
400
+
401
+ const makePublicClassTransformation = (Public: PrototypeFunction) =>
402
+ new SchemaTransformation.Transformation<any, any, never, never>(
403
+ SchemaGetter.transform((input) => Reflect.construct(Public, [input], Public)),
404
+ SchemaGetter.passthrough()
405
+ )
406
+
407
+ const makeFacadeClassAst = (
408
+ schema: OpaqueFacadeInput<any, any>,
409
+ originalAst: SchemaAST.AST,
410
+ Public: PrototypeFunction
411
+ ): SchemaAST.AST => {
412
+ if (SchemaAST.isDeclaration(schema.ast)) {
413
+ const schemaEncoding = schema.ast.encoding ?? []
414
+ if (schemaEncoding.length > 0) {
415
+ return new SchemaAST.Declaration(
416
+ schema.ast.typeParameters,
417
+ schema.ast.run,
418
+ schema.ast.annotations,
419
+ schema.ast.checks,
420
+ [new SchemaAST.Link(schemaEncoding[0]!.to, makePublicClassTransformation(Public)), ...schemaEncoding.slice(1)],
421
+ schema.ast.context,
422
+ schema.ast.encodingChecks
423
+ )
424
+ }
425
+ }
426
+
427
+ return schema.rebuild(originalAst).ast
428
+ }
429
+
430
+ // Carry the schema's own statics, dropping the generic `S.Top` machinery and
431
+ // `prototype`. EXCEPT `to`: models compose each other via `X.to.fields` /
432
+ // `X.to.copy` at definition time, so it must survive on the facade.
433
+ type OpaqueFacadeStatics<SchemaS extends S.Top> = Omit<SchemaS, Exclude<keyof S.Top, "to"> | "prototype">
434
+
435
+ /**
436
+ * Like {@link OpaqueType}, but ALSO supplies a static **make-input** shape, so
437
+ * `make`/`copy` resolve a named `MakeIn` interface instead of re-deriving the struct's
438
+ * mapped `~type.make.in`. Use with codegen-supplied `X.Type` / `X.Encoded` / `X.Make`:
439
+ *
440
+ * ```ts
441
+ * class X extends OpaqueShape<X.Type, X.Encoded, X.Make>()(struct) {}
442
+ * ```
443
+ *
444
+ * `decode`/`encode` already use the supplied `Type`/`Encoded` (they read the schema's
445
+ * `Type`/`Encoded` members, which are `Self`/`Encoded` here) — no separate override needed.
446
+ *
447
+ * NOTE — measured gain is modest (~5%): the struct passed to the wrapper is still
448
+ * constructed in full (definition cost dominates); the static shapes only cheapen
449
+ * consumer-side reads of `Type`/`Encoded`/`MakeIn`. Same `no-branding` gap as
450
+ * {@link OpaqueType}.
451
+ */
452
+ export interface OpaqueShape<Self, Encoded, MakeIn, SchemaS extends S.Top, Brand>
453
+ extends S.Opaque<Self, ExtendedShape<SchemaS, Encoded, MakeIn>, Brand>
454
+ {
455
+ new(_: never): Self
456
+ }
457
+
458
+ export const OpaqueShape: <Self, Encoded, MakeIn, Brand = {}>() => <S extends S.Top>(
459
+ schema: S
460
+ ) => OpaqueShape<Self, Encoded, MakeIn, S, Brand> & Omit<S, keyof S.Top> = S.Opaque as any
461
+
462
+ /**
463
+ * Shallow public view for generated model facades.
464
+ *
465
+ * The runtime value can still be the full private schema class, but emitted
466
+ * declarations expose only named `Type` / `Encoded` / `Make` interfaces and a
467
+ * small static surface. This keeps downstream project references from pulling
468
+ * the private struct field map back through `typeof Model`.
469
+ */
470
+ export interface OpaqueFacade<
471
+ Self,
472
+ Encoded,
473
+ MakeIn,
474
+ DecodingServices = never,
475
+ EncodingServices = DecodingServices,
476
+ Brand = {}
477
+ > extends
478
+ S.Bottom<
479
+ Self,
480
+ Encoded,
481
+ DecodingServices,
482
+ EncodingServices,
483
+ SchemaAST.AST,
484
+ S.Codec<Self, Encoded, DecodingServices, EncodingServices>,
485
+ MakeIn,
486
+ Self,
487
+ readonly [],
488
+ MakeIn
489
+ >
490
+ {
491
+ new(_: never): Brand
492
+ readonly copy: ReturnType<typeof copyOrigin<new(_: MakeIn) => Self>>
493
+ // NOTE: `fields` / `mapFields` are intentionally NOT redeclared here. They are
494
+ // carried (precise) from the underlying schema via `OpaqueFacadeStatics`. A wide
495
+ // `mapFields(f: (fields: S.Struct.Fields) => To)` override would win overload
496
+ // resolution and erase field precision in `Q.project(X.mapFields(...))`.
497
+ }
498
+
499
+ export interface OpaqueClassFacade<
91
500
  Self,
92
- Tag,
93
- { readonly _tag: S.tag<Tag> } & Fields,
94
- SelfFrom
95
- > = TaggedClass as any
501
+ Encoded,
502
+ MakeIn,
503
+ DecodingServices = never,
504
+ EncodingServices = DecodingServices,
505
+ Brand = {}
506
+ > extends
507
+ S.Bottom<
508
+ Self,
509
+ Encoded,
510
+ DecodingServices,
511
+ EncodingServices,
512
+ SchemaAST.AST,
513
+ S.Codec<Self, Encoded, DecodingServices, EncodingServices>,
514
+ MakeIn,
515
+ Self,
516
+ readonly [],
517
+ MakeIn
518
+ >
519
+ {
520
+ new(...args: OpaqueFacadeConstructorArgs<MakeIn>): Brand
521
+ readonly copy: ReturnType<typeof copyOrigin<new(_: MakeIn) => Self>>
522
+ }
523
+
524
+ export function OpaqueFacade<
525
+ Self,
526
+ Encoded,
527
+ MakeIn,
528
+ DecodingServices = never,
529
+ EncodingServices = DecodingServices,
530
+ Brand = {}
531
+ >() {
532
+ function facade<SchemaS extends OpaqueClassFacadeInput<DecodingServices, EncodingServices>>(
533
+ schema: SchemaS
534
+ ):
535
+ & OpaqueClassFacade<Self, Encoded, MakeIn, DecodingServices, EncodingServices, Brand>
536
+ & OpaqueFacadeStatics<SchemaS>
537
+ function facade<SchemaS extends OpaqueFacadeInput<DecodingServices, EncodingServices>>(
538
+ schema: SchemaS
539
+ ):
540
+ & OpaqueFacade<Self, Encoded, MakeIn, DecodingServices, EncodingServices, Brand>
541
+ & OpaqueFacadeStatics<SchemaS>
542
+ function facade(schema: OpaqueFacadeInput<DecodingServices, EncodingServices>) {
543
+ const Base = getFacadeClassSchema(schema)
544
+ if (Base !== undefined) {
545
+ const astCache = new WeakMap<object, SchemaAST.AST>()
546
+ const originalAstDescriptor = getOwnOrInheritedPropertyDescriptor(Base, "ast")
547
+
548
+ return class extends (Base as any) {
549
+ static get ast(): SchemaAST.AST {
550
+ let cached = astCache.get(this)
551
+ if (cached !== undefined) return cached
552
+
553
+ const originalAst = originalAstDescriptor?.get?.call(this) as SchemaAST.AST
554
+ cached = makeFacadeClassAst(schema, originalAst, this)
555
+ astCache.set(this, cached)
556
+ return cached
557
+ }
558
+ }
559
+ }
560
+
561
+ class Facade {}
562
+ return Object.setPrototypeOf(Facade, schema)
563
+ }
564
+
565
+ return facade
566
+ }
567
+
568
+ /**
569
+ * Like class-schema {@link OpaqueFacade}, but for error models (`TaggedErrorClass` /
570
+ * `ErrorClass`). The decoded instance type carries `Cause.YieldableError`, so
571
+ * `yield* new MyError(...)`, `Effect.fail(myError)`, and `instanceof` all keep
572
+ * working through the facade — the runtime `_X` is the real error class (the
573
+ * facade `X extends ...(_X)` inherits its prototype), and the type reflects it.
574
+ * Nothing is lost vs the underlying error class.
575
+ */
576
+ export interface OpaqueErrorFacadeClass<
577
+ Self,
578
+ Encoded,
579
+ MakeIn,
580
+ DecodingServices = never,
581
+ EncodingServices = DecodingServices,
582
+ Brand = {}
583
+ > extends
584
+ S.Bottom<
585
+ Self,
586
+ Encoded,
587
+ DecodingServices,
588
+ EncodingServices,
589
+ SchemaAST.AST,
590
+ S.Codec<Self, Encoded, DecodingServices, EncodingServices>,
591
+ MakeIn,
592
+ Self,
593
+ readonly [],
594
+ MakeIn
595
+ >
596
+ {
597
+ // YieldableError (not Self) on the constructed instance — like class-schema OpaqueFacade's
598
+ // `new(): Brand`, the data type comes from the declaration-merged `interface X`,
599
+ // so `Self` must NOT appear here (would recurse). Merging `X & YieldableError`
600
+ // makes `yield* new X()` / `Effect.fail` / `instanceof` work without losing data.
601
+ new(...args: OpaqueFacadeConstructorArgs<MakeIn>): Cause.YieldableError & Brand
602
+ readonly copy: ReturnType<typeof copyOrigin<new(_: MakeIn) => Self>>
603
+ }
604
+
605
+ export function OpaqueErrorFacadeClass<
606
+ Self,
607
+ Encoded,
608
+ MakeIn,
609
+ DecodingServices = never,
610
+ EncodingServices = DecodingServices,
611
+ Brand = {}
612
+ >() {
613
+ return <SchemaS extends OpaqueClassFacadeInput<DecodingServices, EncodingServices>>(
614
+ schema: SchemaS
615
+ ):
616
+ & OpaqueErrorFacadeClass<Self, Encoded, MakeIn, DecodingServices, EncodingServices, Brand>
617
+ & OpaqueFacadeStatics<SchemaS> =>
618
+ {
619
+ type FacadeSchema =
620
+ & OpaqueErrorFacadeClass<Self, Encoded, MakeIn, DecodingServices, EncodingServices, Brand>
621
+ & OpaqueFacadeStatics<SchemaS>
622
+
623
+ if (typeof schema === "function") {
624
+ return schema as SchemaS & FacadeSchema
625
+ }
626
+
627
+ throw new TypeError("OpaqueErrorFacadeClass requires a class schema")
628
+ }
629
+ }