effect-app 4.0.0-beta.31 → 4.0.0-beta.311

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