effect-app 4.0.0-beta.32 → 4.0.0-beta.321

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 +1570 -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 +579 -0
  45. package/dist/Model/Repository/legacy.d.ts +21 -0
  46. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  47. package/dist/Model/Repository/legacy.js +2 -0
  48. package/dist/Model/Repository/makeRepo.d.ts +63 -0
  49. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  50. package/dist/Model/Repository/makeRepo.js +27 -0
  51. package/dist/Model/Repository/service.d.ts +121 -0
  52. package/dist/Model/Repository/service.d.ts.map +1 -0
  53. package/dist/Model/Repository/service.js +2 -0
  54. package/dist/Model/Repository/validation.d.ts +58 -0
  55. package/dist/Model/Repository/validation.d.ts.map +1 -0
  56. package/dist/Model/Repository/validation.js +32 -0
  57. package/dist/Model/Repository.d.ts +8 -0
  58. package/dist/Model/Repository.d.ts.map +1 -0
  59. package/dist/Model/Repository.js +8 -0
  60. package/dist/Model/dsl.d.ts +33 -0
  61. package/dist/Model/dsl.d.ts.map +1 -0
  62. package/dist/Model/dsl.js +43 -0
  63. package/dist/Model/filter/filterApi.d.ts +30 -0
  64. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  65. package/dist/Model/filter/filterApi.js +2 -0
  66. package/dist/Model/filter/types/errors.d.ts +29 -0
  67. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  68. package/dist/Model/filter/types/errors.js +2 -0
  69. package/dist/Model/filter/types/fields.d.ts +15 -0
  70. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  71. package/dist/Model/filter/types/fields.js +2 -0
  72. package/dist/Model/filter/types/path/common.d.ts +316 -0
  73. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  74. package/dist/Model/filter/types/path/common.js +2 -0
  75. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  76. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  77. package/dist/Model/filter/types/path/eager.js +36 -0
  78. package/dist/Model/filter/types/path/index.d.ts +4 -0
  79. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  80. package/dist/Model/filter/types/path/index.js +3 -0
  81. package/dist/Model/filter/types/utils.d.ts +79 -0
  82. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  83. package/dist/Model/filter/types/utils.js +2 -0
  84. package/dist/Model/filter/types/validator.d.ts +30 -0
  85. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  86. package/dist/Model/filter/types/validator.js +2 -0
  87. package/dist/Model/filter/types.d.ts +5 -0
  88. package/dist/Model/filter/types.d.ts.map +1 -0
  89. package/dist/Model/filter/types.js +7 -0
  90. package/dist/Model/query/dsl.d.ts +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 +7 -6
  138. package/dist/Schema/ext.d.ts +337 -56
  139. package/dist/Schema/ext.d.ts.map +1 -1
  140. package/dist/Schema/ext.js +381 -58
  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 +47 -51
  144. package/dist/Schema/numbers.d.ts +34 -21
  145. package/dist/Schema/numbers.d.ts.map +1 -1
  146. package/dist/Schema/numbers.js +55 -12
  147. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  148. package/dist/Schema/phoneNumber.js +6 -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 +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 +170 -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 +42 -14
  202. package/dist/ids.d.ts.map +1 -1
  203. package/dist/ids.js +30 -5
  204. package/dist/index.d.ts +6 -7
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +8 -8
  207. package/dist/middleware.d.ts +13 -7
  208. package/dist/middleware.d.ts.map +1 -1
  209. package/dist/middleware.js +14 -8
  210. package/dist/rpc/Invalidation.d.ts +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 +950 -0
  273. package/src/Model/Repository/legacy.ts +29 -0
  274. package/src/Model/Repository/makeRepo.ts +156 -0
  275. package/src/Model/Repository/service.ts +676 -0
  276. package/src/Model/Repository/validation.ts +31 -0
  277. package/src/Model/Repository.ts +7 -0
  278. package/src/Model/dsl.ts +129 -0
  279. package/src/Model/filter/filterApi.ts +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 +9 -7
  304. package/src/Schema/ext.ts +502 -98
  305. package/src/Schema/moreStrings.ts +145 -83
  306. package/src/Schema/numbers.ts +97 -28
  307. package/src/Schema/phoneNumber.ts +8 -8
  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 +280 -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 +33 -6
  328. package/src/index.ts +20 -23
  329. package/src/middleware.ts +13 -9
  330. package/src/rpc/Invalidation.ts +278 -0
  331. package/src/rpc/MiddlewareMaker.ts +88 -80
  332. package/src/rpc/README.md +2 -2
  333. package/src/rpc/RpcContextMap.ts +7 -6
  334. package/src/rpc/RpcMiddleware.ts +19 -13
  335. package/src/rpc.ts +4 -4
  336. package/src/runtime.ts +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 +7 -9
  352. package/test/rpc.test.ts +42 -14
  353. package/test/rpcMiddlewareContext.test.ts +63 -0
  354. package/test/schema.test.ts +514 -35
  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,34 @@
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"
5
17
  import type { Simplify } from "effect/Types"
