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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/CHANGELOG.md +1269 -0
  2. package/dist/Array.d.ts +2 -1
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +4 -4
  5. package/dist/Chunk.d.ts.map +1 -1
  6. package/dist/Config/SecretURL.d.ts +3 -1
  7. package/dist/Config/SecretURL.d.ts.map +1 -1
  8. package/dist/Config/SecretURL.js +3 -6
  9. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  10. package/dist/Config/internal/configSecretURL.js +2 -2
  11. package/dist/Config.d.ts +2 -0
  12. package/dist/Config.d.ts.map +1 -0
  13. package/dist/Config.js +8 -0
  14. package/dist/ConfigProvider.d.ts +2 -0
  15. package/dist/ConfigProvider.d.ts.map +1 -0
  16. package/dist/ConfigProvider.js +6 -0
  17. package/dist/{ServiceMap.d.ts → Context.d.ts} +18 -20
  18. package/dist/Context.d.ts.map +1 -0
  19. package/dist/Context.js +67 -0
  20. package/dist/Effect.d.ts +10 -9
  21. package/dist/Effect.d.ts.map +1 -1
  22. package/dist/Effect.js +5 -8
  23. package/dist/Emailer.d.ts +51 -0
  24. package/dist/Emailer.d.ts.map +1 -0
  25. package/dist/Emailer.js +7 -0
  26. package/dist/Function.d.ts.map +1 -1
  27. package/dist/Layer.d.ts +10 -6
  28. package/dist/Layer.d.ts.map +1 -1
  29. package/dist/Layer.js +3 -2
  30. package/dist/Model/Repository/Registry.d.ts +22 -0
  31. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  32. package/dist/Model/Repository/Registry.js +18 -0
  33. package/dist/Model/Repository/ext.d.ts +60 -0
  34. package/dist/Model/Repository/ext.d.ts.map +1 -0
  35. package/dist/Model/Repository/ext.js +122 -0
  36. package/dist/Model/Repository/internal/internal.d.ts +63 -0
  37. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  38. package/dist/Model/Repository/internal/internal.js +430 -0
  39. package/dist/Model/Repository/legacy.d.ts +21 -0
  40. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  41. package/dist/Model/Repository/legacy.js +2 -0
  42. package/dist/Model/Repository/makeRepo.d.ts +54 -0
  43. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  44. package/dist/Model/Repository/makeRepo.js +27 -0
  45. package/dist/Model/Repository/service.d.ts +121 -0
  46. package/dist/Model/Repository/service.d.ts.map +1 -0
  47. package/dist/Model/Repository/service.js +2 -0
  48. package/dist/Model/Repository/validation.d.ts +58 -0
  49. package/dist/Model/Repository/validation.d.ts.map +1 -0
  50. package/dist/Model/Repository/validation.js +32 -0
  51. package/dist/Model/Repository.d.ts +7 -0
  52. package/dist/Model/Repository.d.ts.map +1 -0
  53. package/dist/Model/Repository.js +7 -0
  54. package/dist/Model/dsl.d.ts +33 -0
  55. package/dist/Model/dsl.d.ts.map +1 -0
  56. package/dist/Model/dsl.js +43 -0
  57. package/dist/Model/filter/filterApi.d.ts +30 -0
  58. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  59. package/dist/Model/filter/filterApi.js +2 -0
  60. package/dist/Model/filter/types/errors.d.ts +29 -0
  61. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  62. package/dist/Model/filter/types/errors.js +2 -0
  63. package/dist/Model/filter/types/fields.d.ts +15 -0
  64. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  65. package/dist/Model/filter/types/fields.js +2 -0
  66. package/dist/Model/filter/types/path/common.d.ts +316 -0
  67. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  68. package/dist/Model/filter/types/path/common.js +2 -0
  69. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  70. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  71. package/dist/Model/filter/types/path/eager.js +36 -0
  72. package/dist/Model/filter/types/path/index.d.ts +4 -0
  73. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  74. package/dist/Model/filter/types/path/index.js +3 -0
  75. package/dist/Model/filter/types/utils.d.ts +79 -0
  76. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  77. package/dist/Model/filter/types/utils.js +2 -0
  78. package/dist/Model/filter/types/validator.d.ts +30 -0
  79. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  80. package/dist/Model/filter/types/validator.js +2 -0
  81. package/dist/Model/filter/types.d.ts +5 -0
  82. package/dist/Model/filter/types.d.ts.map +1 -0
  83. package/dist/Model/filter/types.js +7 -0
  84. package/dist/Model/query/dsl.d.ts +493 -0
  85. package/dist/Model/query/dsl.d.ts.map +1 -0
  86. package/dist/Model/query/dsl.js +376 -0
  87. package/dist/Model/query/new-kid-interpreter.d.ts +136 -0
  88. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  89. package/dist/Model/query/new-kid-interpreter.js +336 -0
  90. package/dist/Model/query.d.ts +15 -0
  91. package/dist/Model/query.d.ts.map +1 -0
  92. package/dist/Model/query.js +3 -0
  93. package/dist/Model.d.ts +5 -0
  94. package/dist/Model.d.ts.map +1 -0
  95. package/dist/Model.js +5 -0
  96. package/dist/NonEmptySet.d.ts +3 -1
  97. package/dist/NonEmptySet.d.ts.map +1 -1
  98. package/dist/NonEmptySet.js +2 -2
  99. package/dist/Option.d.ts +1 -0
  100. package/dist/Option.d.ts.map +1 -1
  101. package/dist/Option.js +3 -1
  102. package/dist/Pure.d.ts +7 -5
  103. package/dist/Pure.d.ts.map +1 -1
  104. package/dist/Pure.js +17 -14
  105. package/dist/QueueMaker.d.ts +13 -0
  106. package/dist/QueueMaker.d.ts.map +1 -0
  107. package/dist/QueueMaker.js +4 -0
  108. package/dist/RequestContext.d.ts +208 -0
  109. package/dist/RequestContext.d.ts.map +1 -0
  110. package/dist/RequestContext.js +54 -0
  111. package/dist/Schema/Class.d.ts +157 -19
  112. package/dist/Schema/Class.d.ts.map +1 -1
  113. package/dist/Schema/Class.js +214 -17
  114. package/dist/Schema/FastCheck.d.ts.map +1 -1
  115. package/dist/Schema/SchemaParser.d.ts +5 -0
  116. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  117. package/dist/Schema/SchemaParser.js +6 -0
  118. package/dist/Schema/SpecialJsonSchema.d.ts +34 -0
  119. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  120. package/dist/Schema/SpecialJsonSchema.js +118 -0
  121. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  122. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  123. package/dist/Schema/SpecialOpenApi.js +123 -0
  124. package/dist/Schema/brand.d.ts +4 -2
  125. package/dist/Schema/brand.d.ts.map +1 -1
  126. package/dist/Schema/brand.js +3 -1
  127. package/dist/Schema/email.d.ts.map +1 -1
  128. package/dist/Schema/email.js +7 -4
  129. package/dist/Schema/ext.d.ts +338 -55
  130. package/dist/Schema/ext.d.ts.map +1 -1
  131. package/dist/Schema/ext.js +358 -53
  132. package/dist/Schema/moreStrings.d.ts +82 -36
  133. package/dist/Schema/moreStrings.d.ts.map +1 -1
  134. package/dist/Schema/moreStrings.js +49 -42
  135. package/dist/Schema/numbers.d.ts +34 -21
  136. package/dist/Schema/numbers.d.ts.map +1 -1
  137. package/dist/Schema/numbers.js +55 -12
  138. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  139. package/dist/Schema/phoneNumber.js +6 -3
  140. package/dist/Schema/strings.d.ts +18 -4
  141. package/dist/Schema/strings.d.ts.map +1 -1
  142. package/dist/Schema/strings.js +1 -5
  143. package/dist/Schema.d.ts +213 -7
  144. package/dist/Schema.d.ts.map +1 -1
  145. package/dist/Schema.js +190 -11
  146. package/dist/Set.d.ts +4 -1
  147. package/dist/Set.d.ts.map +1 -1
  148. package/dist/Set.js +3 -2
  149. package/dist/Store.d.ts +170 -0
  150. package/dist/Store.d.ts.map +1 -0
  151. package/dist/Store.js +121 -0
  152. package/dist/_ext/Array.d.ts +1 -1
  153. package/dist/_ext/Array.d.ts.map +1 -1
  154. package/dist/_ext/Array.js +4 -2
  155. package/dist/_ext/misc.d.ts +4 -1
  156. package/dist/_ext/misc.d.ts.map +1 -1
  157. package/dist/_ext/misc.js +4 -2
  158. package/dist/_ext/ord.ext.d.ts +2 -1
  159. package/dist/_ext/ord.ext.d.ts.map +1 -1
  160. package/dist/_ext/ord.ext.js +2 -2
  161. package/dist/client/InvalidationKeys.d.ts +29 -0
  162. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  163. package/dist/client/InvalidationKeys.js +33 -0
  164. package/dist/client/apiClientFactory.d.ts +19 -31
  165. package/dist/client/apiClientFactory.d.ts.map +1 -1
  166. package/dist/client/apiClientFactory.js +104 -34
  167. package/dist/client/clientFor.d.ts +52 -18
  168. package/dist/client/clientFor.d.ts.map +1 -1
  169. package/dist/client/clientFor.js +9 -1
  170. package/dist/client/errors.d.ts +82 -27
  171. package/dist/client/errors.d.ts.map +1 -1
  172. package/dist/client/errors.js +75 -19
  173. package/dist/client/makeClient.d.ts +494 -32
  174. package/dist/client/makeClient.d.ts.map +1 -1
  175. package/dist/client/makeClient.js +66 -24
  176. package/dist/client.d.ts +1 -0
  177. package/dist/client.d.ts.map +1 -1
  178. package/dist/client.js +2 -1
  179. package/dist/faker.d.ts.map +1 -1
  180. package/dist/http/Request.d.ts +1 -1
  181. package/dist/http/Request.d.ts.map +1 -1
  182. package/dist/http/Request.js +2 -2
  183. package/dist/ids.d.ts +42 -14
  184. package/dist/ids.d.ts.map +1 -1
  185. package/dist/ids.js +30 -5
  186. package/dist/index.d.ts +6 -7
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +8 -8
  189. package/dist/middleware.d.ts +13 -7
  190. package/dist/middleware.d.ts.map +1 -1
  191. package/dist/middleware.js +14 -8
  192. package/dist/rpc/Invalidation.d.ts +420 -0
  193. package/dist/rpc/Invalidation.d.ts.map +1 -0
  194. package/dist/rpc/Invalidation.js +168 -0
  195. package/dist/rpc/MiddlewareMaker.d.ts +11 -7
  196. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  197. package/dist/rpc/MiddlewareMaker.js +59 -38
  198. package/dist/rpc/RpcContextMap.d.ts +3 -3
  199. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  200. package/dist/rpc/RpcContextMap.js +4 -4
  201. package/dist/rpc/RpcMiddleware.d.ts +14 -10
  202. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  203. package/dist/rpc/RpcMiddleware.js +1 -1
  204. package/dist/rpc.d.ts +1 -1
  205. package/dist/rpc.d.ts.map +1 -1
  206. package/dist/rpc.js +2 -2
  207. package/dist/runtime.d.ts +19 -0
  208. package/dist/runtime.d.ts.map +1 -0
  209. package/dist/runtime.js +40 -0
  210. package/dist/setupRequest.d.ts +19 -0
  211. package/dist/setupRequest.d.ts.map +1 -0
  212. package/dist/setupRequest.js +69 -0
  213. package/dist/toast.d.ts +51 -0
  214. package/dist/toast.d.ts.map +1 -0
  215. package/dist/toast.js +34 -0
  216. package/dist/transform.d.ts +1 -1
  217. package/dist/transform.d.ts.map +1 -1
  218. package/dist/transform.js +4 -5
  219. package/dist/utils/effectify.d.ts +1 -1
  220. package/dist/utils/effectify.d.ts.map +1 -1
  221. package/dist/utils/effectify.js +2 -2
  222. package/dist/utils/extend.d.ts.map +1 -1
  223. package/dist/utils/gen.d.ts +4 -4
  224. package/dist/utils/gen.d.ts.map +1 -1
  225. package/dist/utils/logLevel.d.ts +2 -2
  226. package/dist/utils/logLevel.d.ts.map +1 -1
  227. package/dist/utils/logger.d.ts +4 -3
  228. package/dist/utils/logger.d.ts.map +1 -1
  229. package/dist/utils/logger.js +4 -4
  230. package/dist/utils.d.ts +34 -39
  231. package/dist/utils.d.ts.map +1 -1
  232. package/dist/utils.js +33 -37
  233. package/dist/validation/validators.d.ts.map +1 -1
  234. package/dist/validation.d.ts.map +1 -1
  235. package/dist/withToast.d.ts +30 -0
  236. package/dist/withToast.d.ts.map +1 -0
  237. package/dist/withToast.js +64 -0
  238. package/package.json +22 -247
  239. package/src/Array.ts +5 -5
  240. package/src/Chunk.ts +3 -3
  241. package/src/Config/SecretURL.ts +6 -3
  242. package/src/Config/internal/configSecretURL.ts +2 -2
  243. package/src/Config.ts +7 -0
  244. package/src/ConfigProvider.ts +5 -0
  245. package/src/{ServiceMap.ts → Context.ts} +56 -63
  246. package/src/Effect.ts +14 -16
  247. package/src/Emailer.ts +51 -0
  248. package/src/Inputify.type.ts +1 -1
  249. package/src/Layer.ts +11 -7
  250. package/src/Model/Repository/Registry.ts +35 -0
  251. package/src/Model/Repository/ext.ts +375 -0
  252. package/src/Model/Repository/internal/internal.ts +741 -0
  253. package/src/Model/Repository/legacy.ts +29 -0
  254. package/src/Model/Repository/makeRepo.ts +145 -0
  255. package/src/Model/Repository/service.ts +676 -0
  256. package/src/Model/Repository/validation.ts +31 -0
  257. package/src/Model/Repository.ts +6 -0
  258. package/src/Model/dsl.ts +129 -0
  259. package/src/Model/filter/filterApi.ts +60 -0
  260. package/src/Model/filter/types/errors.ts +47 -0
  261. package/src/Model/filter/types/fields.ts +50 -0
  262. package/src/Model/filter/types/path/common.ts +404 -0
  263. package/src/Model/filter/types/path/eager.ts +329 -0
  264. package/src/Model/filter/types/path/index.ts +4 -0
  265. package/src/Model/filter/types/utils.ts +128 -0
  266. package/src/Model/filter/types/validator.ts +46 -0
  267. package/src/Model/filter/types.ts +6 -0
  268. package/src/Model/query/dsl.ts +2694 -0
  269. package/src/Model/query/new-kid-interpreter.ts +484 -0
  270. package/src/Model/query.ts +13 -0
  271. package/src/Model.ts +4 -0
  272. package/src/NonEmptySet.ts +6 -4
  273. package/src/Option.ts +2 -0
  274. package/src/Pure.ts +22 -20
  275. package/src/QueueMaker.ts +19 -0
  276. package/src/RequestContext.ts +95 -0
  277. package/src/Schema/Class.ts +517 -59
  278. package/src/Schema/SchemaParser.ts +12 -0
  279. package/src/Schema/SpecialJsonSchema.ts +139 -0
  280. package/src/Schema/SpecialOpenApi.ts +130 -0
  281. package/src/Schema/brand.ts +22 -2
  282. package/src/Schema/email.ts +9 -4
  283. package/src/Schema/ext.ts +446 -91
  284. package/src/Schema/moreStrings.ts +147 -68
  285. package/src/Schema/numbers.ts +97 -28
  286. package/src/Schema/phoneNumber.ts +9 -5
  287. package/src/Schema/strings.ts +23 -14
  288. package/src/Schema.ts +389 -25
  289. package/src/Set.ts +6 -2
  290. package/src/Store.ts +277 -0
  291. package/src/_ext/Array.ts +4 -2
  292. package/src/_ext/misc.ts +4 -1
  293. package/src/_ext/ord.ext.ts +2 -1
  294. package/src/client/InvalidationKeys.ts +50 -0
  295. package/src/client/apiClientFactory.ts +234 -135
  296. package/src/client/clientFor.ts +105 -34
  297. package/src/client/errors.ts +100 -29
  298. package/src/client/makeClient.ts +594 -73
  299. package/src/client.ts +5 -4
  300. package/src/http/Request.ts +3 -3
  301. package/src/http.ts +1 -1
  302. package/src/ids.ts +33 -6
  303. package/src/index.ts +20 -23
  304. package/src/middleware.ts +13 -9
  305. package/src/rpc/Invalidation.ts +261 -0
  306. package/src/rpc/MiddlewareMaker.ts +88 -80
  307. package/src/rpc/README.md +2 -2
  308. package/src/rpc/RpcContextMap.ts +7 -6
  309. package/src/rpc/RpcMiddleware.ts +19 -13
  310. package/src/rpc.ts +4 -4
  311. package/src/runtime.ts +56 -0
  312. package/src/setupRequest.ts +134 -0
  313. package/src/toast.ts +54 -0
  314. package/src/transform.ts +4 -4
  315. package/src/utils/effectify.ts +1 -1
  316. package/src/utils/gen.ts +8 -8
  317. package/src/utils/logLevel.ts +1 -1
  318. package/src/utils/logger.ts +4 -3
  319. package/src/utils.ts +85 -158
  320. package/src/validation.ts +2 -2
  321. package/src/withToast.ts +133 -0
  322. package/test/dist/rpc.test.d.ts.map +1 -1
  323. package/test/dist/secretURL.test.d.ts.map +1 -0
  324. package/test/dist/special.test.d.ts.map +1 -0
  325. package/test/moreStrings.test.ts +1 -1
  326. package/test/rpc.test.ts +46 -6
  327. package/test/schema.test.ts +459 -30
  328. package/test/secretURL.test.ts +160 -0
  329. package/test/special.test.ts +1026 -0
  330. package/test/utils.test.ts +7 -7
  331. package/tsconfig.base.json +6 -5
  332. package/tsconfig.json +3 -1
  333. package/tsconfig.json.bak +2 -2
  334. package/tsconfig.src.json +29 -29
  335. package/tsconfig.test.json +2 -2
  336. package/dist/Operations.d.ts +0 -123
  337. package/dist/Operations.d.ts.map +0 -1
  338. package/dist/Operations.js +0 -29
  339. package/dist/ServiceMap.d.ts.map +0 -1
  340. package/dist/ServiceMap.js +0 -91
  341. package/eslint.config.mjs +0 -26
  342. package/src/Operations.ts +0 -55
