effect-app 4.0.0-beta.3 → 4.0.0-beta.300

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 +1592 -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/Context.d.ts +42 -0
  18. package/dist/Context.d.ts.map +1 -0
  19. package/dist/Context.js +67 -0
  20. package/dist/DataDependencies.d.ts +388 -0
  21. package/dist/DataDependencies.d.ts.map +1 -0
  22. package/dist/DataDependencies.js +64 -0
  23. package/dist/Effect.d.ts +10 -9
  24. package/dist/Effect.d.ts.map +1 -1
  25. package/dist/Effect.js +5 -7
  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/ext.d.ts +60 -0
  37. package/dist/Model/Repository/ext.d.ts.map +1 -0
  38. package/dist/Model/Repository/ext.js +122 -0
  39. package/dist/Model/Repository/internal/internal.d.ts +63 -0
  40. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  41. package/dist/Model/Repository/internal/internal.js +438 -0
  42. package/dist/Model/Repository/legacy.d.ts +21 -0
  43. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  44. package/dist/Model/Repository/legacy.js +2 -0
  45. package/dist/Model/Repository/makeRepo.d.ts +54 -0
  46. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  47. package/dist/Model/Repository/makeRepo.js +27 -0
  48. package/dist/Model/Repository/service.d.ts +121 -0
  49. package/dist/Model/Repository/service.d.ts.map +1 -0
  50. package/dist/Model/Repository/service.js +2 -0
  51. package/dist/Model/Repository/validation.d.ts +58 -0
  52. package/dist/Model/Repository/validation.d.ts.map +1 -0
  53. package/dist/Model/Repository/validation.js +32 -0
  54. package/dist/Model/Repository.d.ts +7 -0
  55. package/dist/Model/Repository.d.ts.map +1 -0
  56. package/dist/Model/Repository.js +7 -0
  57. package/dist/Model/dsl.d.ts +33 -0
  58. package/dist/Model/dsl.d.ts.map +1 -0
  59. package/dist/Model/dsl.js +43 -0
  60. package/dist/Model/filter/filterApi.d.ts +30 -0
  61. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  62. package/dist/Model/filter/filterApi.js +2 -0
  63. package/dist/Model/filter/types/errors.d.ts +29 -0
  64. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  65. package/dist/Model/filter/types/errors.js +2 -0
  66. package/dist/Model/filter/types/fields.d.ts +15 -0
  67. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  68. package/dist/Model/filter/types/fields.js +2 -0
  69. package/dist/Model/filter/types/path/common.d.ts +316 -0
  70. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  71. package/dist/Model/filter/types/path/common.js +2 -0
  72. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  73. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  74. package/dist/Model/filter/types/path/eager.js +36 -0
  75. package/dist/Model/filter/types/path/index.d.ts +4 -0
  76. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  77. package/dist/Model/filter/types/path/index.js +3 -0
  78. package/dist/Model/filter/types/utils.d.ts +79 -0
  79. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  80. package/dist/Model/filter/types/utils.js +2 -0
  81. package/dist/Model/filter/types/validator.d.ts +30 -0
  82. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  83. package/dist/Model/filter/types/validator.js +2 -0
  84. package/dist/Model/filter/types.d.ts +5 -0
  85. package/dist/Model/filter/types.d.ts.map +1 -0
  86. package/dist/Model/filter/types.js +7 -0
  87. package/dist/Model/query/dsl.d.ts +514 -0
  88. package/dist/Model/query/dsl.d.ts.map +1 -0
  89. package/dist/Model/query/dsl.js +376 -0
  90. package/dist/Model/query/new-kid-interpreter.d.ts +132 -0
  91. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  92. package/dist/Model/query/new-kid-interpreter.js +361 -0
  93. package/dist/Model/query.d.ts +15 -0
  94. package/dist/Model/query.d.ts.map +1 -0
  95. package/dist/Model/query.js +3 -0
  96. package/dist/Model.d.ts +5 -0
  97. package/dist/Model.d.ts.map +1 -0
  98. package/dist/Model.js +5 -0
  99. package/dist/NonEmptySet.d.ts +3 -1
  100. package/dist/NonEmptySet.d.ts.map +1 -1
  101. package/dist/NonEmptySet.js +2 -2
  102. package/dist/Option.d.ts +1 -0
  103. package/dist/Option.d.ts.map +1 -1
  104. package/dist/Option.js +3 -1
  105. package/dist/Pure.d.ts +7 -5
  106. package/dist/Pure.d.ts.map +1 -1
  107. package/dist/Pure.js +17 -14
  108. package/dist/QueueMaker.d.ts +11 -0
  109. package/dist/QueueMaker.d.ts.map +1 -0
  110. package/dist/QueueMaker.js +11 -0
  111. package/dist/RequestContext.d.ts +87 -0
  112. package/dist/RequestContext.d.ts.map +1 -0
  113. package/dist/RequestContext.js +45 -0
  114. package/dist/RequestScopedDependencies.d.ts +21 -0
  115. package/dist/RequestScopedDependencies.d.ts.map +1 -0
  116. package/dist/RequestScopedDependencies.js +16 -0
  117. package/dist/Schema/Class.d.ts +188 -19
  118. package/dist/Schema/Class.d.ts.map +1 -1
  119. package/dist/Schema/Class.js +259 -22
  120. package/dist/Schema/FastCheck.d.ts.map +1 -1
  121. package/dist/Schema/SchemaParser.d.ts +5 -0
  122. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  123. package/dist/Schema/SchemaParser.js +6 -0
  124. package/dist/Schema/SpecialJsonSchema.d.ts +34 -0
  125. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  126. package/dist/Schema/SpecialJsonSchema.js +118 -0
  127. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  128. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  129. package/dist/Schema/SpecialOpenApi.js +123 -0
  130. package/dist/Schema/brand.d.ts +11 -6
  131. package/dist/Schema/brand.d.ts.map +1 -1
  132. package/dist/Schema/brand.js +3 -1
  133. package/dist/Schema/email.d.ts.map +1 -1
  134. package/dist/Schema/email.js +9 -5
  135. package/dist/Schema/ext.d.ts +340 -56
  136. package/dist/Schema/ext.d.ts.map +1 -1
  137. package/dist/Schema/ext.js +361 -63
  138. package/dist/Schema/moreStrings.d.ts +82 -36
  139. package/dist/Schema/moreStrings.d.ts.map +1 -1
  140. package/dist/Schema/moreStrings.js +53 -44
  141. package/dist/Schema/numbers.d.ts +34 -21
  142. package/dist/Schema/numbers.d.ts.map +1 -1
  143. package/dist/Schema/numbers.js +55 -12
  144. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  145. package/dist/Schema/phoneNumber.js +8 -4
  146. package/dist/Schema/schema.d.ts +1 -1
  147. package/dist/Schema/schema.d.ts.map +1 -1
  148. package/dist/Schema/schema.js +2 -2
  149. package/dist/Schema/strings.d.ts +18 -4
  150. package/dist/Schema/strings.d.ts.map +1 -1
  151. package/dist/Schema/strings.js +1 -5
  152. package/dist/Schema.d.ts +238 -58
  153. package/dist/Schema.d.ts.map +1 -1
  154. package/dist/Schema.js +227 -69
  155. package/dist/SchemaAST.d.ts +2 -0
  156. package/dist/SchemaAST.d.ts.map +1 -0
  157. package/dist/SchemaAST.js +2 -0
  158. package/dist/Set.d.ts +4 -1
  159. package/dist/Set.d.ts.map +1 -1
  160. package/dist/Set.js +3 -2
  161. package/dist/Store.d.ts +163 -0
  162. package/dist/Store.d.ts.map +1 -0
  163. package/dist/Store.js +113 -0
  164. package/dist/_ext/Array.d.ts +1 -1
  165. package/dist/_ext/Array.d.ts.map +1 -1
  166. package/dist/_ext/Array.js +4 -2
  167. package/dist/_ext/misc.d.ts +4 -1
  168. package/dist/_ext/misc.d.ts.map +1 -1
  169. package/dist/_ext/misc.js +4 -2
  170. package/dist/_ext/ord.ext.d.ts +2 -1
  171. package/dist/_ext/ord.ext.d.ts.map +1 -1
  172. package/dist/_ext/ord.ext.js +2 -2
  173. package/dist/builtin.d.ts +2 -14
  174. package/dist/builtin.d.ts.map +1 -1
  175. package/dist/builtin.js +1 -1
  176. package/dist/client/InvalidationKeys.d.ts +30 -0
  177. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  178. package/dist/client/InvalidationKeys.js +37 -0
  179. package/dist/client/apiClientFactory.d.ts +19 -31
  180. package/dist/client/apiClientFactory.d.ts.map +1 -1
  181. package/dist/client/apiClientFactory.js +160 -41
  182. package/dist/client/clientFor.d.ts +54 -18
  183. package/dist/client/clientFor.d.ts.map +1 -1
  184. package/dist/client/clientFor.js +9 -1
  185. package/dist/client/errors.d.ts +82 -27
  186. package/dist/client/errors.d.ts.map +1 -1
  187. package/dist/client/errors.js +75 -19
  188. package/dist/client/makeClient.d.ts +492 -32
  189. package/dist/client/makeClient.d.ts.map +1 -1
  190. package/dist/client/makeClient.js +62 -38
  191. package/dist/client.d.ts +2 -0
  192. package/dist/client.d.ts.map +1 -1
  193. package/dist/client.js +3 -1
  194. package/dist/faker.d.ts.map +1 -1
  195. package/dist/http/Request.d.ts +1 -1
  196. package/dist/http/Request.d.ts.map +1 -1
  197. package/dist/http/Request.js +5 -5
  198. package/dist/ids.d.ts +42 -14
  199. package/dist/ids.d.ts.map +1 -1
  200. package/dist/ids.js +30 -5
  201. package/dist/index.d.ts +6 -8
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +8 -9
  204. package/dist/middleware.d.ts +13 -7
  205. package/dist/middleware.d.ts.map +1 -1
  206. package/dist/middleware.js +14 -8
  207. package/dist/rpc/Invalidation.d.ts +3140 -0
  208. package/dist/rpc/Invalidation.d.ts.map +1 -0
  209. package/dist/rpc/Invalidation.js +178 -0
  210. package/dist/rpc/MiddlewareMaker.d.ts +11 -7
  211. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  212. package/dist/rpc/MiddlewareMaker.js +59 -38
  213. package/dist/rpc/RpcContextMap.d.ts +3 -3
  214. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  215. package/dist/rpc/RpcContextMap.js +4 -4
  216. package/dist/rpc/RpcMiddleware.d.ts +14 -10
  217. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  218. package/dist/rpc/RpcMiddleware.js +1 -1
  219. package/dist/rpc.d.ts +1 -1
  220. package/dist/rpc.d.ts.map +1 -1
  221. package/dist/rpc.js +2 -2
  222. package/dist/runtime.d.ts +19 -0
  223. package/dist/runtime.d.ts.map +1 -0
  224. package/dist/runtime.js +40 -0
  225. package/dist/setupRequest.d.ts +20 -0
  226. package/dist/setupRequest.d.ts.map +1 -0
  227. package/dist/setupRequest.js +72 -0
  228. package/dist/toast.d.ts +51 -0
  229. package/dist/toast.d.ts.map +1 -0
  230. package/dist/toast.js +34 -0
  231. package/dist/transform.d.ts +1 -1
  232. package/dist/transform.d.ts.map +1 -1
  233. package/dist/transform.js +4 -5
  234. package/dist/utils/effectify.d.ts +1 -1
  235. package/dist/utils/effectify.d.ts.map +1 -1
  236. package/dist/utils/effectify.js +2 -2
  237. package/dist/utils/extend.d.ts.map +1 -1
  238. package/dist/utils/gen.d.ts +4 -4
  239. package/dist/utils/gen.d.ts.map +1 -1
  240. package/dist/utils/logLevel.d.ts +2 -2
  241. package/dist/utils/logLevel.d.ts.map +1 -1
  242. package/dist/utils/logger.d.ts +4 -3
  243. package/dist/utils/logger.d.ts.map +1 -1
  244. package/dist/utils/logger.js +4 -4
  245. package/dist/utils.d.ts +50 -37
  246. package/dist/utils.d.ts.map +1 -1
  247. package/dist/utils.js +51 -36
  248. package/dist/validation/validators.d.ts.map +1 -1
  249. package/dist/validation.d.ts.map +1 -1
  250. package/dist/withToast.d.ts +30 -0
  251. package/dist/withToast.d.ts.map +1 -0
  252. package/dist/withToast.js +64 -0
  253. package/package.json +27 -255
  254. package/src/Array.ts +5 -5
  255. package/src/Chunk.ts +3 -3
  256. package/src/Config/SecretURL.ts +6 -3
  257. package/src/Config/internal/configSecretURL.ts +2 -2
  258. package/src/Config.ts +7 -0
  259. package/src/ConfigProvider.ts +5 -0
  260. package/src/{ServiceMap.ts → Context.ts} +59 -65
  261. package/src/DataDependencies.ts +114 -0
  262. package/src/Effect.ts +15 -16
  263. package/src/Emailer.ts +51 -0
  264. package/src/Inputify.type.ts +1 -1
  265. package/src/Layer.ts +11 -7
  266. package/src/Model/Repository/Registry.ts +35 -0
  267. package/src/Model/Repository/ext.ts +375 -0
  268. package/src/Model/Repository/internal/internal.ts +755 -0
  269. package/src/Model/Repository/legacy.ts +29 -0
  270. package/src/Model/Repository/makeRepo.ts +145 -0
  271. package/src/Model/Repository/service.ts +676 -0
  272. package/src/Model/Repository/validation.ts +31 -0
  273. package/src/Model/Repository.ts +6 -0
  274. package/src/Model/dsl.ts +129 -0
  275. package/src/Model/filter/filterApi.ts +60 -0
  276. package/src/Model/filter/types/errors.ts +47 -0
  277. package/src/Model/filter/types/fields.ts +50 -0
  278. package/src/Model/filter/types/path/common.ts +404 -0
  279. package/src/Model/filter/types/path/eager.ts +329 -0
  280. package/src/Model/filter/types/path/index.ts +4 -0
  281. package/src/Model/filter/types/utils.ts +128 -0
  282. package/src/Model/filter/types/validator.ts +46 -0
  283. package/src/Model/filter/types.ts +6 -0
  284. package/src/Model/query/dsl.ts +2770 -0
  285. package/src/Model/query/new-kid-interpreter.ts +526 -0
  286. package/src/Model/query.ts +13 -0
  287. package/src/Model.ts +4 -0
  288. package/src/NonEmptySet.ts +6 -4
  289. package/src/Option.ts +2 -0
  290. package/src/Pure.ts +22 -20
  291. package/src/QueueMaker.ts +11 -0
  292. package/src/RequestContext.ts +48 -0
  293. package/src/RequestScopedDependencies.ts +45 -0
  294. package/src/Schema/Class.ts +631 -63
  295. package/src/Schema/SchemaParser.ts +12 -0
  296. package/src/Schema/SpecialJsonSchema.ts +139 -0
  297. package/src/Schema/SpecialOpenApi.ts +130 -0
  298. package/src/Schema/brand.ts +34 -8
  299. package/src/Schema/email.ts +12 -5
  300. package/src/Schema/ext.ts +469 -106
  301. package/src/Schema/moreStrings.ts +155 -73
  302. package/src/Schema/numbers.ts +97 -28
  303. package/src/Schema/phoneNumber.ts +12 -6
  304. package/src/Schema/schema.ts +1 -1
  305. package/src/Schema/strings.ts +23 -14
  306. package/src/Schema.ts +468 -121
  307. package/src/SchemaAST.ts +1 -0
  308. package/src/Set.ts +6 -2
  309. package/src/Store.ts +273 -0
  310. package/src/_ext/Array.ts +4 -2
  311. package/src/_ext/misc.ts +4 -1
  312. package/src/_ext/ord.ext.ts +2 -1
  313. package/src/builtin-json.d.ts +24 -0
  314. package/src/builtin.ts +16 -21
  315. package/src/client/InvalidationKeys.ts +55 -0
  316. package/src/client/apiClientFactory.ts +306 -144
  317. package/src/client/clientFor.ts +107 -34
  318. package/src/client/errors.ts +109 -29
  319. package/src/client/makeClient.ts +593 -87
  320. package/src/client.ts +6 -4
  321. package/src/http/Request.ts +9 -6
  322. package/src/http.ts +1 -1
  323. package/src/ids.ts +34 -7
  324. package/src/index.ts +20 -24
  325. package/src/middleware.ts +13 -9
  326. package/src/rpc/Invalidation.ts +278 -0
  327. package/src/rpc/MiddlewareMaker.ts +88 -80
  328. package/src/rpc/README.md +2 -2
  329. package/src/rpc/RpcContextMap.ts +7 -6
  330. package/src/rpc/RpcMiddleware.ts +19 -13
  331. package/src/rpc.ts +4 -4
  332. package/src/runtime.ts +56 -0
  333. package/src/setupRequest.ts +138 -0
  334. package/src/toast.ts +54 -0
  335. package/src/transform.ts +4 -4
  336. package/src/utils/effectify.ts +1 -1
  337. package/src/utils/gen.ts +8 -8
  338. package/src/utils/logLevel.ts +1 -1
  339. package/src/utils/logger.ts +4 -3
  340. package/src/utils.ts +105 -156
  341. package/src/validation.ts +2 -2
  342. package/src/withToast.ts +133 -0
  343. package/test/dist/moreStrings.test.d.ts.map +1 -0
  344. package/test/dist/rpc.test.d.ts.map +1 -1
  345. package/test/dist/rpcMiddlewareContext.test.d.ts.map +1 -0
  346. package/test/dist/secretURL.test.d.ts.map +1 -0
  347. package/test/dist/special.test.d.ts.map +1 -0
  348. package/test/moreStrings.test.ts +17 -0
  349. package/test/rpc.test.ts +45 -6
  350. package/test/rpcMiddlewareContext.test.ts +63 -0
  351. package/test/schema.test.ts +613 -7
  352. package/test/secretURL.test.ts +160 -0
  353. package/test/special.test.ts +1258 -0
  354. package/test/utils.test.ts +7 -7
  355. package/tsconfig.base.json +6 -5
  356. package/tsconfig.json +3 -1
  357. package/tsconfig.src.json +29 -29
  358. package/tsconfig.test.json +2 -2
  359. package/dist/Operations.d.ts +0 -87
  360. package/dist/Operations.d.ts.map +0 -1
  361. package/dist/Operations.js +0 -29
  362. package/dist/ServiceMap.d.ts +0 -44
  363. package/dist/ServiceMap.d.ts.map +0 -1
  364. package/dist/ServiceMap.js +0 -91
  365. package/dist/Struct.d.ts +0 -44
  366. package/dist/Struct.d.ts.map +0 -1
  367. package/dist/Struct.js +0 -29
  368. package/eslint.config.mjs +0 -26
  369. package/src/Operations.ts +0 -55
  370. package/src/Struct.ts +0 -54
  371. 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