6
- import { customRandom, nanoid, urlAlphabet } from "nanoid"
18
+ import { nanoid } from "nanoid"
7
19
  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"
20
+ import type * as SchemaAST from "../SchemaAST.ts"
21
+ import { type BrandedSchema, fromBrand, nominal } from "./brand.ts"
22
+ import { withDefaultMake } from "./ext.ts"
23
+ import { type B as SchemaB } from "./schema.ts"
24
+ import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.ts"
12
25
 
13
26
  const nonEmptyString = S.NonEmptyString
14
27
 
15
28
  /**
16
29
  * A string that is at least 1 character long and a maximum of 50.
17
30
  */
18
- export interface NonEmptyString50Brand extends Simplify<B.Brand<"NonEmptyString50"> & NonEmptyString64Brand> {}
31
+ export interface NonEmptyString50Brand extends Simplify<SchemaB.Brand<"NonEmptyString50"> & NonEmptyString64Brand> {}
19
32
 
20
33
  /**
21
34
  * A string that is at least 1 character long and a maximum of 50.
@@ -25,11 +38,13 @@ export type NonEmptyString50 = string & NonEmptyString50Brand
25
38
  /**
26
39
  * A string that is at least 1 character long and a maximum of 50.
27
40
  */
28
- export const NonEmptyString50 = nonEmptyString.pipe(
41
+ export interface NonEmptyString50Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString50> {
42
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString50
43
+ }
44
+ export const NonEmptyString50: NonEmptyString50Schema = nonEmptyString.pipe(
29
45
  S.check(S.isMaxLength(50)),
30
- fromBrand(nominal<NonEmptyString50>(), {
46
+ fromBrand<NonEmptyString50>(nominal<NonEmptyString50>(), {
31
47
  identifier: "NonEmptyString50",
32
- title: "NonEmptyString50",
33
48
  jsonSchema: {}
34
49
  }),
35
50
  withDefaultMake
@@ -38,7 +53,7 @@ export const NonEmptyString50 = nonEmptyString.pipe(
38
53
  /**
39
54
  * A string that is at least 1 character long and a maximum of 64.
40
55
  */
41
- export interface NonEmptyString64Brand extends Simplify<B.Brand<"NonEmptyString64"> & NonEmptyString80Brand> {}
56
+ export interface NonEmptyString64Brand extends Simplify<SchemaB.Brand<"NonEmptyString64"> & NonEmptyString80Brand> {}
42
57
 
43
58
  /**
44
59
  * A string that is at least 1 character long and a maximum of 64.
@@ -48,11 +63,13 @@ export type NonEmptyString64 = string & NonEmptyString64Brand
48
63
  /**
49
64
  * A string that is at least 1 character long and a maximum of 64.
50
65
  */
51
- export const NonEmptyString64 = nonEmptyString.pipe(
66
+ export interface NonEmptyString64Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString64> {
67
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString64
68
+ }
69
+ export const NonEmptyString64: NonEmptyString64Schema = nonEmptyString.pipe(
52
70
  S.check(S.isMaxLength(64)),
53
- fromBrand(nominal<NonEmptyString64>(), {
71
+ fromBrand<NonEmptyString64>(nominal<NonEmptyString64>(), {
54
72
  identifier: "NonEmptyString64",
55
- title: "NonEmptyString64",
56
73
  jsonSchema: {}
57
74
  }),
58
75
  withDefaultMake
@@ -61,7 +78,7 @@ export const NonEmptyString64 = nonEmptyString.pipe(
61
78
  /**
62
79
  * A string that is at least 1 character long and a maximum of 80.
63
80
  */
64
- export interface NonEmptyString80Brand extends Simplify<B.Brand<"NonEmptyString80"> & NonEmptyString100Brand> {}
81
+ export interface NonEmptyString80Brand extends Simplify<SchemaB.Brand<"NonEmptyString80"> & NonEmptyString100Brand> {}
65
82
 
66
83
  /**
67
84
  * A string that is at least 1 character long and a maximum of 80.
@@ -72,11 +89,13 @@ export type NonEmptyString80 = string & NonEmptyString80Brand
72
89
  * A string that is at least 1 character long and a maximum of 80.
73
90
  */
74
91
 
75
- export const NonEmptyString80 = nonEmptyString.pipe(
92
+ export interface NonEmptyString80Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString80> {
93
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString80
94
+ }
95
+ export const NonEmptyString80: NonEmptyString80Schema = nonEmptyString.pipe(
76
96
  S.check(S.isMaxLength(80)),
77
- fromBrand(nominal<NonEmptyString80>(), {
97
+ fromBrand<NonEmptyString80>(nominal<NonEmptyString80>(), {
78
98
  identifier: "NonEmptyString80",
79
- title: "NonEmptyString80",
80
99
  jsonSchema: {}
81
100
  }),
82
101
  withDefaultMake
@@ -85,7 +104,7 @@ export const NonEmptyString80 = nonEmptyString.pipe(
85
104
  /**
86
105
  * A string that is at least 1 character long and a maximum of 100.
87
106
  */
88
- export interface NonEmptyString100Brand extends Simplify<B.Brand<"NonEmptyString100"> & NonEmptyString255Brand> {}
107
+ export interface NonEmptyString100Brand extends Simplify<SchemaB.Brand<"NonEmptyString100"> & NonEmptyString255Brand> {}
89
108
 
90
109
  /**
91
110
  * A string that is at least 1 character long and a maximum of 100.
@@ -95,11 +114,13 @@ export type NonEmptyString100 = string & NonEmptyString100Brand
95
114
  /**
96
115
  * A string that is at least 1 character long and a maximum of 100.
97
116
  */
98
- export const NonEmptyString100 = nonEmptyString.pipe(
117
+ export interface NonEmptyString100Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString100> {
118
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString100
119
+ }
120
+ export const NonEmptyString100: NonEmptyString100Schema = nonEmptyString.pipe(
99
121
  S.check(S.isMaxLength(100)),
100
- fromBrand(nominal<NonEmptyString100>(), {
122
+ fromBrand<NonEmptyString100>(nominal<NonEmptyString100>(), {
101
123
  identifier: "NonEmptyString100",
102
- title: "NonEmptyString100",
103
124
  jsonSchema: {}
104
125
  }),
105
126
  withDefaultMake
@@ -108,7 +129,7 @@ export const NonEmptyString100 = nonEmptyString.pipe(
108
129
  /**
109
130
  * A string that is at least 3 character long and a maximum of 255.
110
131
  */
111
- export interface Min3String255Brand extends Simplify<B.Brand<"Min3String255"> & NonEmptyString255Brand> {}
132
+ export interface Min3String255Brand extends Simplify<SchemaB.Brand<"Min3String255"> & NonEmptyString255Brand> {}
112
133
 
113
134
  /**
114
135
  * A string that is at least 3 character long and a maximum of 255.
@@ -118,58 +139,79 @@ export type Min3String255 = string & Min3String255Brand
118
139
  /**
119
140
  * A string that is at least 3 character long and a maximum of 255.
120
141
  */
121
- export const Min3String255 = pipe(
142
+ export interface Min3String255Schema extends BrandedSchema<S.String, Min3String255> {
143
+ (i: string, options?: SchemaAST.ParseOptions): Min3String255
144
+ }
145
+ export const Min3String255: Min3String255Schema = pipe(
122
146
  S.String,
123
147
  S.check(S.isMinLength(3), S.isMaxLength(255)),
124
- fromBrand(nominal<Min3String255>(), { identifier: "Min3String255", title: "Min3String255", jsonSchema: {} }),
148
+ fromBrand<Min3String255>(nominal<Min3String255>(), {
149
+ identifier: "Min3String255",
150
+ jsonSchema: {}
151
+ }),
125
152
  withDefaultMake
126
153
  )
127
154
 
128
155
  /**
129
156
  * A string that is at least 6 characters long and a maximum of 50.
130
157
  */
131
- export interface StringIdBrand extends Simplify<B.Brand<"StringId"> & NonEmptyString50Brand> {}
158
+ export interface StringIdBrand extends Simplify<SchemaB.Brand<"StringId"> & NonEmptyString50Brand> {}
132
159
 
133
160
  /**
134
161
  * A string that is at least 6 characters long and a maximum of 50.
135
162
  */
136
163
  export type StringId = string & StringIdBrand
137
164
 
138
- const makeStringId = (): StringId => nanoid() as unknown as StringId
139
165
  const minLength = 6
140
166
  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)
167
+ const StringIdSchemaBase = pipe(
168
+ S.String,
169
+ S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
170
+ fromBrand<StringId>(nominal<StringId>(), {
171
+ identifier: "StringId",
172
+ jsonSchema: {}
173
+ })
174
+ )
175
+ const makeStringId = (s?: string): StringId =>
176
+ s !== undefined ? S.decodeSync(StringIdSchemaBase)(s) : nanoid() as unknown as StringId
147
177
  /**
148
178
  * A string that is at least 6 characters long and a maximum of 50.
179
+ *
180
+ * `.withConstructorDefault` => fresh `nanoid()` (construction-only; not
181
+ * applied during decode — see file-level note).
149
182
  */
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
- ),
183
+ export interface StringIdSchema extends BrandedSchema<S.String, StringId> {
184
+ (i: string, options?: SchemaAST.ParseOptions): StringId
185
+ /** Generate fresh `nanoid()`-shaped `StringId`. */
186
+ make(): StringId
187
+ /** Construct a `StringId` from a known string (validated via decodeSync). */
188
+ make(input: string, options?: S.MakeOptions): StringId
189
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.String, StringId>>
190
+ }
191
+ export const StringId: StringIdSchema = extendM(
192
+ StringIdSchemaBase,
161
193
  (s) => ({
162
194
  make: makeStringId,
163
- withDefault: s.pipe(withDefaultConstructor(makeStringId))
195
+ /**
196
+ * Construction-only default: fresh `nanoid()`-shaped `StringId`. Applied
197
+ * only when the field is omitted from `.make(...)` input. NOT applied
198
+ * during decode — cannot be used to JIT-migrate database fields. See
199
+ * file-level note.
200
+ */
201
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(makeStringId)))
164
202
  })
165
203
  )
166
204
  .pipe(withDefaultMake)
167
205
 
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>() {
206
+ /**
207
+ * Build a `StringId` schema whose values are required to start with a fixed
208
+ * `prefix` (joined with `separator`, default `-`).
209
+ *
210
+ * The returned schema exposes `.withConstructorDefault` that mints a fresh
211
+ * prefixed id. Construction-only — not applied during decode; see file-level
212
+ * note.
213
+ */
214
+ export function prefixedStringId<Type extends StringId>() {
173
215
  return <Prefix extends string, Separator extends string = "-">(
174
216
  prefix: Prefix,
175
217
  name: string,
@@ -177,27 +219,19 @@ export function prefixedStringId<Brand extends StringId>() {
177
219
  ) => {
178
220
  type FullPrefix = `${Prefix}${Separator}`
179
221
  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
222
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
185
- const s: S.Codec<string & Brand, string> = StringId
223
+ const s = StringIdSchemaBase
186
224
  .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)
225
+ S.refine((x: string): x is Type => x.startsWith(pref), {
226
+ identifier: name
193
227
  })
194
- ) as S.Codec<string & Brand, string>
228
+ )
195
229
  const schema = s.pipe(withDefaultMake)
196
- const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Brand
230
+ const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Type
197
231
 
198
232
  return extendM(
199
233
  schema,
200
- (ex): PrefixedStringUtils<Brand, Prefix, Separator> => ({
234
+ (ex): PrefixedStringUtils<Type, Prefix, Separator> => ({
201
235
  make,
202
236
  /**
203
237
  * Automatically adds the prefix.
@@ -208,35 +242,60 @@ export function prefixedStringId<Brand extends StringId>() {
208
242
  */
209
243
  prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
210
244
  prefix,
211
- withDefault: schema.pipe(withDefaultConstructor(make))
245
+ /**
246
+ * Construction-only default: fresh prefixed id. Applied only when
247
+ * the field is omitted from `.make(...)` input. NOT applied during
248
+ * decode — cannot be used to JIT-migrate database fields. See
249
+ * file-level note.
250
+ */
251
+ withConstructorDefault: schema.pipe(
252
+ S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>(
253
+ Effect.sync(make)
254
+ )
255
+ )
212
256
  })
213
257
  )
214
258
  }
215
259
  }
216
260
 
217
- export const brandedStringId = <
218
- Brand extends StringIdBrand
219
- >() =>
261
+ /**
262
+ * Build a branded `StringId` schema for the given branded `Id` type.
263
+ *
264
+ * Exposes `.withConstructorDefault` that mints a fresh `nanoid()`-shaped id.
265
+ * Construction-only — not applied during decode; see file-level note.
266
+ */
267
+ export const brandedStringId = <Id extends string & B.Brand<any>>(): BrandedStringIdSchema<Id> =>
220
268
  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>>
269
+ Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema<Id>
225
270
  )
226
271
 
227
272
  export interface PrefixedStringUtils<
228
- Brand extends StringId,
273
+ Type extends StringId,
229
274
  Prefix extends string,
230
275
  Separator extends string
231
276
  > {
232
- readonly make: () => Brand
233
- readonly unsafeFrom: (str: string) => Brand
234
- prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Brand
277
+ readonly make: () => Type
278
+ readonly unsafeFrom: (str: string) => Type
279
+ prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Type
235
280
  readonly prefix: Prefix
236
- readonly withDefault: S.withConstructorDefault<S.Codec<Brand, string> & S.WithoutConstructorDefault>
281
+ /**
282
+ * Construction-only default: fresh prefixed id. Applied only when the
283
+ * field is omitted from `.make(...)` input. NOT applied during decode —
284
+ * cannot be used to JIT-migrate database fields. See file-level note.
285
+ */
286
+ readonly withConstructorDefault: S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>
287
+ }
288
+
289
+ export interface BrandedStringIdSchema<Id extends string & B.Brand<any>> extends BrandedSchema<S.String, Id> {
290
+ (i: string, options?: SchemaAST.ParseOptions): Id
291
+ /** Generate fresh `nanoid()`-shaped id (inherited from `StringId`). */
292
+ make(): Id
293
+ /** Construct an `Id` from a known string (validated via decodeSync). */
294
+ make(input: string, options?: S.MakeOptions): Id
295
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.String, Id>>
237
296
  }
238
297
 
239
- export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
298
+ export interface UrlBrand extends Simplify<SchemaB.Brand<"Url"> & NonEmptyStringBrand> {}
240
299
 
241
300
  export type Url = string & UrlBrand
242
301
 
@@ -244,16 +303,19 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
244
303
  return validator.default.isURL(s, { require_tld: false })
245
304
  }
246
305
 
247
- export const Url = S
306
+ export interface UrlSchema extends S.refine<Url, S.String> {
307
+ (i: string, options?: SchemaAST.ParseOptions): Url
308
+ }
309
+ export const Url: UrlSchema = S
248
310
  .String
249
311
  .pipe(
312
+ S.annotate({
313
+ title: "Url",
314
+ format: "uri"
315
+ }),
250
316
  S.refine(isUrl, {
251
317
  identifier: "Url",
252
- title: "Url",
253
318
  jsonSchema: { format: "uri" }
254
319
  }),
255
- S.annotate({
256
- toArbitrary: () => (fc) => fc.webUrl().map((_) => _ as Url)
257
- }),
258
320
  withDefaultMake
259
321
  )
@@ -1,76 +1,145 @@
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"
2
13
  import * as S from "effect/Schema"
3
14
  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"
15
+ import type * as SchemaAST from "../SchemaAST.ts"
16
+ import { type BrandedSchema, fromBrand, nominal } from "./brand.ts"
17
+ import { withDefaultMake } from "./ext.ts"
18
+ import { type B } from "./schema.ts"
7
19
 
8
20
  export interface PositiveIntBrand
9
21
  extends Simplify<B.Brand<"PositiveInt"> & NonNegativeIntBrand & PositiveNumberBrand>
10
22
  {}
11
- export const PositiveInt = extendM(
23
+ export type PositiveInt = number & PositiveIntBrand
24
+ /** Positive integer. `.withConstructorDefault` => `1` (construction-only). */
25
+ export interface PositiveIntSchema extends BrandedSchema<S.Int, PositiveInt> {
26
+ (i: number, options?: SchemaAST.ParseOptions): PositiveInt
27
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Int, PositiveInt>>
28
+ }
29
+ export const PositiveInt: PositiveIntSchema = extendM(
12
30
  S.Int.pipe(
13
31
  S.check(S.isGreaterThan(0)),
14
- fromBrand(nominal<PositiveInt>(), { identifier: "PositiveInt", title: "PositiveInt", jsonSchema: {} }),
32
+ fromBrand<PositiveInt>(nominal<PositiveInt>(), { identifier: "PositiveInt", jsonSchema: {} }),
15
33
  withDefaultMake
16
34
  ),
17
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(1))) })
35
+ (s) => ({
36
+ /**
37
+ * Construction-only default `1`. Applied only when the field is omitted
38
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
39
+ * JIT-migrate database fields. See file-level note.
40
+ */
41
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1))))
42
+ })
18
43
  )
19
- export type PositiveInt = number & PositiveIntBrand
20
44
 
21
45
  export interface NonNegativeIntBrand extends Simplify<B.Brand<"NonNegativeInt"> & IntBrand & NonNegativeNumberBrand> {}
22
- export const NonNegativeInt = extendM(
46
+ export type NonNegativeInt = number & NonNegativeIntBrand
47
+ /** Non-negative integer. `.withConstructorDefault` => `0` (construction-only). */
48
+ export interface NonNegativeIntSchema extends BrandedSchema<S.Int, NonNegativeInt> {
49
+ (i: number, options?: SchemaAST.ParseOptions): NonNegativeInt
50
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Int, NonNegativeInt>>
51
+ }
52
+ export const NonNegativeInt: NonNegativeIntSchema = extendM(
23
53
  S.Int.pipe(
24
54
  S.check(S.isGreaterThanOrEqualTo(0)),
25
- fromBrand(nominal<NonNegativeInt>(), {
55
+ fromBrand<NonNegativeInt>(nominal<NonNegativeInt>(), {
26
56
  identifier: "NonNegativeInt",
27
- title: "NonNegativeInt",
28
57
  jsonSchema: {}
29
58
  }),
30
59
  withDefaultMake
31
60
  ),
32
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(0))) })
61
+ (s) => ({
62
+ /**
63
+ * Construction-only default `0`. Applied only when the field is omitted
64
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
65
+ * JIT-migrate database fields. See file-level note.
66
+ */
67
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0))))
68
+ })
33
69
  )
34
- export type NonNegativeInt = number & NonNegativeIntBrand
35
70
 
36
71
  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
72
  export type Int = number & IntBrand
73
+ /** Integer. `.withConstructorDefault` => `0` (construction-only). */
74
+ export interface IntSchema extends BrandedSchema<S.Int, Int> {
75
+ (i: number, options?: SchemaAST.ParseOptions): Int
76
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Int, Int>>
77
+ }
78
+ export const Int: IntSchema = extendM(
79
+ S.Int.pipe(fromBrand<Int>(nominal<Int>(), { identifier: "Int", jsonSchema: {} }), withDefaultMake),
80
+ (s) => ({
81
+ /**
82
+ * Construction-only default `0`. Applied only when the field is omitted
83
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
84
+ * JIT-migrate database fields. See file-level note.
85
+ */
86
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0))))
87
+ })
88
+ )
42
89
 
