effect-app 4.0.0-beta.98 → 4.0.0

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 (371) hide show
  1. package/CHANGELOG.md +2030 -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 +2 -2
  6. package/dist/Chunk.d.ts.map +1 -1
  7. package/dist/Config/SecretURL.d.ts +3 -1
  8. package/dist/Config/SecretURL.d.ts.map +1 -1
  9. package/dist/Config/SecretURL.js +3 -6
  10. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  11. package/dist/Config/internal/configSecretURL.js +2 -2
  12. package/dist/Config.d.ts +0 -5
  13. package/dist/Config.d.ts.map +1 -1
  14. package/dist/Config.js +7 -5
  15. package/dist/ConfigProvider.d.ts +0 -37
  16. package/dist/ConfigProvider.d.ts.map +1 -1
  17. package/dist/ConfigProvider.js +5 -41
  18. package/dist/Context.d.ts +6 -4
  19. package/dist/Context.d.ts.map +1 -1
  20. package/dist/Context.js +4 -3
  21. package/dist/DataDependencies.d.ts +136 -0
  22. package/dist/DataDependencies.d.ts.map +1 -0
  23. package/dist/DataDependencies.js +112 -0
  24. package/dist/Effect.d.ts +3 -3
  25. package/dist/Effect.d.ts.map +1 -1
  26. package/dist/Effect.js +6 -9
  27. package/dist/Emailer.d.ts +51 -0
  28. package/dist/Emailer.d.ts.map +1 -0
  29. package/dist/Emailer.js +7 -0
  30. package/dist/Function.d.ts.map +1 -1
  31. package/dist/Layer.d.ts +6 -3
  32. package/dist/Layer.d.ts.map +1 -1
  33. package/dist/Layer.js +3 -2
  34. package/dist/Model/Repository/Registry.d.ts +22 -0
  35. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  36. package/dist/Model/Repository/Registry.js +18 -0
  37. package/dist/Model/Repository/dependency.d.ts +6 -0
  38. package/dist/Model/Repository/dependency.d.ts.map +1 -0
  39. package/dist/Model/Repository/dependency.js +29 -0
  40. package/dist/Model/Repository/ext.d.ts +60 -0
  41. package/dist/Model/Repository/ext.d.ts.map +1 -0
  42. package/dist/Model/Repository/ext.js +124 -0
  43. package/dist/Model/Repository/internal/internal.d.ts +68 -0
  44. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  45. package/dist/Model/Repository/internal/internal.js +611 -0
  46. package/dist/Model/Repository/legacy.d.ts +21 -0
  47. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  48. package/dist/Model/Repository/legacy.js +2 -0
  49. package/dist/Model/Repository/makeRepo.d.ts +71 -0
  50. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  51. package/dist/Model/Repository/makeRepo.js +30 -0
  52. package/dist/Model/Repository/service.d.ts +121 -0
  53. package/dist/Model/Repository/service.d.ts.map +1 -0
  54. package/dist/Model/Repository/service.js +2 -0
  55. package/dist/Model/Repository/validation.d.ts +72 -0
  56. package/dist/Model/Repository/validation.d.ts.map +1 -0
  57. package/dist/Model/Repository/validation.js +39 -0
  58. package/dist/Model/Repository.d.ts +8 -0
  59. package/dist/Model/Repository.d.ts.map +1 -0
  60. package/dist/Model/Repository.js +8 -0
  61. package/dist/Model/dsl.d.ts +33 -0
  62. package/dist/Model/dsl.d.ts.map +1 -0
  63. package/dist/Model/dsl.js +43 -0
  64. package/dist/Model/filter/filterApi.d.ts +30 -0
  65. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  66. package/dist/Model/filter/filterApi.js +2 -0
  67. package/dist/Model/filter/types/errors.d.ts +29 -0
  68. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  69. package/dist/Model/filter/types/errors.js +2 -0
  70. package/dist/Model/filter/types/fields.d.ts +15 -0
  71. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  72. package/dist/Model/filter/types/fields.js +2 -0
  73. package/dist/Model/filter/types/path/common.d.ts +316 -0
  74. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  75. package/dist/Model/filter/types/path/common.js +2 -0
  76. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  77. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  78. package/dist/Model/filter/types/path/eager.js +36 -0
  79. package/dist/Model/filter/types/path/index.d.ts +4 -0
  80. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  81. package/dist/Model/filter/types/path/index.js +3 -0
  82. package/dist/Model/filter/types/utils.d.ts +79 -0
  83. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  84. package/dist/Model/filter/types/utils.js +2 -0
  85. package/dist/Model/filter/types/validator.d.ts +30 -0
  86. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  87. package/dist/Model/filter/types/validator.js +2 -0
  88. package/dist/Model/filter/types.d.ts +5 -0
  89. package/dist/Model/filter/types.d.ts.map +1 -0
  90. package/dist/Model/filter/types.js +7 -0
  91. package/dist/Model/query/dsl.d.ts +630 -0
  92. package/dist/Model/query/dsl.d.ts.map +1 -0
  93. package/dist/Model/query/dsl.js +376 -0
  94. package/dist/Model/query/new-kid-interpreter.d.ts +132 -0
  95. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  96. package/dist/Model/query/new-kid-interpreter.js +370 -0
  97. package/dist/Model/query.d.ts +15 -0
  98. package/dist/Model/query.d.ts.map +1 -0
  99. package/dist/Model/query.js +3 -0
  100. package/dist/Model.d.ts +6 -0
  101. package/dist/Model.d.ts.map +1 -0
  102. package/dist/Model.js +6 -0
  103. package/dist/NonEmptySet.d.ts +3 -1
  104. package/dist/NonEmptySet.d.ts.map +1 -1
  105. package/dist/NonEmptySet.js +2 -2
  106. package/dist/Option.d.ts +1 -0
  107. package/dist/Option.d.ts.map +1 -1
  108. package/dist/Option.js +3 -1
  109. package/dist/Pure.d.ts +5 -3
  110. package/dist/Pure.d.ts.map +1 -1
  111. package/dist/Pure.js +5 -2
  112. package/dist/QueueMaker.d.ts +11 -0
  113. package/dist/QueueMaker.d.ts.map +1 -0
  114. package/dist/QueueMaker.js +11 -0
  115. package/dist/RequestContext.d.ts +87 -0
  116. package/dist/RequestContext.d.ts.map +1 -0
  117. package/dist/RequestContext.js +45 -0
  118. package/dist/RequestScopedDependencies.d.ts +21 -0
  119. package/dist/RequestScopedDependencies.d.ts.map +1 -0
  120. package/dist/RequestScopedDependencies.js +16 -0
  121. package/dist/Schema/Class.d.ts +163 -16
  122. package/dist/Schema/Class.d.ts.map +1 -1
  123. package/dist/Schema/Class.js +193 -21
  124. package/dist/Schema/FastCheck.d.ts.map +1 -1
  125. package/dist/Schema/SchemaParser.d.ts +5 -0
  126. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  127. package/dist/Schema/SchemaParser.js +6 -0
  128. package/dist/Schema/SpecialJsonSchema.d.ts +15 -2
  129. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -1
  130. package/dist/Schema/SpecialJsonSchema.js +70 -12
  131. package/dist/Schema/SpecialOpenApi.d.ts +1 -1
  132. package/dist/Schema/SpecialOpenApi.js +3 -3
  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 +6 -4
  136. package/dist/Schema/email.d.ts.map +1 -1
  137. package/dist/Schema/email.js +8 -5
  138. package/dist/Schema/ext.d.ts +297 -72
  139. package/dist/Schema/ext.d.ts.map +1 -1
  140. package/dist/Schema/ext.js +331 -67
  141. package/dist/Schema/moreStrings.d.ts +82 -48
  142. package/dist/Schema/moreStrings.d.ts.map +1 -1
  143. package/dist/Schema/moreStrings.js +85 -51
  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 +64 -12
  147. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  148. package/dist/Schema/phoneNumber.js +6 -6
  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 +223 -6
  156. package/dist/Schema.d.ts.map +1 -1
  157. package/dist/Schema.js +189 -23
  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 +13 -8
  183. package/dist/client/apiClientFactory.d.ts.map +1 -1
  184. package/dist/client/apiClientFactory.js +148 -29
  185. package/dist/client/clientFor.d.ts +48 -13
  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 +74 -28
  189. package/dist/client/errors.d.ts.map +1 -1
  190. package/dist/client/errors.js +41 -10
  191. package/dist/client/makeClient.d.ts +487 -32
  192. package/dist/client/makeClient.d.ts.map +1 -1
  193. package/dist/client/makeClient.js +47 -21
  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 +2 -2
  199. package/dist/http/Request.d.ts.map +1 -1
  200. package/dist/http/Request.js +2 -2
  201. package/dist/http/internal/lib.d.ts +12 -12
  202. package/dist/http/internal/lib.d.ts.map +1 -1
  203. package/dist/http/internal/lib.js +13 -13
  204. package/dist/ids.d.ts +32 -14
  205. package/dist/ids.d.ts.map +1 -1
  206. package/dist/ids.js +38 -7
  207. package/dist/index.d.ts +3 -0
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.js +5 -1
  210. package/dist/middleware.d.ts +12 -6
  211. package/dist/middleware.d.ts.map +1 -1
  212. package/dist/middleware.js +13 -7
  213. package/dist/rpc/Invalidation.d.ts +1124 -0
  214. package/dist/rpc/Invalidation.d.ts.map +1 -0
  215. package/dist/rpc/Invalidation.js +178 -0
  216. package/dist/rpc/MiddlewareMaker.d.ts +10 -7
  217. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  218. package/dist/rpc/MiddlewareMaker.js +57 -37
  219. package/dist/rpc/RpcContextMap.d.ts +2 -2
  220. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  221. package/dist/rpc/RpcMiddleware.d.ts +13 -10
  222. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  223. package/dist/rpc/RpcMiddleware.js +2 -2
  224. package/dist/rpc.d.ts +1 -1
  225. package/dist/rpc.d.ts.map +1 -1
  226. package/dist/rpc.js +2 -2
  227. package/dist/runtime.d.ts +19 -0
  228. package/dist/runtime.d.ts.map +1 -0
  229. package/dist/runtime.js +40 -0
  230. package/dist/setupRequest.d.ts +20 -0
  231. package/dist/setupRequest.d.ts.map +1 -0
  232. package/dist/setupRequest.js +72 -0
  233. package/dist/toast.d.ts +51 -0
  234. package/dist/toast.d.ts.map +1 -0
  235. package/dist/toast.js +34 -0
  236. package/dist/transform.d.ts +1 -1
  237. package/dist/transform.d.ts.map +1 -1
  238. package/dist/transform.js +4 -5
  239. package/dist/utils/effectify.d.ts +1 -1
  240. package/dist/utils/effectify.d.ts.map +1 -1
  241. package/dist/utils/effectify.js +2 -2
  242. package/dist/utils/extend.d.ts +6 -1
  243. package/dist/utils/extend.d.ts.map +1 -1
  244. package/dist/utils/extend.js +24 -6
  245. package/dist/utils/gen.d.ts +4 -4
  246. package/dist/utils/gen.d.ts.map +1 -1
  247. package/dist/utils/logLevel.d.ts +2 -2
  248. package/dist/utils/logLevel.d.ts.map +1 -1
  249. package/dist/utils/logger.d.ts +2 -1
  250. package/dist/utils/logger.d.ts.map +1 -1
  251. package/dist/utils/logger.js +2 -2
  252. package/dist/utils.d.ts +34 -39
  253. package/dist/utils.d.ts.map +1 -1
  254. package/dist/utils.js +33 -37
  255. package/dist/validation/validators.d.ts.map +1 -1
  256. package/dist/validation.d.ts.map +1 -1
  257. package/dist/withToast.d.ts +30 -0
  258. package/dist/withToast.d.ts.map +1 -0
  259. package/dist/withToast.js +64 -0
  260. package/package.json +26 -266
  261. package/src/Array.ts +5 -5
  262. package/src/Chunk.ts +3 -3
  263. package/src/Config/SecretURL.ts +6 -3
  264. package/src/Config/internal/configSecretURL.ts +2 -2
  265. package/src/Config.ts +6 -13
  266. package/src/ConfigProvider.ts +4 -47
  267. package/src/Context.ts +9 -8
  268. package/src/DataDependencies.ts +171 -0
  269. package/src/Effect.ts +9 -12
  270. package/src/Emailer.ts +51 -0
  271. package/src/Inputify.type.ts +1 -1
  272. package/src/Layer.ts +8 -5
  273. package/src/Model/Repository/Registry.ts +35 -0
  274. package/src/Model/Repository/dependency.ts +32 -0
  275. package/src/Model/Repository/ext.ts +374 -0
  276. package/src/Model/Repository/internal/internal.ts +988 -0
  277. package/src/Model/Repository/legacy.ts +29 -0
  278. package/src/Model/Repository/makeRepo.ts +168 -0
  279. package/src/Model/Repository/service.ts +676 -0
  280. package/src/Model/Repository/validation.ts +38 -0
  281. package/src/Model/Repository.ts +7 -0
  282. package/src/Model/dsl.ts +129 -0
  283. package/src/Model/filter/filterApi.ts +78 -0
  284. package/src/Model/filter/types/errors.ts +47 -0
  285. package/src/Model/filter/types/fields.ts +50 -0
  286. package/src/Model/filter/types/path/common.ts +404 -0
  287. package/src/Model/filter/types/path/eager.ts +329 -0
  288. package/src/Model/filter/types/path/index.ts +4 -0
  289. package/src/Model/filter/types/utils.ts +128 -0
  290. package/src/Model/filter/types/validator.ts +46 -0
  291. package/src/Model/filter/types.ts +6 -0
  292. package/src/Model/query/dsl.ts +3092 -0
  293. package/src/Model/query/new-kid-interpreter.ts +532 -0
  294. package/src/Model/query.ts +13 -0
  295. package/src/Model.ts +5 -0
  296. package/src/NonEmptySet.ts +6 -4
  297. package/src/Option.ts +2 -0
  298. package/src/Pure.ts +6 -3
  299. package/src/QueueMaker.ts +11 -0
  300. package/src/RequestContext.ts +48 -0
  301. package/src/RequestScopedDependencies.ts +45 -0
  302. package/src/Schema/Class.ts +550 -56
  303. package/src/Schema/SchemaParser.ts +12 -0
  304. package/src/Schema/SpecialJsonSchema.ts +75 -7
  305. package/src/Schema/SpecialOpenApi.ts +5 -5
  306. package/src/Schema/brand.ts +27 -12
  307. package/src/Schema/email.ts +9 -7
  308. package/src/Schema/ext.ts +408 -91
  309. package/src/Schema/moreStrings.ts +213 -88
  310. package/src/Schema/numbers.ts +107 -29
  311. package/src/Schema/phoneNumber.ts +8 -9
  312. package/src/Schema/schema.ts +1 -1
  313. package/src/Schema/strings.ts +23 -14
  314. package/src/Schema.ts +403 -46
  315. package/src/SchemaAST.ts +1 -0
  316. package/src/Set.ts +6 -2
  317. package/src/Store.ts +325 -0
  318. package/src/_ext/Array.ts +4 -2
  319. package/src/_ext/misc.ts +4 -1
  320. package/src/_ext/ord.ext.ts +2 -1
  321. package/src/builtin-json.d.ts +24 -0
  322. package/src/builtin.ts +16 -21
  323. package/src/client/InvalidationKeys.ts +55 -0
  324. package/src/client/apiClientFactory.ts +291 -126
  325. package/src/client/clientFor.ts +101 -33
  326. package/src/client/errors.ts +66 -20
  327. package/src/client/makeClient.ts +519 -60
  328. package/src/client.ts +6 -4
  329. package/src/http/Request.ts +4 -4
  330. package/src/http/internal/lib.ts +12 -12
  331. package/src/http.ts +1 -1
  332. package/src/ids.ts +45 -8
  333. package/src/index.ts +20 -16
  334. package/src/middleware.ts +12 -8
  335. package/src/rpc/Invalidation.ts +278 -0
  336. package/src/rpc/MiddlewareMaker.ts +86 -79
  337. package/src/rpc/README.md +2 -2
  338. package/src/rpc/RpcContextMap.ts +4 -4
  339. package/src/rpc/RpcMiddleware.ts +18 -13
  340. package/src/rpc.ts +4 -4
  341. package/src/runtime.ts +57 -0
  342. package/src/setupRequest.ts +138 -0
  343. package/src/toast.ts +54 -0
  344. package/src/transform.ts +4 -4
  345. package/src/utils/effectify.ts +1 -1
  346. package/src/utils/extend.ts +24 -5
  347. package/src/utils/gen.ts +7 -7
  348. package/src/utils/logLevel.ts +1 -1
  349. package/src/utils/logger.ts +3 -2
  350. package/src/utils.ts +85 -158
  351. package/src/validation.ts +2 -2
  352. package/src/withToast.ts +133 -0
  353. package/test/dist/rpc.test.d.ts.map +1 -1
  354. package/test/dist/rpcMiddlewareContext.test.d.ts.map +1 -0
  355. package/test/moreStrings.test.ts +55 -10
  356. package/test/rpc.test.ts +28 -11
  357. package/test/rpcMiddlewareContext.test.ts +63 -0
  358. package/test/schema.test.ts +318 -55
  359. package/test/secretURL.test.ts +4 -1
  360. package/test/special.test.ts +663 -131
  361. package/test/utils.test.ts +5 -5
  362. package/tsconfig.base.json +6 -4
  363. package/tsconfig.json +9 -1
  364. package/tsconfig.src.json +29 -29
  365. package/tsconfig.test.json +2 -2
  366. package/dist/Operations.d.ts +0 -124
  367. package/dist/Operations.d.ts.map +0 -1
  368. package/dist/Operations.js +0 -29
  369. package/eslint.config.mjs +0 -26
  370. package/src/Operations.ts +0 -55
  371. package/tsconfig.json.bak +0 -12