package/src/Schema/ext.ts CHANGED
@@ -1,10 +1,49 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-return */
3
- import { Effect, Option, pipe, Schema, type SchemaAST, SchemaGetter, SchemaIssue, SchemaTransformation, ServiceMap } from "effect"
3
+ /**
4
+ * # `withConstructorDefault` policy
5
+ *
6
+ * The `withConstructorDefault` properties exported throughout this module
7
+ * (and from `numbers.ts`, `moreStrings.ts`, `ids.ts`) attach a default value
8
+ * that is **only** applied during construction — i.e. when the field is
9
+ * omitted from the input to a Schema constructor / `.make(...)` call.
10
+ *
11
+ * They are **NOT** applied during `decode` (JSON, database rows, RPC payloads,
12
+ * etc.). Decoding a payload with a missing field will still fail with a parse
13
+ * error, exactly as if the default were not present.
14
+ *
15
+ * Concretely this means `withConstructorDefault` MUST NOT be relied on as a
16
+ * just-in-time migration mechanism for database fields. If a stored record is
17
+ * missing a newly added field, the constructor default will not fill it in on
18
+ * read — decoding will fail.
19
+ *
20
+ * ## Don't reach for `withDecodingDefault*` either
21
+ *
22
+ * The sibling `withDecodingDefaultType` (and `withDecodingDefault`) extensions
23
+ * exist, but they are discouraged for migrating persisted data. A missing
24
+ * field in a stored record is just as likely to be data corruption as it is
25
+ * an old-shape document; silently substituting a default hides the problem
26
+ * and can poison downstream aggregates.
27
+ *
28
+ * Prefer an **explicit, preferably versioned** migration of database data
29
+ * (a schema-version field, a one-shot backfill, or a transform on read that
30
+ * is gated on an explicit version marker) over shoving missing fields under
31
+ * the rug with a decode-time default.
32
+ */
33
+ import * as Config from "effect/Config"
34
+ import * as Effect from "effect/Effect"
35
+ import { pipe } from "effect/Function"
36
+ import * as Function from "effect/Function"
37
+ import * as Option from "effect/Option"
4
38
  import * as S from "effect/Schema"
