effect-app 4.0.0-beta.30 → 4.0.0-beta.301

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