@@ -1,21 +1,36 @@
1
- import { Effect, 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 { 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(S.withConstructorDefault(Effect.sync(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 = 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
- )
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,37 +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(S.withConstructorDefault<S.Codec<Brand, string> & S.WithoutConstructorDefault>(
212
- Effect.sync(make)
213
- ))
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
+ )
214
317
  })
215
318
  )
216
319
  }
217
320
  }
218
321
 
219
- export const brandedStringId = <
220
- Brand extends StringIdBrand
221
- >() =>
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> =>
222
329
  withDefaultMake(
223
- Object.assign(Object.create(StringId), StringId) as S.Codec<string & Brand, string> & {
224
- make: () => string & Brand
225
- withDefault: S.withConstructorDefault<S.Codec<string & Brand, string> & S.WithoutConstructorDefault>
226
- } & WithDefaults<S.Codec<string & Brand, string>>
330
+ Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema<Id>
227
331
  )
228
332
 
229
333
  export interface PrefixedStringUtils<
230
- Brand extends StringId,
334
+ Type extends StringId,
231
335
  Prefix extends string,
232
336
  Separator extends string
233
337
  > {
234
- readonly make: () => Brand
235
- readonly unsafeFrom: (str: string) => Brand
236
- 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
237
341
  readonly prefix: Prefix
238
- 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>>
239
357
  }