43
90
  export interface PositiveNumberBrand extends Simplify<B.Brand<"PositiveNumber"> & NonNegativeNumberBrand> {}
44
- export const PositiveNumber = extendM(
45
- S.Number.pipe(
91
+ export type PositiveNumber = number & PositiveNumberBrand
92
+ /** Positive finite number. `.withConstructorDefault` => `1` (construction-only). */
93
+ export interface PositiveNumberSchema extends BrandedSchema<S.Finite, PositiveNumber> {
94
+ (i: number, options?: SchemaAST.ParseOptions): PositiveNumber
95
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Finite, PositiveNumber>>
96
+ }
97
+ export const PositiveNumber: PositiveNumberSchema = extendM(
98
+ S.Finite.pipe(
46
99
  S.check(S.isGreaterThan(0)),
47
- fromBrand(nominal<PositiveNumber>(), {
100
+ fromBrand<PositiveNumber>(nominal<PositiveNumber>(), {
48
101
  identifier: "PositiveNumber",
49
- title: "PositiveNumber",
50
102
  jsonSchema: {}
51
103
  }),
52
104
  withDefaultMake
53
105
  ),
54
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(1))) })
106
+ (s) => ({
107
+ /**
108
+ * Construction-only default `1`. Applied only when the field is omitted
109
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
110
+ * JIT-migrate database fields. See file-level note.
111
+ */
112
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1))))
113
+ })
55
114
  )
