effect-app 4.0.0-beta.33 → 4.0.0-beta.331

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 +1628 -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 +136 -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 +611 -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 +71 -0
  49. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  50. package/dist/Model/Repository/makeRepo.js +30 -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 +72 -0
  55. package/dist/Model/Repository/validation.d.ts.map +1 -0
  56. package/dist/Model/Repository/validation.js +39 -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 +630 -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 +370 -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 +5 -5
  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 +12 -6
  138. package/dist/Schema/ext.d.ts +335 -61
  139. package/dist/Schema/ext.d.ts.map +1 -1
  140. package/dist/Schema/ext.js +388 -63
  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 +90 -53
  144. package/dist/Schema/numbers.d.ts +33 -21
  145. package/dist/Schema/numbers.d.ts.map +1 -1
  146. package/dist/Schema/numbers.js +65 -12
  147. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  148. package/dist/Schema/phoneNumber.js +11 -7
  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 +225 -7
  156. package/dist/Schema.d.ts.map +1 -1
  157. package/dist/Schema.js +193 -26
  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 +215 -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 +157 -39
  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 -30
  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 +32 -14
  202. package/dist/ids.d.ts.map +1 -1
  203. package/dist/ids.js +38 -6
  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 +1124 -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 +988 -0
  273. package/src/Model/Repository/legacy.ts +29 -0
  274. package/src/Model/Repository/makeRepo.ts +168 -0
  275. package/src/Model/Repository/service.ts +676 -0
  276. package/src/Model/Repository/validation.ts +38 -0
  277. package/src/Model/Repository.ts +7 -0
  278. package/src/Model/dsl.ts +129 -0
  279. package/src/Model/filter/filterApi.ts +78 -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 +3092 -0
  289. package/src/Model/query/new-kid-interpreter.ts +532 -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 +24 -9
  303. package/src/Schema/email.ts +14 -7
  304. package/src/Schema/ext.ts +508 -102
  305. package/src/Schema/moreStrings.ts +217 -86
  306. package/src/Schema/numbers.ts +107 -28
  307. package/src/Schema/phoneNumber.ts +13 -9
  308. package/src/Schema/schema.ts +1 -1
  309. package/src/Schema/strings.ts +23 -14
  310. package/src/Schema.ts +403 -46
  311. package/src/SchemaAST.ts +1 -0
  312. package/src/Set.ts +6 -2
  313. package/src/Store.ts +325 -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 +301 -141
  321. package/src/client/clientFor.ts +107 -34
  322. package/src/client/errors.ts +100 -29
  323. package/src/client/makeClient.ts +594 -80
  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 +45 -7
  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 +57 -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 +55 -10
  352. package/test/rpc.test.ts +38 -10
  353. package/test/rpcMiddlewareContext.test.ts +63 -0
  354. package/test/schema.test.ts +505 -26
  355. package/test/secretURL.test.ts +160 -0
  356. package/test/special.test.ts +1261 -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,21 +1,36 @@
1
- import { pipe } from "effect"
1
+ /**
2
+ * Branded string ID schemas with `.withConstructorDefault` extensions.
3
+ *
4
+ * Each `.withConstructorDefault` here is **only** applied when the field is
5
+ * omitted during construction (`.make(...)`). It is **not** applied during
6
+ * decode and therefore cannot be used to JIT-migrate database fields.
7
+ *
8
+ * For persisted data, prefer an explicit, preferably versioned migration
9
+ * over decode-time fallbacks. See `./ext.ts` for the full policy note.
10
+ */
2
11
  import type { Refinement } from "effect-app/Function"
3
12
  import { extendM } from "effect-app/utils"
13
+ import type * as B from "effect/Brand"
14
+ import * as Effect from "effect/Effect"
15
+ import { pipe } from "effect/Function"
4
16
  import * as S from "effect/Schema"
17
+ import * as Getter from "effect/SchemaGetter"
18
+ import * as SchemaIssue from "effect/SchemaIssue"
5
19
  import type { Simplify } from "effect/Types"
6
20
  import { customRandom, nanoid, urlAlphabet } from "nanoid"
7
21
  import validator from "validator"