5
- import { type NonEmptyReadonlyArray } from "../Array.js"
6
- import { extendM, typedKeysOf } from "../utils.js"
7
- import { type AST } from "./schema.js"
39
+ import { isDateValid } from "effect/Schema"
40
+ import type * as SchemaAST from "effect/SchemaAST"
41
+ import * as SchemaIssue from "effect/SchemaIssue"
42
+ import * as SchemaTransformation from "effect/SchemaTransformation"
43
+ import { type NonEmptyReadonlyArray } from "../Array.ts"
44
+ import * as Context from "../Context.ts"
45
+ import { extendM, typedKeysOf } from "../utils.ts"
46
+ import { type AST } from "./schema.ts"
8
47
 
9
48
  type ProvidedCodec<Self extends S.Top, R> = S.Codec<
10
49
  Self["Type"],
@@ -13,131 +52,429 @@ type ProvidedCodec<Self extends S.Top, R> = S.Codec<
13
52
  Exclude<Self["EncodingServices"], R>
14
53
  >
15
54
 
16
- // TODO: v4 migration — withConstructorDefault signature changed, propertySignature removed
17
- // Constraint relaxed from `Self extends S.Top & S.WithoutConstructorDefault` to `Self extends S.Top`
18
- // because `.pipe()` widens the schema type to `Top` which doesn't satisfy `WithoutConstructorDefault`.
19
- // The narrowing assertions below are safe — we're asserting "this schema hasn't had a default applied yet".
20
- export const withDefaultConstructor = <A>(
21
- makeDefault: () => NoInfer<A>
22
- ) =>
23
- <Self extends S.Top>(self: Self): S.withConstructorDefault<Self & S.WithoutConstructorDefault> => {
24
- type Narrowed = Self & S.WithoutConstructorDefault
25
- return S.withConstructorDefault<Narrowed>(
26
- () => Option.some(makeDefault() as Narrowed["~type.make.in"])
27
- )(self as Narrowed)
55
+ const concurrencySetting = Effect.runSync(
56
+ Config
57
+ .literal("unbounded", "SCHEMA_CONCURRENCY")
58
+ .pipe(Config.orElse(() => Config.number("SCHEMA_CONCURRENCY")), Config.option)
59
+ )
60
+
61
+ export const DefaultParseOptions: SchemaAST.ParseOptions = {
62
+ concurrency: Option.getOrElse(concurrencySetting, () => "unbounded" as const)
28
63
  }
29
64
 
65
+ /**
66
+ * Parse-options annotation used on schema constructors for decode paths where callers
67
+ * cannot currently pass parse options (notably some RPC / HttpApi integration paths).
68
+ *
69
+ * Keep this annotation in place so those framework-managed decodes still run with
70
+ * unbounded concurrency by default.
71
+ */
72
+ export const concurrencyUnbounded = { parseOptions: DefaultParseOptions } as const
73
+
74
+ type DecodeLike = (schema: any) => (input: any, options?: SchemaAST.ParseOptions) => any
75
+
76
+ export const withDefaultParseOptions = <Decode extends DecodeLike>(
77
+ decode: Decode,
78
+ defaultParseOptions: SchemaAST.ParseOptions = DefaultParseOptions
79
+ ): Decode =>
80
+ ((schema: any) => {
81
+ const run = decode(schema)
82
+ return (input: any, options?: SchemaAST.ParseOptions) => run(input, { ...defaultParseOptions, ...options })
83
+ }) as Decode
84
+
30
85
  // TODO: v4 migration - Date is no longer by default encoded to string.
31
- const DateFromString = Schema.Date.pipe(
32
- Schema.encodeTo(Schema.String, {
33
- decode: SchemaGetter.Date(),
34
- encode: SchemaGetter.transform((_) => _.toISOString())
35
- })
36
- )
86
+
87
+ const DateString = S.String.annotate({
88
+ identifier: "DateOrInvalid",
89
+ description: "an ISO 8601 date string that will be decoded as a Date (may be invalid)",
90
+ format: "date-time"
91
+ })
37
92
 
38
93
  /**
39
- * Like the default Schema `Date` but from String with `withDefault` => now
94
+ * Schema type for {@link DateFromString}.
95
+ *
96
+ * @category Schemas
97
+ * @since 4.0.0
40
98
  */
41
- export const Date = Object.assign(DateFromString, {
42
- withDefault: DateFromString.pipe(withDefaultConstructor(() => new global.Date()))
43
- })
99
+ export interface DateFromString extends S.decodeTo<S.Date, S.String> {}
44
100
 
45
101
  /**
46
- * Like the default Schema `Boolean` but with `withDefault` => false
102
+ * A transformation schema that parses an ISO 8601 string into a `Date`.
103
+ *
104
+ * Decoding:
105
+ * - A `string` is decoded as a `Date`.
106
+ *
107
+ * Encoding:
108
+ * - A `Date` is encoded as a `string`.
109
+ *
110
+ * @since 4.0.0
47
111
  */
112
+ export const DateFromString: DateFromString = DateString.pipe(S.decodeTo(S.Date, SchemaTransformation.dateFromString))
113
+
114
+ /** Like the default Schema `Date` but from String, with default helpers. */
115
+ export const Date = extendM(DateFromString, (s) => ({
116
+ /**
117
+ * Construction-only default `new Date()`. Applied only when the field is
118
+ * omitted from `.make(...)` input. NOT applied during decode — cannot be
119
+ * used to JIT-migrate database fields. See file-level note.
120
+ */
121
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))),
122
+ /**
123
+ * Decode-time default `new Date()`. **Discouraged for persisted data:** a
124
+ * missing field may be data corruption, not an old-shape document; silently
125
+ * substituting `new Date()` hides the problem. Prefer an explicit,
126
+ * preferably versioned migration over a decode-time fallback. See
127
+ * file-level note.
128
+ */
129
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new global.Date())))
130
+ }))
131
+
132
+ const DateValidString = S.String.annotate({
133
+ identifier: "Date",
134
+ description: "a valid ISO 8601 date string that will be decoded as a Date",
135
+ format: "date-time"
136
+ })
137
+
138
+ const DateValidFromString = DateValidString
139
+ .pipe(
140
+ S.decodeTo(S.Date, SchemaTransformation.dateFromString)
141
+ )
142
+ .check(isDateValid())
143
+
144
+ /** Like the default Schema `DateValid` but from String, with default helpers. */
145
+ export const DateValid = extendM(DateValidFromString, (s) => ({
146
+ /**
147
+ * Construction-only default `new Date()`. Applied only when the field is
148
+ * omitted from `.make(...)` input. NOT applied during decode — cannot be
149
+ * used to JIT-migrate database fields. See file-level note.
150
+ */
151
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))),
152
+ /**
153
+ * Decode-time default `new Date()`. **Discouraged for persisted data:** a
154
+ * missing field may be data corruption, not an old-shape document; silently
155
+ * substituting `new Date()` hides the problem. Prefer an explicit,
156
+ * preferably versioned migration over a decode-time fallback. See
157
+ * file-level note.
158
+ */
159
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new global.Date())))
160
+ }))
161
+
162
+ /** Like the default Schema `Boolean` but with default helpers. */
48
163
  export const Boolean = Object.assign(S.Boolean, {
49
- withDefault: S.Boolean.pipe(withDefaultConstructor(() => false))
164
+ /**
165
+ * Construction-only default `false`. Applied only when the field is
166
+ * omitted from `.make(...)` input. NOT applied during decode — cannot be
167
+ * used to JIT-migrate database fields. See file-level note.
168
+ */
169
+ withConstructorDefault: S.Boolean.pipe(S.withConstructorDefault(Effect.succeed(false))),
170
+ /**
171
+ * Decode-time default `false`. **Discouraged for persisted data:** a
172
+ * missing field may be data corruption, not an old-shape document; silently
173
+ * substituting `false` hides the problem. Prefer an explicit, preferably
174
+ * versioned migration over a decode-time fallback. See file-level note.
175
+ */
176
+ withDecodingDefaultType: S.Boolean.pipe(S.withDecodingDefaultType(Effect.succeed(false)))
50
177
  })