240
358
 
241
- export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
359
+ export interface UrlBrand extends Simplify<SchemaB.Brand<"Url"> & NonEmptyStringBrand> {}
242
360
 
243
361
  export type Url = string & UrlBrand
244
362
 
@@ -246,7 +364,10 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
246
364
  return validator.default.isURL(s, { require_tld: false })
247
365
  }
248
366
 
249
- 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
250
371
  .String
251
372
  .pipe(
252
373
  S.annotate({
@@ -255,11 +376,15 @@ export const Url = S
255
376
  }),
256
377
  S.refine(isUrl, {
257
378
  identifier: "Url",
258
- title: "Url",
259
- jsonSchema: { format: "uri" }
260
- }),
261
- S.annotate({
262
- toArbitrary: () => (fc) => fc.webUrl().map((_) => _ as 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
+ }
263
388
  }),
264
389
  withDefaultMake
265
390
  )
@@ -1,77 +1,155 @@
1
- import { Effect } from "effect"
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
+ */
2
11
  import { extendM } from "effect-app/utils"
12
+ import * as Effect from "effect/Effect"
13
+ import * as Order from "effect/Order"
3
14
  import * as S from "effect/Schema"
4
15
  import type { Simplify } from "effect/Types"
5
- import { fromBrand, nominal } from "./brand.js"
6
- import { withDefaultMake } from "./ext.js"
7
- 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"
8
20
 