8
- import { fromBrand, nominal } from "./brand.js"
9
- import { withDefaultConstructor, withDefaultMake, type WithDefaults } from "./ext.js"
10
- import { type B } from "./schema.js"
11
- import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.js"
22
+ import type * as SchemaAST from "../SchemaAST.ts"
23
+ import { type BrandedSchema, fromBrand, nominal } from "./brand.ts"
24
+ import { withDefaultMake } from "./ext.ts"
25
+ import { type B as SchemaB } from "./schema.ts"
26
+ import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.ts"
12
27
 
13
28
  const nonEmptyString = S.NonEmptyString
14
29
 
15
30
  /**
16
31
  * A string that is at least 1 character long and a maximum of 50.
17
32
  */
18
- export interface NonEmptyString50Brand extends Simplify<B.Brand<"NonEmptyString50"> & NonEmptyString64Brand> {}
33
+ export interface NonEmptyString50Brand extends Simplify<SchemaB.Brand<"NonEmptyString50"> & NonEmptyString64Brand> {}
19
34
 
20
35
  /**
21
36
  * A string that is at least 1 character long and a maximum of 50.
@@ -25,11 +40,13 @@ export type NonEmptyString50 = string & NonEmptyString50Brand
25
40
  /**
26
41
  * A string that is at least 1 character long and a maximum of 50.
27
42
  */