18
  import { customRandom, nanoid, urlAlphabet } 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,59 +139,86 @@ 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
167
  const size = 21
142
168
  const length = 10 * size
143
- const StringIdArb = (): any => (fc: any) =>
169
+ const StringIdSchemaBase = pipe(
170
+ S.String,
171
+ S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
172
+ fromBrand<StringId>(nominal<StringId>(), {
173
+ identifier: "StringId",
174
+ toArbitrary: () => (fc) => StringIdArb()(fc),
175
+ jsonSchema: {}
176
+ })
177
+ )
178
+ const makeStringId = (s?: string): StringId =>
179
+ s !== undefined ? S.decodeSync(StringIdSchemaBase)(s) : nanoid() as unknown as StringId
180
+ const StringIdArb = (): S.LazyArbitrary<StringId> => (fc) =>
144
181
  fc
145
182
  .uint8Array({ minLength: length, maxLength: length })
146
- .map((_: any) => customRandom(urlAlphabet, size, (size: number) => _.subarray(0, size))())
147
-
183
+ .map((_) => customRandom(urlAlphabet, size, (size) => _.subarray(0, size))() as StringId)
148
184
  /**
149
185
  * A string that is at least 6 characters long and a maximum of 50.
186
+ *
187
+ * `.withConstructorDefault` => fresh `nanoid()` (construction-only; not
188
+ * applied during decode — see file-level note).
150
189
  */