51
178
 
52
179
  /**
53
- * Like the default Schema `Number` but with `withDefault` => 0
180
+ * You probably want to use `Finite` instead of this. Like the default Schema
181
+ * `Number` but with default helpers.
54
182
  */
55
- export const Number = Object.assign(S.Number, { withDefault: S.Number.pipe(withDefaultConstructor(() => 0)) })
183
+ export const Number = Object.assign(S.Number, {
184
+ /**
185
+ * Construction-only default `0`. Applied only when the field is omitted
186
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
187
+ * JIT-migrate database fields. See file-level note.
188
+ */
189
+ withConstructorDefault: S.Number.pipe(S.withConstructorDefault(Effect.succeed(0))),
190
+ /**
191
+ * Decode-time default `0`. **Discouraged for persisted data:** a missing
192
+ * field may be data corruption, not an old-shape document; silently
193
+ * substituting `0` hides the problem. Prefer an explicit, preferably
194
+ * versioned migration over a decode-time fallback. See file-level note.
195
+ */
196
+ withDecodingDefaultType: S.Number.pipe(S.withDecodingDefaultType(Effect.succeed(0)))
197
+ })
56
198
 
57
- /**
58
- * Like the default Schema `Literal` but with `withDefault` => literals[0]
59
- */
60
- export const Literal = <Literals extends NonEmptyReadonlyArray<AST.LiteralValue>>(...literals: Literals) =>
199
+ /** Like the default Schema `Finite` but with default helpers. */
200
+ export const Finite = Object.assign(S.Finite, {
201
+ /**
202
+ * Construction-only default `0`. Applied only when the field is omitted
203
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
204
+ * JIT-migrate database fields. See file-level note.
205
+ */
206
+ withConstructorDefault: S.Finite.pipe(S.withConstructorDefault(Effect.succeed(0))),
207
+ /**
208
+ * Decode-time default `0`. **Discouraged for persisted data:** a missing
209
+ * field may be data corruption, not an old-shape document; silently
210
+ * substituting `0` hides the problem. Prefer an explicit, preferably
211
+ * versioned migration over a decode-time fallback. See file-level note.
212
+ */
213
+ withDecodingDefaultType: S.Finite.pipe(S.withDecodingDefaultType(Effect.succeed(0)))
214
+ })
215
+
216
+ /** Like the default Schema `Literals` but with default helpers. Default value is `literals[0]`. */
217
+ export const Literals = <const Literals extends NonEmptyReadonlyArray<AST.LiteralValue>>(literals: Literals) =>
61
218
  pipe(
62
219
  S.Literals(literals),
63
220
  (s) =>
64
221
  Object.assign(s, {
222
+ /** Override the default literal value used by `withConstructorDefault` / `withDecodingDefaultType`. */
65
223
  changeDefault: <A extends Literals[number]>(a: A) => {
66
224
  return Object.assign(S.Literals(literals), {
67
225
  Default: a,
68
- withDefault: s.pipe(withDefaultConstructor(() => a))
226
+ /**
227
+ * Construction-only default. Applied only when the field is
228
+ * omitted from `.make(...)` input. NOT applied during decode —
229
+ * cannot be used to JIT-migrate database fields. See file-level
230
+ * note.
231
+ */
232
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.succeed(a))),
233
+ /**
234
+ * Decode-time default. **Discouraged for persisted data:** a
235
+ * missing field may be data corruption, not an old-shape
236
+ * document; silently substituting hides the problem. Prefer an
237
+ * explicit, preferably versioned migration over a decode-time
238
+ * fallback. See file-level note.
239
+ */
240
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(a)))
69
241
  }) // todo: copy annotations from original?