28
- export const NonEmptyString50 = nonEmptyString.pipe(
43
+ export interface NonEmptyString50Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString50> {
44
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString50
45
+ }
46
+ export const NonEmptyString50: NonEmptyString50Schema = nonEmptyString.pipe(
29
47
  S.check(S.isMaxLength(50)),
30
- fromBrand(nominal<NonEmptyString50>(), {
48
+ fromBrand<NonEmptyString50>(nominal<NonEmptyString50>(), {
31
49
  identifier: "NonEmptyString50",
32
- title: "NonEmptyString50",
33
50
  jsonSchema: {}
34
51
  }),
35
52
  withDefaultMake
@@ -38,7 +55,7 @@ export const NonEmptyString50 = nonEmptyString.pipe(
38
55
  /**
39
56
  * A string that is at least 1 character long and a maximum of 64.
40
57
  */
41
- export interface NonEmptyString64Brand extends Simplify<B.Brand<"NonEmptyString64"> & NonEmptyString80Brand> {}
58
+ export interface NonEmptyString64Brand extends Simplify<SchemaB.Brand<"NonEmptyString64"> & NonEmptyString80Brand> {}
42
59
 
43
60
  /**
44
61
  * A string that is at least 1 character long and a maximum of 64.
@@ -48,11 +65,13 @@ export type NonEmptyString64 = string & NonEmptyString64Brand
48
65
  /**
49
66
  * A string that is at least 1 character long and a maximum of 64.
50
67
  */
51
- export const NonEmptyString64 = nonEmptyString.pipe(
68
+ export interface NonEmptyString64Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString64> {
69
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString64
70
+ }
71
+ export const NonEmptyString64: NonEmptyString64Schema = nonEmptyString.pipe(
52
72
  S.check(S.isMaxLength(64)),
53
- fromBrand(nominal<NonEmptyString64>(), {
73
+ fromBrand<NonEmptyString64>(nominal<NonEmptyString64>(), {
54
74
  identifier: "NonEmptyString64",
55
- title: "NonEmptyString64",
56
75
  jsonSchema: {}
57
76
  }),
58
77
  withDefaultMake
@@ -61,7 +80,7 @@ export const NonEmptyString64 = nonEmptyString.pipe(
61
80
  /**
62
81
  * A string that is at least 1 character long and a maximum of 80.
63
82
  */
64
- export interface NonEmptyString80Brand extends Simplify<B.Brand<"NonEmptyString80"> & NonEmptyString100Brand> {}
83
+ export interface NonEmptyString80Brand extends Simplify<SchemaB.Brand<"NonEmptyString80"> & NonEmptyString100Brand> {}
65
84
 
66
85
  /**
67
86
  * A string that is at least 1 character long and a maximum of 80.
@@ -72,11 +91,13 @@ export type NonEmptyString80 = string & NonEmptyString80Brand
72
91
  * A string that is at least 1 character long and a maximum of 80.
73
92
  */
74
93
 
75
- export const NonEmptyString80 = nonEmptyString.pipe(
94
+ export interface NonEmptyString80Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString80> {
95
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString80
96
+ }
97
+ export const NonEmptyString80: NonEmptyString80Schema = nonEmptyString.pipe(
76
98
  S.check(S.isMaxLength(80)),
77
- fromBrand(nominal<NonEmptyString80>(), {
99
+ fromBrand<NonEmptyString80>(nominal<NonEmptyString80>(), {
78
100
  identifier: "NonEmptyString80",
79
- title: "NonEmptyString80",
80
101
  jsonSchema: {}
81
102
  }),
82
103
  withDefaultMake
@@ -85,7 +106,7 @@ export const NonEmptyString80 = nonEmptyString.pipe(
85
106
  /**
86
107
  * A string that is at least 1 character long and a maximum of 100.
87
108
  */
88
- export interface NonEmptyString100Brand extends Simplify<B.Brand<"NonEmptyString100"> & NonEmptyString255Brand> {}
109
+ export interface NonEmptyString100Brand extends Simplify<SchemaB.Brand<"NonEmptyString100"> & NonEmptyString255Brand> {}
89
110
 
90
111
  /**
91
112
  * A string that is at least 1 character long and a maximum of 100.
@@ -95,11 +116,13 @@ export type NonEmptyString100 = string & NonEmptyString100Brand
95
116
  /**
96
117
  * A string that is at least 1 character long and a maximum of 100.
97
118
  */
98
- export const NonEmptyString100 = nonEmptyString.pipe(
119
+ export interface NonEmptyString100Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString100> {
120
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString100
121
+ }
122
+ export const NonEmptyString100: NonEmptyString100Schema = nonEmptyString.pipe(
99
123
  S.check(S.isMaxLength(100)),
100
- fromBrand(nominal<NonEmptyString100>(), {
124
+ fromBrand<NonEmptyString100>(nominal<NonEmptyString100>(), {
101
125
  identifier: "NonEmptyString100",
102
- title: "NonEmptyString100",
103
126
  jsonSchema: {}
104
127
  }),
105
128
  withDefaultMake
@@ -108,7 +131,7 @@ export const NonEmptyString100 = nonEmptyString.pipe(
108
131
  /**
109
132
  * A string that is at least 3 character long and a maximum of 255.
110
133
  */
111
- export interface Min3String255Brand extends Simplify<B.Brand<"Min3String255"> & NonEmptyString255Brand> {}
134
+ export interface Min3String255Brand extends Simplify<SchemaB.Brand<"Min3String255"> & NonEmptyString255Brand> {}
112
135
 
113
136
  /**
114
137
  * A string that is at least 3 character long and a maximum of 255.
@@ -118,58 +141,115 @@ export type Min3String255 = string & Min3String255Brand
118
141
  /**
119
142
  * A string that is at least 3 character long and a maximum of 255.
120
143
  */
121
- export const Min3String255 = pipe(
144
+ export interface Min3String255Schema extends BrandedSchema<S.String, Min3String255> {
145
+ (i: string, options?: SchemaAST.ParseOptions): Min3String255
146
+ }
147
+ export const Min3String255: Min3String255Schema = pipe(
122
148
  S.String,
123
149
  S.check(S.isMinLength(3), S.isMaxLength(255)),
124
- fromBrand(nominal<Min3String255>(), { identifier: "Min3String255", title: "Min3String255", jsonSchema: {} }),
150
+ fromBrand<Min3String255>(nominal<Min3String255>(), {
151
+ identifier: "Min3String255",
152
+ jsonSchema: {}
153
+ }),
125
154
  withDefaultMake
126
155
  )
127
156
 
128
157
  /**
129
158
  * A string that is at least 6 characters long and a maximum of 50.
130
159
  */
131
- export interface StringIdBrand extends Simplify<B.Brand<"StringId"> & NonEmptyString50Brand> {}
160
+ export interface StringIdBrand extends Simplify<SchemaB.Brand<"StringId"> & NonEmptyString50Brand> {}
132
161
 
133
162
  /**
134
163
  * A string that is at least 6 characters long and a maximum of 50.
135
164
  */
136
165
  export type StringId = string & StringIdBrand
137
166
 
138
- const makeStringId = (): StringId => nanoid() as unknown as StringId
139
167
  const minLength = 6
140
168
  const maxLength = 50
141
- const size = 21
142
- const length = 10 * size
143
- const StringIdArb = (): S.LazyArbitrary<StringId> => (fc) =>
144
- fc
145
- .uint8Array({ minLength: length, maxLength: length })
146
- .map((_) => customRandom(urlAlphabet, size, (size) => _.subarray(0, size))() as StringId)
169
+ const nanoidSize = 21
170
+ const nanoidByteLength = 10 * nanoidSize
171
+
172
+ const StringIdString = pipe(
173
+ S.String,
174
+ S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
175
+ fromBrand<StringId>(nominal<StringId>(), {
176
+ identifier: "StringId",
177
+ jsonSchema: {}
178
+ })
179
+ )
180
+
181
+ const nanoidFromBytes = (bytes: Uint8Array) =>
182
+ customRandom(urlAlphabet, nanoidSize, (size) => bytes.subarray(0, size))() as StringId
183
+
184
+ // JSON stays a branded string (toCodec). Generation uses toCodecArbitrary — the native
185
+ // replacement for fast-check `toArbitrary` — same as the old StringIdArb:
186
+ // uint8Array(210).map(bytes => customRandom(urlAlphabet, 21, …)).
187
+ const StringIdSchemaBase = S.declareConstructor<StringId, string>()(
188
+ [],
189
+ () => (input, ast, options) =>
190
+ S.is(StringIdString)(input)
191
+ ? Effect.succeed(input)
192
+ : Effect.fail(new SchemaIssue.InvalidType(ast, input, options)),
193
+ {
194
+ identifier: "StringId",
195
+ expected: "StringId",
196
+ toCodec: () =>
197
+ S.link<StringId>()(StringIdString, {
198
+ decode: Getter.passthrough(),
199
+ encode: Getter.passthrough()
200
+ }),
201
+ toCodecArbitrary: () =>
202
+ S.link<StringId>()(
203
+ S.Uint8Array.check(S.isMinLength(nanoidByteLength), S.isMaxLength(nanoidByteLength)),
204
+ {
205
+ decode: Getter.transform(nanoidFromBytes),
206
+ encode: Getter.forbiddenEncoding
207
+ }
208
+ )
209
+ }
210
+ )
211
+ const makeStringId = (s?: string): StringId =>
212
+ s !== undefined ? S.decodeSync(StringIdString)(s) : nanoid() as unknown as StringId
147
213
  /**
148
214
  * A string that is at least 6 characters long and a maximum of 50.
215
+ *
216
+ * `.withConstructorDefault` => fresh `nanoid()` (construction-only; not
217
+ * applied during decode — see file-level note).
149
218
  */
150
- export const StringId = extendM(
151
- pipe(
152
- S.String,
153
- S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
154
- fromBrand(nominal<StringId>(), {
155
- identifier: "StringId",
156
- title: "StringId",
157
- toArbitrary: () => (fc) => StringIdArb()(fc),
158
- jsonSchema: {}
159
- })
160
- ),
219
+ export interface StringIdSchema extends S.declareConstructor<StringId, string, readonly [], StringId> {
220
+ (i: string, options?: SchemaAST.ParseOptions): StringId
221
+ /** Generate fresh `nanoid()`-shaped `StringId`. */
222
+ make(): StringId
223
+ /** Construct a `StringId` from a known string (validated via decodeSync). */
224
+ make(input: string, options?: S.MakeOptions): StringId
225
+ readonly withConstructorDefault: S.withConstructorDefault<
226
+ S.declareConstructor<StringId, string, readonly [], StringId>
227
+ >
228
+ }
229
+ export const StringId: StringIdSchema = extendM(
230
+ StringIdSchemaBase,
161
231
  (s) => ({
162
232
  make: makeStringId,
163
- withDefault: s.pipe(withDefaultConstructor(makeStringId))
233
+ /**
234
+ * Construction-only default: fresh `nanoid()`-shaped `StringId`. Applied
235
+ * only when the field is omitted from `.make(...)` input. NOT applied
236
+ * during decode — cannot be used to JIT-migrate database fields. See
237
+ * file-level note.
238
+ */
239
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(makeStringId)))
164
240
  })
165
241
  )
166
242
  .pipe(withDefaultMake)
167
243
 
168
- // const prefixedStringIdUnsafe = (prefix: string) => StringId(prefix + StringId.make())
169
-
170
- // const prefixedStringIdUnsafeThunk = (prefix: string) => () => prefixedStringIdUnsafe(prefix)
171
-
172
- export function prefixedStringId<Brand extends StringId>() {
244
+ /**
245
+ * Build a `StringId` schema whose values are required to start with a fixed
246
+ * `prefix` (joined with `separator`, default `-`).
247
+ *
248
+ * The returned schema exposes `.withConstructorDefault` that mints a fresh
249
+ * prefixed id. Construction-only — not applied during decode; see file-level
250
+ * note.
251
+ */
252
+ export function prefixedStringId<Type extends StringId>() {
173
253
  return <Prefix extends string, Separator extends string = "-">(
174
254
  prefix: Prefix,
175
255
  name: string,
@@ -177,27 +257,42 @@ export function prefixedStringId<Brand extends StringId>() {
177
257
  ) => {
178
258
  type FullPrefix = `${Prefix}${Separator}`
179
259
  const pref = `${prefix}${separator ?? "-"}` as FullPrefix
180
- const arb = (): S.LazyArbitrary<string & Brand> => (fc) =>
181
- StringIdArb()(fc).map(
182
- (x) => (pref + x.substring(0, 50 - pref.length)) as Brand
183
- )
184
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
185
- const s: S.Codec<string & Brand, string> = StringId
186
- .pipe(
187
- S.refine((x: string): x is string & Brand => x.startsWith(pref), {
188
- identifier: name,
189
- title: name
190
- }),
191
- S.annotate({
192
- toArbitrary: () => (fc) => arb()(fc)
193
- })
194
- ) as S.Codec<string & Brand, string>
260
+ const PrefixedString = StringIdString.pipe(
261
+ S.refine((x): x is Type => x.startsWith(pref), { identifier: name })
262
+ )
263
+ // Pre-rc.114: StringIdArb().map(x => pref + x.substring(0, 50 - pref.length))
264
+ const s = S.declareConstructor<Type, string>()(
265
+ [],
266
+ () => (input, ast, options) =>
267
+ S.is(PrefixedString)(input)
268
+ ? Effect.succeed(input)
269
+ : Effect.fail(new SchemaIssue.InvalidType(ast, input, options)),
270
+ {
271
+ identifier: name,
272
+ expected: name,
273
+ toCodec: () =>
274
+ S.link<Type>()(PrefixedString, {
275
+ decode: Getter.passthrough(),
276
+ encode: Getter.passthrough()
277
+ }),
278
+ toCodecArbitrary: () =>
279
+ S.link<Type>()(
280
+ S.Uint8Array.check(S.isMinLength(nanoidByteLength), S.isMaxLength(nanoidByteLength)),
281
+ {
282
+ decode: Getter.transform((bytes) =>
283
+ (pref + nanoidFromBytes(bytes).substring(0, maxLength - pref.length)) as Type
284
+ ),
285
+ encode: Getter.forbiddenEncoding
286
+ }
287
+ )
288
+ }
289
+ )
195
290
  const schema = s.pipe(withDefaultMake)
196
- const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Brand
291
+ const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Type
197
292
 
198
293
  return extendM(
199
294
  schema,
200
- (ex): PrefixedStringUtils<Brand, Prefix, Separator> => ({
295
+ (ex): PrefixedStringUtils<Type, Prefix, Separator> => ({
201
296
  make,
202
297
  /**
203
298
  * Automatically adds the prefix.
@@ -208,35 +303,60 @@ export function prefixedStringId<Brand extends StringId>() {
208
303
  */
209
304
  prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
210
305
  prefix,
211
- withDefault: schema.pipe(withDefaultConstructor(make))
306
+ /**
307
+ * Construction-only default: fresh prefixed id. Applied only when
308
+ * the field is omitted from `.make(...)` input. NOT applied during
309
+ * decode — cannot be used to JIT-migrate database fields. See
310
+ * file-level note.
311
+ */
312
+ withConstructorDefault: schema.pipe(
313
+ S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>(
314
+ Effect.sync(make)
315
+ )
316
+ )
212
317
  })
213
318
  )
214
319
  }
215
320
  }
216
321
 
217
- export const brandedStringId = <
218
- Brand extends StringIdBrand
219
- >() =>
322
+ /**
323
+ * Build a branded `StringId` schema for the given branded `Id` type.
324
+ *
325
+ * Exposes `.withConstructorDefault` that mints a fresh `nanoid()`-shaped id.
326
+ * Construction-only — not applied during decode; see file-level note.
327
+ */
328
+ export const brandedStringId = <Id extends string & B.Brand<any>>(): BrandedStringIdSchema<Id> =>
220
329
  withDefaultMake(
221
- Object.assign(Object.create(StringId), StringId) as S.Codec<string & Brand, string> & {
222
- make: () => string & Brand
223
- withDefault: S.withConstructorDefault<S.Codec<string & Brand, string> & S.WithoutConstructorDefault>
224
- } & WithDefaults<S.Codec<string & Brand, string>>
330
+ Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema<Id>
225
331
  )
226
332
 
227
333
  export interface PrefixedStringUtils<
228
- Brand extends StringId,
334
+ Type extends StringId,
229
335
  Prefix extends string,
230
336
  Separator extends string
231
337
  > {
232
- readonly make: () => Brand
233
- readonly unsafeFrom: (str: string) => Brand
234
- prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Brand
338
+ readonly make: () => Type
339
+ readonly unsafeFrom: (str: string) => Type
340
+ prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Type
235
341
  readonly prefix: Prefix
236
- readonly withDefault: S.withConstructorDefault<S.Codec<Brand, string> & S.WithoutConstructorDefault>
342
+ /**
343
+ * Construction-only default: fresh prefixed id. Applied only when the
344
+ * field is omitted from `.make(...)` input. NOT applied during decode —
345
+ * cannot be used to JIT-migrate database fields. See file-level note.
346
+ */
347
+ readonly withConstructorDefault: S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>
348
+ }
349
+
350
+ export interface BrandedStringIdSchema<Id extends string & B.Brand<any>> extends BrandedSchema<S.String, Id> {
351
+ (i: string, options?: SchemaAST.ParseOptions): Id
352
+ /** Generate fresh `nanoid()`-shaped id (inherited from `StringId`). */
353
+ make(): Id
354
+ /** Construct an `Id` from a known string (validated via decodeSync). */
355
+ make(input: string, options?: S.MakeOptions): Id
356
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.String, Id>>
237
357
  }
238
358
 
239
- export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
359
+ export interface UrlBrand extends Simplify<SchemaB.Brand<"Url"> & NonEmptyStringBrand> {}
240
360
 
241
361
  export type Url = string & UrlBrand
242
362
 
@@ -244,16 +364,27 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
244
364
  return validator.default.isURL(s, { require_tld: false })
245
365
  }
246
366
 
247
- export const Url = S
367
+ export interface UrlSchema extends S.refine<Url, S.String> {
368
+ (i: string, options?: SchemaAST.ParseOptions): Url
369
+ }
370
+ export const Url: UrlSchema = S
248
371
  .String
249
372
  .pipe(
250
- S.refine(isUrl, {
251
- identifier: "Url",
373
+ S.annotate({
252
374
  title: "Url",
253
- jsonSchema: { format: "uri" }
375
+ format: "uri"
254
376
  }),
255
- S.annotate({
256
- toArbitrary: () => (fc) => fc.webUrl().map((_) => _ as Url)
377
+ S.refine(isUrl, {
378
+ identifier: "Url",
379
+ jsonSchema: { format: "uri" },
380
+ // Native Arbitrary otherwise emits strings that `isURL({ require_tld: false })`
381
+ // accepts (`"R"`, `"prototype"`). Restore the old fast-check `fc.webUrl()` shape.
382
+ arbitraryConstraint: {
383
+ patterns: [{
384
+ source: "^https://[a-z]{3,12}\\.(?:com|net|org|de)(?:/[a-z0-9-]{0,16})?$",
385
+ flags: ""
386
+ }]
387
+ }
257
388
  }),
258
389
  withDefaultMake
259
390
  )
@@ -1,76 +1,155 @@
1
+ /**
2
+ * Numeric brand schemas with `.withConstructorDefault` extensions.
3
+ *
4
+ * Each `.withConstructorDefault` here is **only** applied when the field is
5
+ * omitted during construction (`.make(...)`). It is **not** applied during
6
+ * decode and therefore cannot be used to JIT-migrate database fields.
7
+ *
8
+ * For persisted data, prefer an explicit, preferably versioned migration
9
+ * over decode-time fallbacks. See `./ext.ts` for the full policy note.
10
+ */
1
11
  import { extendM } from "effect-app/utils"
12
+ import * as Effect from "effect/Effect"
13
+ import * as Order from "effect/Order"
2
14
  import * as S from "effect/Schema"
3
15
  import type { Simplify } from "effect/Types"
4
- import { fromBrand, nominal } from "./brand.js"
5
- import { withDefaultConstructor, withDefaultMake } from "./ext.js"
6
- import { type B } from "./schema.js"
16
+ import type * as SchemaAST from "../SchemaAST.ts"
17
+ import { type BrandedSchema, fromBrand, nominal } from "./brand.ts"
18
+ import { withDefaultMake } from "./ext.ts"
19
+ import { type B } from "./schema.ts"
7
20
 
8
21
  export interface PositiveIntBrand
9
22
  extends Simplify<B.Brand<"PositiveInt"> & NonNegativeIntBrand & PositiveNumberBrand>
10
23
  {}
11
- export const PositiveInt = extendM(
24
+ export type PositiveInt = number & PositiveIntBrand
25
+ /** Positive integer. `.withConstructorDefault` => `1` (construction-only). */
26
+ export interface PositiveIntSchema extends BrandedSchema<S.Int, PositiveInt> {
27
+ (i: number, options?: SchemaAST.ParseOptions): PositiveInt
28
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Int, PositiveInt>>
29
+ }
30
+ export const PositiveInt: PositiveIntSchema = extendM(
12
31
  S.Int.pipe(
13
32
  S.check(S.isGreaterThan(0)),
14
- fromBrand(nominal<PositiveInt>(), { identifier: "PositiveInt", title: "PositiveInt", jsonSchema: {} }),
33
+ fromBrand<PositiveInt>(nominal<PositiveInt>(), { identifier: "PositiveInt", jsonSchema: {} }),
15
34
  withDefaultMake
16
35
  ),
17
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(1))) })
36
+ (s) => ({
37
+ /**
38
+ * Construction-only default `1`. Applied only when the field is omitted
39
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
40
+ * JIT-migrate database fields. See file-level note.
41
+ */
42
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1))))
43
+ })
18
44
  )
19
- export type PositiveInt = number & PositiveIntBrand
20
45
 
21
46
  export interface NonNegativeIntBrand extends Simplify<B.Brand<"NonNegativeInt"> & IntBrand & NonNegativeNumberBrand> {}
22
- export const NonNegativeInt = extendM(
47
+ export type NonNegativeInt = number & NonNegativeIntBrand
48
+ /** Non-negative integer. `.withConstructorDefault` => `0` (construction-only). */
49
+ export interface NonNegativeIntSchema extends BrandedSchema<S.Int, NonNegativeInt> {
50
+ (i: number, options?: SchemaAST.ParseOptions): NonNegativeInt
51
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Int, NonNegativeInt>>
52
+ }
53
+ export const NonNegativeInt: NonNegativeIntSchema = extendM(
23
54
  S.Int.pipe(
24
55
  S.check(S.isGreaterThanOrEqualTo(0)),
25
- fromBrand(nominal<NonNegativeInt>(), {
56
+ fromBrand<NonNegativeInt>(nominal<NonNegativeInt>(), {
26
57
  identifier: "NonNegativeInt",
27
- title: "NonNegativeInt",
28
58
  jsonSchema: {}
29
59
  }),
30
60
  withDefaultMake
31
61
  ),
32
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(0))) })
62
+ (s) => ({
63
+ /**
64
+ * Construction-only default `0`. Applied only when the field is omitted
65
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
66
+ * JIT-migrate database fields. See file-level note.
67
+ */
68
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0))))
69
+ })
33
70
  )
34
- export type NonNegativeInt = number & NonNegativeIntBrand
35
71
 
36
72
  export interface IntBrand extends Simplify<B.Brand<"Int">> {}
37
- export const Int = extendM(
38
- S.Int.pipe(fromBrand(nominal<Int>(), { identifier: "Int", title: "Int", jsonSchema: {} }), withDefaultMake),
39
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(0))) })
40
- )
41
73
  export type Int = number & IntBrand
74
+ /** Integer. `.withConstructorDefault` => `0` (construction-only). */
75
+ export interface IntSchema extends BrandedSchema<S.Int, Int> {
76
+ (i: number, options?: SchemaAST.ParseOptions): Int
77
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Int, Int>>
78
+ }
79
+ export const Int: IntSchema = extendM(
80
+ S.Int.pipe(fromBrand<Int>(nominal<Int>(), { identifier: "Int", jsonSchema: {} }), withDefaultMake),
81
+ (s) => ({
82
+ /**
83
+ * Construction-only default `0`. Applied only when the field is omitted
84
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
85
+ * JIT-migrate database fields. See file-level note.
86
+ */
87
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0))))
88
+ })
89
+ )
42
90
 
43
91
  export interface PositiveNumberBrand extends Simplify<B.Brand<"PositiveNumber"> & NonNegativeNumberBrand> {}
44
- export const PositiveNumber = extendM(
92
+ export type PositiveNumber = number & PositiveNumberBrand
93
+ /** Positive finite number. `.withConstructorDefault` => `1` (construction-only). */
94
+ // Generation-only: native Arbitrary otherwise samples up to Number.MAX_VALUE, so derived totals
95
+ // (amount x weight, sums) overflow to Infinity. Validation and JSON Schema are unaffected.
96
+ const realisticMaximum = 1_000_000
97
+
98
+ export interface PositiveNumberSchema extends BrandedSchema<S.Finite, PositiveNumber> {
99
+ (i: number, options?: SchemaAST.ParseOptions): PositiveNumber
100
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Finite, PositiveNumber>>
101
+ }
102
+ export const PositiveNumber: PositiveNumberSchema = extendM(
45
103
  S.Finite.pipe(
46
- S.check(S.isGreaterThan(0)),
47
- fromBrand(nominal<PositiveNumber>(), {
104
+ S.check(S.isGreaterThan(0, {
105
+ // the full constraint: annotations replace the check default, which carries `order` + `minimum`
106
+ arbitraryConstraint: { order: Order.Number, minimum: 0, exclusiveMinimum: true, maximum: realisticMaximum }
107
+ })),
108
+ fromBrand<PositiveNumber>(nominal<PositiveNumber>(), {
48
109
  identifier: "PositiveNumber",
49
- title: "PositiveNumber",
50
110
  jsonSchema: {}
51
111
  }),
52
112
  withDefaultMake
53
113
  ),
54
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(1))) })
114
+ (s) => ({
115
+ /**
116
+ * Construction-only default `1`. Applied only when the field is omitted
117
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
118
+ * JIT-migrate database fields. See file-level note.
119
+ */
120
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1))))
121
+ })
55
122
  )
56
- export type PositiveNumber = number & PositiveNumberBrand
57
123
 
58
124
  export interface NonNegativeNumberBrand extends Simplify<B.Brand<"NonNegativeNumber">> {}
59
- export const NonNegativeNumber = extendM(
125
+ export type NonNegativeNumber = number & NonNegativeNumberBrand
126
+ /** Non-negative finite number. `.withConstructorDefault` => `0` (construction-only). */
127
+ export interface NonNegativeNumberSchema extends BrandedSchema<S.Finite, NonNegativeNumber> {
128
+ (i: number, options?: SchemaAST.ParseOptions): NonNegativeNumber
129
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Finite, NonNegativeNumber>>
130
+ }
131
+ export const NonNegativeNumber: NonNegativeNumberSchema = extendM(
60
132
  S
61
133
  .Finite
62
134
  .pipe(
63
- S.check(S.isGreaterThanOrEqualTo(0)),
64
- fromBrand(nominal<NonNegativeNumber>(), {
135
+ S.check(S.isGreaterThanOrEqualTo(0, {
136
+ arbitraryConstraint: { order: Order.Number, minimum: 0, maximum: realisticMaximum }
137
+ })),
138
+ fromBrand<NonNegativeNumber>(nominal<NonNegativeNumber>(), {
65
139
  identifier: "NonNegativeNumber",
66
- title: "NonNegativeNumber",
67
140
  jsonSchema: {}
68
141
  }),
69
142
  withDefaultMake
70
143
  ),
71
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(0))) })
144
+ (s) => ({
145
+ /**
146
+ * Construction-only default `0`. Applied only when the field is omitted
147
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
148
+ * JIT-migrate database fields. See file-level note.
149
+ */
150
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0))))
151
+ })
72
152
  )
73
- export type NonNegativeNumber = number & NonNegativeNumberBrand
74
153
 
75
154
  /** @deprecated Not an actual decimal */
76
155
  export const NonNegativeDecimal = NonNegativeNumber