151
- export const StringId = extendM(
152
- pipe(
153
- S.String,
154
- S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
155
- fromBrand(nominal<StringId>(), {
156
- identifier: "StringId",
157
- title: "StringId",
158
- arbitrary: StringIdArb,
159
- jsonSchema: {}
160
- })
161
- ),
190
+ export interface StringIdSchema extends BrandedSchema<S.String, StringId> {
191
+ (i: string, options?: SchemaAST.ParseOptions): StringId
192
+ /** Generate fresh `nanoid()`-shaped `StringId`. */
193
+ make(): StringId
194
+ /** Construct a `StringId` from a known string (validated via decodeSync). */
195
+ make(input: string, options?: S.MakeOptions): StringId
196
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.String, StringId>>
197
+ }
198
+ export const StringId: StringIdSchema = extendM(
199
+ StringIdSchemaBase,
162
200
  (s) => ({
163
201
  make: makeStringId,
164
- withDefault: s.pipe(withDefaultConstructor(makeStringId))
202
+ /**
203
+ * Construction-only default: fresh `nanoid()`-shaped `StringId`. Applied
204
+ * only when the field is omitted from `.make(...)` input. NOT applied
205
+ * during decode — cannot be used to JIT-migrate database fields. See
206
+ * file-level note.
207
+ */
208
+ withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(makeStringId)))
165
209
  })