70
242
  },
71
- Default: literals[0] as typeof literals[0],
72
- withDefault: s.pipe(withDefaultConstructor(() => literals[0]))
243
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- load-bearing: Object.assign widens the field type without it, breaking `expectTypeOf(l.Default).toEqualTypeOf<"a">()` in tests
244
+ Default: literals[0] as Literals[0],
245
+ /**
246
+ * Construction-only default `literals[0]`. Applied only when the
247
+ * field is omitted from `.make(...)` input. NOT applied during
248
+ * decode — cannot be used to JIT-migrate database fields. See
249
+ * file-level note.
250
+ */
251
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.succeed(literals[0]))),
252
+ /**
253
+ * Decode-time default `literals[0]`. **Discouraged for persisted
254
+ * data:** a missing field may be data corruption, not an old-shape
255
+ * document; silently substituting hides the problem. Prefer an
256
+ * explicit, preferably versioned migration over a decode-time
257
+ * fallback. See file-level note.
258
+ */
259
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(literals[0])))
73
260
  })
74
261
  )
75
262
 
76
- /**
77
- * Like the default Schema `Array` but with `withDefault` => []
78
- */
263
+ /** Like the default Schema `Array` but with default helpers. */
79
264
  export function Array<ValueSchema extends S.Top>(value: ValueSchema) {
80
265
  return pipe(
81
- S.Array(value),
82
- (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => [])) })
266
+ S.Array(value).annotate(concurrencyUnbounded),
267
+ (s) =>
268
+ Object.assign(s, {
269
+ /**
270
+ * Construction-only default `[]`. Applied only when the field is
271
+ * omitted from `.make(...)` input. NOT applied during decode —
272
+ * cannot be used to JIT-migrate database fields. See file-level
273
+ * note.
274
+ */
275
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => []))),
276
+ /**
277
+ * Decode-time default `[]`. **Discouraged for persisted data:** a
278
+ * missing field may be data corruption, not an old-shape document;
279
+ * silently substituting `[]` hides the problem. Prefer an explicit,
280
+ * preferably versioned migration over a decode-time fallback. See
281
+ * file-level note.
282
+ */
283
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => [])))
284
+ })
83
285
  )