9
21
  export interface PositiveIntBrand
10
22
  extends Simplify<B.Brand<"PositiveInt"> & NonNegativeIntBrand & PositiveNumberBrand>
11
23
  {}
12
- 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(
13
31
  S.Int.pipe(
14
32
  S.check(S.isGreaterThan(0)),
15
- fromBrand(nominal<PositiveInt>(), { identifier: "PositiveInt", title: "PositiveInt", jsonSchema: {} }),
33
+ fromBrand<PositiveInt>(nominal<PositiveInt>(), { identifier: "PositiveInt", jsonSchema: {} }),
16
34
  withDefaultMake
17
35
  ),
18
- (s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => 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
+ })
19
44
  )
20
- export type PositiveInt = number & PositiveIntBrand
21
45
 
22
46
  export interface NonNegativeIntBrand extends Simplify<B.Brand<"NonNegativeInt"> & IntBrand & NonNegativeNumberBrand> {}
23
- 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(
24
54
  S.Int.pipe(
25
55
  S.check(S.isGreaterThanOrEqualTo(0)),
26
- fromBrand(nominal<NonNegativeInt>(), {
56
+ fromBrand<NonNegativeInt>(nominal<NonNegativeInt>(), {
27
57
  identifier: "NonNegativeInt",
28
- title: "NonNegativeInt",
29
58
  jsonSchema: {}
30
59
  }),
31
60
  withDefaultMake
32
61
  ),
33
- (s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => 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
+ })
34
70
  )
35
- export type NonNegativeInt = number & NonNegativeIntBrand
36
71
 
37
72
  export interface IntBrand extends Simplify<B.Brand<"Int">> {}
38
- export const Int = extendM(
39
- S.Int.pipe(fromBrand(nominal<Int>(), { identifier: "Int", title: "Int", jsonSchema: {} }), withDefaultMake),
40
- (s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) })
41
- )
42
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
+ )
43
90
 