56
- export type PositiveNumber = number & PositiveNumberBrand
57
115
 
58
116
  export interface NonNegativeNumberBrand extends Simplify<B.Brand<"NonNegativeNumber">> {}
59
- export const NonNegativeNumber = extendM(
117
+ export type NonNegativeNumber = number & NonNegativeNumberBrand
118
+ /** Non-negative finite number. `.withConstructorDefault` => `0` (construction-only). */
119
+ export interface NonNegativeNumberSchema extends BrandedSchema<S.Finite, NonNegativeNumber> {
120
+ (i: number, options?: SchemaAST.ParseOptions): NonNegativeNumber
121
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.Finite, NonNegativeNumber>>
122
+ }
123
+ export const NonNegativeNumber: NonNegativeNumberSchema = extendM(
60
124
  S
61
- .Number
125
+ .Finite
62
126
  .pipe(
63
127
  S.check(S.isGreaterThanOrEqualTo(0)),
64
- fromBrand(nominal<NonNegativeNumber>(), {
128
+ fromBrand<NonNegativeNumber>(nominal<NonNegativeNumber>(), {
65
129
  identifier: "NonNegativeNumber",
66
- title: "NonNegativeNumber",
67
130
  jsonSchema: {}
68
131
  }),
69
132
  withDefaultMake
70
133
  ),
71
- (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => s(0))) })
134
+ (s) => ({
135
+ /**
136
+ * Construction-only default `0`. Applied only when the field is omitted
137
+ * from `.make(...)` input. NOT applied during decode — cannot be used to
138
+ * JIT-migrate database fields. See file-level note.
139
+ */
140
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0))))
141
+ })
72
142
  )