84
286
  }
85
287
 
86
288
  /**
87
- * Like the default Schema `Map` but with `withDefault` => []
289
+ * An annotated `S.Array` of unique items that decodes to a `ReadonlySet`.
88
290
  */
89
- function Map_<KeySchema extends S.Top, ValueSchema extends S.Top>(input: { key: KeySchema; value: ValueSchema }) {
90
- return pipe(
91
- S.ReadonlyMap(input.key, input.value),
92
- (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => new global.Map())) })
291
+ export const ReadonlySetFromArray = <ValueSchema extends S.Top>(value: ValueSchema) => {
292
+ const from = S
293
+ .Array(value)
294
+ .annotate({ ...concurrencyUnbounded, expected: "an array of unique items that will be decoded as a ReadonlySet" })
295
+ const to = S.instanceOf(Set) as S.instanceOf<ReadonlySet<ValueSchema["Type"]>>
296
+ const schema = from.pipe(
297
+ S.decodeTo(
298
+ to,
299
+ SchemaTransformation.transform({
300
+ decode: (arr) => new Set(arr) as ReadonlySet<ValueSchema["Type"]>,
301
+ encode: (set) => [...set]
302
+ })
303
+ )
93
304
  )
305
+ return schema
94
306
  }
95
307
 
96
- export { Map_ as Map }
97
-
98
308
  /**
99
- * Like the default Schema `ReadonlySet` but with `withDefault` => new Set()
309
+ * An annotated `S.Array` of key-value tuples that decodes to a `ReadonlyMap`.
100
310
  */
311
+ export const ReadonlyMapFromArray = <KeySchema extends S.Top, ValueSchema extends S.Top>(pair: {
312
+ readonly key: KeySchema
313
+ readonly value: ValueSchema
314
+ }) => {
315
+ const from = S
316
+ .Array(S.Tuple([pair.key, pair.value]))
317
+ .annotate({
318
+ ...concurrencyUnbounded,
319
+ expected: "an array of key-value tuples that will be decoded as a ReadonlyMap"
320
+ })
321
+ const to = S.instanceOf(Map) as S.instanceOf<
322
+ ReadonlyMap<KeySchema["Type"], ValueSchema["Type"]>
323
+ >
324
+ const schema = from.pipe(
325
+ S.decodeTo(
326
+ to,
327
+ SchemaTransformation.transform({
328
+ decode: (
329
+ arr
330
+ ) => new Map(arr) as ReadonlyMap<KeySchema["Type"], ValueSchema["Type"]>,
331
+ encode: (
332
+ map
333
+ ) => [...map.entries()] as any // fu
334
+ })
335
+ )
336
+ )
337
+ return schema
338
+ }
339
+
340
+ /** Like the default Schema `ReadonlySet` but from Array, with default helpers. */
101
341
  export const ReadonlySet = <ValueSchema extends S.Top>(value: ValueSchema) =>