44
91
  export interface PositiveNumberBrand extends Simplify<B.Brand<"PositiveNumber"> & NonNegativeNumberBrand> {}
45
- 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(
46
103
  S.Finite.pipe(
47
- S.check(S.isGreaterThan(0)),
48
- 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>(), {
49
109
  identifier: "PositiveNumber",
50
- title: "PositiveNumber",
51
110
  jsonSchema: {}
52
111
  }),
53
112
  withDefaultMake
54
113
  ),
55
- (s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => 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
+ })
56
122
  )
57
- export type PositiveNumber = number & PositiveNumberBrand
58
123
 
59
124
  export interface NonNegativeNumberBrand extends Simplify<B.Brand<"NonNegativeNumber">> {}
60
- 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(
61
132
  S
62
133
  .Finite
63
134
  .pipe(
64
- S.check(S.isGreaterThanOrEqualTo(0)),
65
- fromBrand(nominal<NonNegativeNumber>(), {
135
+ S.check(S.isGreaterThanOrEqualTo(0, {
136
+ arbitraryConstraint: { order: Order.Number, minimum: 0, maximum: realisticMaximum }
137
+ })),
138
+ fromBrand<NonNegativeNumber>(nominal<NonNegativeNumber>(), {
66
139
  identifier: "NonNegativeNumber",
67
- title: "NonNegativeNumber",
68
140
  jsonSchema: {}
69
141
  }),
70
142
  withDefaultMake
71
143
  ),
72
- (s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => 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
+ })
73
152
  )
74
- export type NonNegativeNumber = number & NonNegativeNumberBrand
75
153
 
76
154
  /** @deprecated Not an actual decimal */
77
155
  export const NonNegativeDecimal = NonNegativeNumber