73
- export type NonNegativeNumber = number & NonNegativeNumberBrand
74
143
 
75
144
  /** @deprecated Not an actual decimal */
76
145
  export const NonNegativeDecimal = NonNegativeNumber
@@ -2,10 +2,9 @@ import type { Refinement } from "effect-app/Function"
2
2
  import { isValidPhone } from "effect-app/validation"
3
3
  import * as S from "effect/Schema"
4
4
  import type { Simplify } from "effect/Types"
5
- import { withDefaultMake } from "./ext.js"
6
- import { Numbers } from "./FastCheck.js"
7
- import type { B } from "./schema.js"
8
- import type { NonEmptyStringBrand } from "./strings.js"
5
+ import { withDefaultMake } from "./ext.ts"
6
+ import type { B } from "./schema.ts"
7
+ import type { NonEmptyStringBrand } from "./strings.ts"
9
8
 
10
9
  export interface PhoneNumberBrand extends Simplify<B.Brand<"PhoneNumber"> & NonEmptyStringBrand> {}
11
10
  export type PhoneNumber = string & PhoneNumberBrand
@@ -13,14 +12,15 @@ export type PhoneNumber = string & PhoneNumberBrand
13
12
  export const PhoneNumber = S
14
13
  .String
15
14
  .pipe(
15
+ S.annotate({
16
+ title: "PhoneNumber",
17
+ description: "a phone number with at least 7 digits",
18
+ format: "phone"
19
+ }),
16
20
  S.refine(isValidPhone as Refinement<string, PhoneNumber>, {
17
21
  identifier: "PhoneNumber",
18
- title: "PhoneNumber",
19
22
  description: "a phone number with at least 7 digits",
20
23
  jsonSchema: { format: "phone" }
21
24
  }),
22
- S.annotate({
23
- toArbitrary: () => (fc) => Numbers(7, 10)(fc).map((_) => _ as PhoneNumber)
24
- }),
25
25
  withDefaultMake
26
26
  )
@@ -1,5 +1,5 @@
1
1
  import * as B from "effect/Brand"
2
- import * as AST from "effect/SchemaAST"
3
2
  import * as P from "effect/SchemaParser"
3
+ import * as AST from "../SchemaAST.ts"
4
4
 
5
5
  export { AST, B, P }