102
342
  pipe(
103
- S.ReadonlySet(value),
343
+ ReadonlySetFromArray(value),
104
344
  (s) =>
105
- Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => new Set<S.Schema.Type<ValueSchema>>())) })
345
+ Object.assign(s, {
346
+ /**
347
+ * Construction-only default `new Set()`. Applied only when the field
348
+ * is omitted from `.make(...)` input. NOT applied during decode —
349
+ * cannot be used to JIT-migrate database fields. See file-level
350
+ * note.
351
+ */
352
+ withConstructorDefault: s.pipe(
353
+ S.withConstructorDefault(Effect.sync(() => new Set<ValueSchema["Type"]>()))
354
+ ),
355
+ /**
356
+ * Decode-time default `new Set()`. **Discouraged for persisted
357
+ * data:** a missing field may be data corruption, not an old-shape
358
+ * document; silently substituting an empty set hides the problem.
359
+ * Prefer an explicit, preferably versioned migration over a
360
+ * decode-time fallback. See file-level note.
361
+ */
362
+ withDecodingDefaultType: s.pipe(
363
+ S.withDecodingDefaultType(Effect.sync(() => new Set<ValueSchema["Type"]>()))
364
+ )
365
+ })
106
366
  )
107
367
 
108
- /**
109
- * Like the default Schema `ReadonlyMap` but with `withDefault` => new Map()
110
- */
368
+ /** Like the default Schema `ReadonlyMap` but from Array, with default helpers. */
111
369
  export const ReadonlyMap = <KeySchema extends S.Top, ValueSchema extends S.Top>(pair: {
112
370
  readonly key: KeySchema
113
371
  readonly value: ValueSchema
114
372
  }) =>
115
373
  pipe(
116
- S.ReadonlyMap(pair.key, pair.value),
117
- (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => new Map())) })
374
+ ReadonlyMapFromArray(pair),
375
+ (s) =>
376
+ Object.assign(s, {
377
+ /**
378
+ * Construction-only default `new Map()`. Applied only when the field
379
+ * is omitted from `.make(...)` input. NOT applied during decode —
380
+ * cannot be used to JIT-migrate database fields. See file-level
381
+ * note.
382
+ */
383
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new Map()))),
384
+ /**
385
+ * Decode-time default `new Map()`. **Discouraged for persisted
386
+ * data:** a missing field may be data corruption, not an old-shape
387
+ * document; silently substituting an empty map hides the problem.
388
+ * Prefer an explicit, preferably versioned migration over a
389
+ * decode-time fallback. See file-level note.
390
+ */
391
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new Map())))
392
+ })
118
393
  )
119
394
 
120
- /**
121
- * Like the default Schema `NullOr` but with `withDefault` => null
122
- */
395
+ /** Like the default Schema `NullOr` but with default helpers. */
123
396
  export const NullOr = <Schema extends S.Top>(self: Schema) =>
124
397
  pipe(
125
398
  S.NullOr(self),
126
- (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => null)) })
399
+ (s) =>
400
+ Object.assign(s, {
401
+ /**
402
+ * Construction-only default `null`. Applied only when the field is
403
+ * omitted from `.make(...)` input. NOT applied during decode —
404
+ * cannot be used to JIT-migrate database fields. See file-level
405
+ * note.
406
+ */
407
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.succeed(null))),
408
+ /**
409
+ * Decode-time default `null`. **Discouraged for persisted data:** a
410
+ * missing field may be data corruption, not an old-shape document;
411
+ * silently substituting `null` hides the problem. Prefer an
412
+ * explicit, preferably versioned migration over a decode-time
413
+ * fallback. See file-level note.
414
+ */
415
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(null)))
416
+ })
127
417
  )
128
418
 
129
- export const defaultDate = <Schema extends S.Top>(schema: Schema) =>
130
- schema.pipe(withDefaultConstructor(() => new global.Date()))
419
+ /**
420
+ * Attach a `withConstructorDefault` of `new Date()` to any schema.
421
+ *
422
+ * **Construction-only.** Applied only when the field is omitted from
423
+ * `.make(...)` input. NOT applied during decode — cannot be used to
424
+ * JIT-migrate database fields. See file-level note.
425
+ */
426
+ export const defaultDate = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
427
+ schema.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date())))
131
428
 
132
- export const defaultBool = <Schema extends S.Top>(schema: Schema) => schema.pipe(withDefaultConstructor(() => false))
429
+ /**
430
+ * Attach a `withConstructorDefault` of `false` to any schema.
431
+ *
432
+ * **Construction-only.** Applied only when the field is omitted from
433
+ * `.make(...)` input. NOT applied during decode — cannot be used to
434
+ * JIT-migrate database fields. See file-level note.
435
+ */
436
+ export const defaultBool = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
437
+ schema.pipe(S.withConstructorDefault(Effect.succeed(false)))
133
438
 
134
- export const defaultNullable = <Schema extends S.Top>(schema: Schema) => schema.pipe(withDefaultConstructor(() => null))
439
+ /**
440
+ * Attach a `withConstructorDefault` of `null` to any schema.
441
+ *
442
+ * **Construction-only.** Applied only when the field is omitted from
443
+ * `.make(...)` input. NOT applied during decode — cannot be used to
444
+ * JIT-migrate database fields. See file-level note.
445
+ */
446
+ export const defaultNullable = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
447
+ schema.pipe(S.withConstructorDefault(Effect.succeed(null)))
135
448
 
136
- export const defaultArray = <Schema extends S.Top>(schema: Schema) => schema.pipe(withDefaultConstructor(() => []))
449
+ /**
450
+ * Attach a `withConstructorDefault` of `[]` to any schema.
451
+ *
452
+ * **Construction-only.** Applied only when the field is omitted from
453
+ * `.make(...)` input. NOT applied during decode — cannot be used to
454
+ * JIT-migrate database fields. See file-level note.
455
+ */
456
+ export const defaultArray = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
457
+ schema.pipe(S.withConstructorDefault(Effect.sync(() => [])))
137
458
 