166
210
  )
167
211
  .pipe(withDefaultMake)
168
212
 
169
- // const prefixedStringIdUnsafe = (prefix: string) => StringId(prefix + StringId.make())
170
-
171
- // const prefixedStringIdUnsafeThunk = (prefix: string) => () => prefixedStringIdUnsafe(prefix)
172
-
173
- export function prefixedStringId<Brand extends StringId>() {
213
+ /**
214
+ * Build a `StringId` schema whose values are required to start with a fixed
215
+ * `prefix` (joined with `separator`, default `-`).
216
+ *
217
+ * The returned schema exposes `.withConstructorDefault` that mints a fresh
218
+ * prefixed id. Construction-only — not applied during decode; see file-level
219
+ * note.
220
+ */
221
+ export function prefixedStringId<Type extends StringId>() {
174
222
  return <Prefix extends string, Separator extends string = "-">(
175
223
  prefix: Prefix,
176
224
  name: string,
@@ -178,25 +226,26 @@ export function prefixedStringId<Brand extends StringId>() {
178
226
  ) => {
179
227
  type FullPrefix = `${Prefix}${Separator}`
180
228
  const pref = `${prefix}${separator ?? "-"}` as FullPrefix
181
- const arb = (): any => (fc: any) =>
229
+ const arb = (): S.LazyArbitrary<Type> => (fc) =>
182
230
  StringIdArb()(fc).map(
183
- (x: any) => (pref + x.substring(0, 50 - pref.length)) as Brand
231
+ (x) => (pref + x.substring(0, 50 - pref.length)) as Type
184
232
  )
185
233
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
186
- const s: S.Codec<string & Brand, string> = StringId
234
+ const s = StringIdSchemaBase
187
235
  .pipe(
188
- S.refine((x: string): x is string & Brand => x.startsWith(pref), {
189
- arbitrary: arb,
190
- identifier: name,
191
- title: name
236
+ S.refine((x: string): x is Type => x.startsWith(pref), {
237
+ identifier: name
238
+ }),
239
+ S.annotate({
240
+ toArbitrary: () => (fc) => arb()(fc)
192
241
  })
193
- ) as any
242
+ )
194
243
  const schema = s.pipe(withDefaultMake)
195
- const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Brand
244
+ const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Type
196
245
 
197
246
  return extendM(
198
247
  schema,
199
- (ex): PrefixedStringUtils<Brand, Prefix, Separator> => ({
248
+ (ex): PrefixedStringUtils<Type, Prefix, Separator> => ({
200
249
  make,
201
250
  /**
202
251
  * Automatically adds the prefix.
@@ -207,35 +256,60 @@ export function prefixedStringId<Brand extends StringId>() {
207
256
  */
208
257
  prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
209
258
  prefix,
210
- withDefault: schema.pipe(withDefaultConstructor(make))
259
+ /**
260
+ * Construction-only default: fresh prefixed id. Applied only when
261
+ * the field is omitted from `.make(...)` input. NOT applied during
262
+ * decode — cannot be used to JIT-migrate database fields. See
263
+ * file-level note.
264
+ */
265
+ withConstructorDefault: schema.pipe(
266
+ S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>(
267
+ Effect.sync(make)
268
+ )
269
+ )
211
270
  })
212
271
  )
213
272
  }
214
273
  }
215
274
 
216
- export const brandedStringId = <
217
- Brand extends StringIdBrand
218
- >() =>
275
+ /**
276
+ * Build a branded `StringId` schema for the given branded `Id` type.
277
+ *
278
+ * Exposes `.withConstructorDefault` that mints a fresh `nanoid()`-shaped id.
279
+ * Construction-only — not applied during decode; see file-level note.
280
+ */
281
+ export const brandedStringId = <Id extends string & B.Brand<any>>(): BrandedStringIdSchema<Id> =>
219
282
  withDefaultMake(
220
- Object.assign(Object.create(StringId), StringId) as S.Codec<string & Brand> & {
221
- make: () => string & Brand
222
- withDefault: any
223
- } & WithDefaults<S.Codec<string & Brand>>
283
+ Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema<Id>
224
284
  )
225
285
 
226
286
  export interface PrefixedStringUtils<
227
- Brand extends StringId,
287
+ Type extends StringId,
228
288
  Prefix extends string,
229
289
  Separator extends string
230
290
  > {
231
- readonly make: () => Brand
232
- readonly unsafeFrom: (str: string) => Brand
233
- prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Brand
291
+ readonly make: () => Type
292
+ readonly unsafeFrom: (str: string) => Type
293
+ prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Type
234
294
  readonly prefix: Prefix
235
- readonly withDefault: any
295
+ /**
296
+ * Construction-only default: fresh prefixed id. Applied only when the
297
+ * field is omitted from `.make(...)` input. NOT applied during decode —
298
+ * cannot be used to JIT-migrate database fields. See file-level note.
299
+ */
300
+ readonly withConstructorDefault: S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>
236
301
  }
237
302
 
238
- export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
303
+ export interface BrandedStringIdSchema<Id extends string & B.Brand<any>> extends BrandedSchema<S.String, Id> {
304
+ (i: string, options?: SchemaAST.ParseOptions): Id
305
+ /** Generate fresh `nanoid()`-shaped id (inherited from `StringId`). */
306
+ make(): Id
307
+ /** Construct an `Id` from a known string (validated via decodeSync). */
308
+ make(input: string, options?: S.MakeOptions): Id
309
+ readonly withConstructorDefault: S.withConstructorDefault<BrandedSchema<S.String, Id>>
310
+ }
311
+
312
+ export interface UrlBrand extends Simplify<SchemaB.Brand<"Url"> & NonEmptyStringBrand> {}
239
313
 
240
314
  export type Url = string & UrlBrand
241
315
 
@@ -243,14 +317,22 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
243
317
  return validator.default.isURL(s, { require_tld: false })
244
318
  }
245
319
 
246
- export const Url = S
320
+ export interface UrlSchema extends S.refine<Url, S.String> {
321
+ (i: string, options?: SchemaAST.ParseOptions): Url
322
+ }
323
+ export const Url: UrlSchema = S
247
324
  .String
248
325
  .pipe(
326
+ S.annotate({
327
+ title: "Url",
328
+ format: "uri"
329
+ }),
249
330
  S.refine(isUrl, {
250
- arbitrary: (): any => (fc: any) => fc.webUrl().map((_: any) => _ as Url),
251
331
  identifier: "Url",
252
- title: "Url",
253
332
  jsonSchema: { format: "uri" }
254
333
  }),
334
+ S.annotate({
335
+ toArbitrary: () => (fc) => fc.webUrl().map((_) => _ as Url)
336
+ }),
255
337
  withDefaultMake
256
338
  )
@@ -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,10 @@ 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 { Numbers } from "./FastCheck.ts"
7
+ import type { B } from "./schema.ts"
8
+ import type { NonEmptyStringBrand } from "./strings.ts"
9
9
 
10
10
  export interface PhoneNumberBrand extends Simplify<B.Brand<"PhoneNumber"> & NonEmptyStringBrand> {}
11
11
  export type PhoneNumber = string & PhoneNumberBrand
@@ -13,12 +13,18 @@ export type PhoneNumber = string & PhoneNumberBrand
13
13
  export const PhoneNumber = S
14
14
  .String
15
15
  .pipe(
16
+ S.annotate({
17
+ title: "PhoneNumber",
18
+ description: "a phone number with at least 7 digits",
19
+ format: "phone"
20
+ }),
16
21
  S.refine(isValidPhone as Refinement<string, PhoneNumber>, {
17
22
  identifier: "PhoneNumber",
18
- title: "PhoneNumber",
19
23
  description: "a phone number with at least 7 digits",
20
- arbitrary: () => (fc: any) => Numbers(7, 10)(fc).map((_: any) => _ as PhoneNumber),
21
24
  jsonSchema: { format: "phone" }
22
25
  }),
26
+ S.annotate({
27
+ toArbitrary: () => (fc) => Numbers(7, 10)(fc).map((_) => _ as PhoneNumber)
28
+ }),
23
29
  withDefaultMake
24
30
  )
@@ -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 }