138
- export const defaultMap = <Schema extends S.Top>(schema: Schema) => schema.pipe(withDefaultConstructor(() => new Map()))
459
+ /**
460
+ * Attach a `withConstructorDefault` of `new Map()` to any schema.
461
+ *
462
+ * **Construction-only.** Applied only when the field is omitted from
463
+ * `.make(...)` input. NOT applied during decode — cannot be used to
464
+ * JIT-migrate database fields. See file-level note.
465
+ */
466
+ export const defaultMap = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
467
+ schema.pipe(S.withConstructorDefault(Effect.sync(() => new Map())))
139
468
 
140
- export const defaultSet = <Schema extends S.Top>(schema: Schema) => schema.pipe(withDefaultConstructor(() => new Set()))
469
+ /**
470
+ * Attach a `withConstructorDefault` of `new Set()` to any schema.
471
+ *
472
+ * **Construction-only.** Applied only when the field is omitted from
473
+ * `.make(...)` input. NOT applied during decode — cannot be used to
474
+ * JIT-migrate database fields. See file-level note.
475
+ */
476
+ export const defaultSet = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
477
+ schema.pipe(S.withConstructorDefault(Effect.sync(() => new Set())))
141
478
 
142
479
  export const withDefaultMake = <Self extends S.Top>(s: Self) => {
143
480
  const a = Object.assign(S.decodeSync(s as any) as WithDefaults<Self>, s)
@@ -166,9 +503,25 @@ export type WithDefaults<Self extends S.Top> = (
166
503
  // export type UnionToIntersection3<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I
167
504
  // : never
168
505
 
506
+ /** Union of `DateValid` and `Date`, with default helpers. */
169
507
  export const inputDate = extendM(
170
- S.Union([S.DateValid, S.Date]),
171
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => new globalThis.Date())) })
508
+ S.Union([S.DateValid, Date]),
509
+ (s) => ({
510
+ /**
511
+ * Construction-only default `new Date()`. Applied only when the field is
512
+ * omitted from `.make(...)` input. NOT applied during decode — cannot be
513
+ * used to JIT-migrate database fields. See file-level note.
514
+ */
515
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new globalThis.Date()))),
516
+ /**
517
+ * Decode-time default `new Date()`. **Discouraged for persisted data:** a
518
+ * missing field may be data corruption, not an old-shape document;
519
+ * silently substituting `new Date()` hides the problem. Prefer an
520
+ * explicit, preferably versioned migration over a decode-time fallback.
521
+ * See file-level note.
522
+ */
523
+ withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new globalThis.Date())))
524
+ })
172
525
  )
173
526
 
174
527
  export interface UnionBrand {}
@@ -218,7 +571,7 @@ export const transformTo = <To extends S.Top, From extends S.Top>(
218
571
  { message: "One way schema transformation, encoding is not allowed" }
219
572
  )
220
573
  )
221
- }) as any
574
+ })
222
575
  )
223
576
  )
224
577
 
@@ -235,7 +588,7 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
235
588
  S.decodeTo(
236
589
  to,
237
590
  SchemaTransformation.transformOrFail({
238
- decode: decode as any,
591
+ decode,
239
592
  encode: (i: any) =>
240
593
  Effect.fail(
241
594
  new SchemaIssue.Forbidden(
@@ -243,34 +596,36 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
243
596
  { message: "One way schema transformation, encoding is not allowed" }
244
597
  )
245
598
  )
246
- }) as any
599
+ })
247
600
  )
248
601
  )
249
602
 
250
- export const provide = <Self extends S.Top, R>(
251
- self: Self,
252
- context: ServiceMap.ServiceMap<R>
253
- ): ProvidedCodec<Self, R> => {
603
+ export const provide: {
604
+ <R>(context: Context.Context<R>): <Self extends S.Top>(self: Self) => ProvidedCodec<Self, R>
605
+ <Self extends S.Top, R>(self: Self, context: Context.Context<R>): ProvidedCodec<Self, R>
606
+ } = Function.dual(2, <Self extends S.Top, R>(self: Self, context: Context.Context<R>): ProvidedCodec<Self, R> => {
254
607
  const prov = Effect.provide(context)
255
608
  return self.pipe(
256
609
  S.middlewareDecoding((effect) => prov(effect)),
257
610
  S.middlewareEncoding((effect) => prov(effect))
258
- ) as ProvidedCodec<Self, R>
259
- }
260
- export const contextFromServices = <
611
+ )
612
+ })
613
+ export const contextFromServices = Effect.fnUntraced(function*<
261
614
  Self extends S.Top,
262
- Tags extends ReadonlyArray<ServiceMap.Key<any, any>>
615
+ Tags extends ReadonlyArray<Context.Key<any, any>>
616
+ >(self: Self, ...services: Tags) {
617
+ const context: Context.Context<Context.Service.Identifier<Tags[number]>> = Context.pick(...services)(
618
+ yield* Effect.context<Context.Service.Identifier<Tags[number]>>()
619
+ )
620
+ return provide(self, context)
621
+ }) as <
622
+ Self extends S.Top,
623
+ Tags extends ReadonlyArray<Context.Key<any, any>>
263
624
  >(
264
625
  self: Self,
265
626
  ...services: Tags
266
- ): Effect.Effect<
267
- ProvidedCodec<Self, ServiceMap.Service.Identifier<Tags[number]>>,
627
+ ) => Effect.Effect<
628
+ ProvidedCodec<Self, Context.Service.Identifier<Tags[number]>>,
268
629
  never,
269
- ServiceMap.Service.Identifier<Tags[number]>
270
- > =>
271
- Effect.gen(function*() {
272
- const context: ServiceMap.ServiceMap<ServiceMap.Service.Identifier<Tags[number]>> = ServiceMap.pick(...services)(
273
- yield* Effect.services<ServiceMap.Service.Identifier<Tags[number]>>()
274
- )
275
- return provide(self, context)
276
- })
630
+ Context.Service.Identifier<Tags[number]>
631
+ >