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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/CHANGELOG.md +1269 -0
  2. package/dist/Array.d.ts +2 -1
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +4 -4
  5. package/dist/Chunk.d.ts.map +1 -1
  6. package/dist/Config/SecretURL.d.ts +3 -1
  7. package/dist/Config/SecretURL.d.ts.map +1 -1
  8. package/dist/Config/SecretURL.js +3 -6
  9. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  10. package/dist/Config/internal/configSecretURL.js +2 -2
  11. package/dist/Config.d.ts +2 -0
  12. package/dist/Config.d.ts.map +1 -0
  13. package/dist/Config.js +8 -0
  14. package/dist/ConfigProvider.d.ts +2 -0
  15. package/dist/ConfigProvider.d.ts.map +1 -0
  16. package/dist/ConfigProvider.js +6 -0
  17. package/dist/{ServiceMap.d.ts → Context.d.ts} +18 -20
  18. package/dist/Context.d.ts.map +1 -0
  19. package/dist/Context.js +67 -0
  20. package/dist/Effect.d.ts +10 -9
  21. package/dist/Effect.d.ts.map +1 -1
  22. package/dist/Effect.js +5 -8
  23. package/dist/Emailer.d.ts +51 -0
  24. package/dist/Emailer.d.ts.map +1 -0
  25. package/dist/Emailer.js +7 -0
  26. package/dist/Function.d.ts.map +1 -1
  27. package/dist/Layer.d.ts +10 -6
  28. package/dist/Layer.d.ts.map +1 -1
  29. package/dist/Layer.js +3 -2
  30. package/dist/Model/Repository/Registry.d.ts +22 -0
  31. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  32. package/dist/Model/Repository/Registry.js +18 -0
  33. package/dist/Model/Repository/ext.d.ts +60 -0
  34. package/dist/Model/Repository/ext.d.ts.map +1 -0
  35. package/dist/Model/Repository/ext.js +122 -0
  36. package/dist/Model/Repository/internal/internal.d.ts +63 -0
  37. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  38. package/dist/Model/Repository/internal/internal.js +430 -0
  39. package/dist/Model/Repository/legacy.d.ts +21 -0
  40. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  41. package/dist/Model/Repository/legacy.js +2 -0
  42. package/dist/Model/Repository/makeRepo.d.ts +54 -0
  43. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  44. package/dist/Model/Repository/makeRepo.js +27 -0
  45. package/dist/Model/Repository/service.d.ts +121 -0
  46. package/dist/Model/Repository/service.d.ts.map +1 -0
  47. package/dist/Model/Repository/service.js +2 -0
  48. package/dist/Model/Repository/validation.d.ts +58 -0
  49. package/dist/Model/Repository/validation.d.ts.map +1 -0
  50. package/dist/Model/Repository/validation.js +32 -0
  51. package/dist/Model/Repository.d.ts +7 -0
  52. package/dist/Model/Repository.d.ts.map +1 -0
  53. package/dist/Model/Repository.js +7 -0
  54. package/dist/Model/dsl.d.ts +33 -0
  55. package/dist/Model/dsl.d.ts.map +1 -0
  56. package/dist/Model/dsl.js +43 -0
  57. package/dist/Model/filter/filterApi.d.ts +30 -0
  58. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  59. package/dist/Model/filter/filterApi.js +2 -0
  60. package/dist/Model/filter/types/errors.d.ts +29 -0
  61. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  62. package/dist/Model/filter/types/errors.js +2 -0
  63. package/dist/Model/filter/types/fields.d.ts +15 -0
  64. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  65. package/dist/Model/filter/types/fields.js +2 -0
  66. package/dist/Model/filter/types/path/common.d.ts +316 -0
  67. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  68. package/dist/Model/filter/types/path/common.js +2 -0
  69. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  70. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  71. package/dist/Model/filter/types/path/eager.js +36 -0
  72. package/dist/Model/filter/types/path/index.d.ts +4 -0
  73. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  74. package/dist/Model/filter/types/path/index.js +3 -0
  75. package/dist/Model/filter/types/utils.d.ts +79 -0
  76. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  77. package/dist/Model/filter/types/utils.js +2 -0
  78. package/dist/Model/filter/types/validator.d.ts +30 -0
  79. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  80. package/dist/Model/filter/types/validator.js +2 -0
  81. package/dist/Model/filter/types.d.ts +5 -0
  82. package/dist/Model/filter/types.d.ts.map +1 -0
  83. package/dist/Model/filter/types.js +7 -0
  84. package/dist/Model/query/dsl.d.ts +493 -0
  85. package/dist/Model/query/dsl.d.ts.map +1 -0
  86. package/dist/Model/query/dsl.js +376 -0
  87. package/dist/Model/query/new-kid-interpreter.d.ts +136 -0
  88. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  89. package/dist/Model/query/new-kid-interpreter.js +336 -0
  90. package/dist/Model/query.d.ts +15 -0
  91. package/dist/Model/query.d.ts.map +1 -0
  92. package/dist/Model/query.js +3 -0
  93. package/dist/Model.d.ts +5 -0
  94. package/dist/Model.d.ts.map +1 -0
  95. package/dist/Model.js +5 -0
  96. package/dist/NonEmptySet.d.ts +3 -1
  97. package/dist/NonEmptySet.d.ts.map +1 -1
  98. package/dist/NonEmptySet.js +2 -2
  99. package/dist/Option.d.ts +1 -0
  100. package/dist/Option.d.ts.map +1 -1
  101. package/dist/Option.js +3 -1
  102. package/dist/Pure.d.ts +7 -5
  103. package/dist/Pure.d.ts.map +1 -1
  104. package/dist/Pure.js +17 -14
  105. package/dist/QueueMaker.d.ts +13 -0
  106. package/dist/QueueMaker.d.ts.map +1 -0
  107. package/dist/QueueMaker.js +4 -0
  108. package/dist/RequestContext.d.ts +208 -0
  109. package/dist/RequestContext.d.ts.map +1 -0
  110. package/dist/RequestContext.js +54 -0
  111. package/dist/Schema/Class.d.ts +157 -19
  112. package/dist/Schema/Class.d.ts.map +1 -1
  113. package/dist/Schema/Class.js +214 -17
  114. package/dist/Schema/FastCheck.d.ts.map +1 -1
  115. package/dist/Schema/SchemaParser.d.ts +5 -0
  116. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  117. package/dist/Schema/SchemaParser.js +6 -0
  118. package/dist/Schema/SpecialJsonSchema.d.ts +34 -0
  119. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  120. package/dist/Schema/SpecialJsonSchema.js +118 -0
  121. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  122. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  123. package/dist/Schema/SpecialOpenApi.js +123 -0
  124. package/dist/Schema/brand.d.ts +4 -2
  125. package/dist/Schema/brand.d.ts.map +1 -1
  126. package/dist/Schema/brand.js +3 -1
  127. package/dist/Schema/email.d.ts.map +1 -1
  128. package/dist/Schema/email.js +7 -4
  129. package/dist/Schema/ext.d.ts +338 -55
  130. package/dist/Schema/ext.d.ts.map +1 -1
  131. package/dist/Schema/ext.js +358 -53
  132. package/dist/Schema/moreStrings.d.ts +82 -36
  133. package/dist/Schema/moreStrings.d.ts.map +1 -1
  134. package/dist/Schema/moreStrings.js +49 -42
  135. package/dist/Schema/numbers.d.ts +34 -21
  136. package/dist/Schema/numbers.d.ts.map +1 -1
  137. package/dist/Schema/numbers.js +55 -12
  138. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  139. package/dist/Schema/phoneNumber.js +6 -3
  140. package/dist/Schema/strings.d.ts +18 -4
  141. package/dist/Schema/strings.d.ts.map +1 -1
  142. package/dist/Schema/strings.js +1 -5
  143. package/dist/Schema.d.ts +213 -7
  144. package/dist/Schema.d.ts.map +1 -1
  145. package/dist/Schema.js +190 -11
  146. package/dist/Set.d.ts +4 -1
  147. package/dist/Set.d.ts.map +1 -1
  148. package/dist/Set.js +3 -2
  149. package/dist/Store.d.ts +170 -0
  150. package/dist/Store.d.ts.map +1 -0
  151. package/dist/Store.js +121 -0
  152. package/dist/_ext/Array.d.ts +1 -1
  153. package/dist/_ext/Array.d.ts.map +1 -1
  154. package/dist/_ext/Array.js +4 -2
  155. package/dist/_ext/misc.d.ts +4 -1
  156. package/dist/_ext/misc.d.ts.map +1 -1
  157. package/dist/_ext/misc.js +4 -2
  158. package/dist/_ext/ord.ext.d.ts +2 -1
  159. package/dist/_ext/ord.ext.d.ts.map +1 -1
  160. package/dist/_ext/ord.ext.js +2 -2
  161. package/dist/client/InvalidationKeys.d.ts +29 -0
  162. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  163. package/dist/client/InvalidationKeys.js +33 -0
  164. package/dist/client/apiClientFactory.d.ts +19 -31
  165. package/dist/client/apiClientFactory.d.ts.map +1 -1
  166. package/dist/client/apiClientFactory.js +104 -34
  167. package/dist/client/clientFor.d.ts +52 -18
  168. package/dist/client/clientFor.d.ts.map +1 -1
  169. package/dist/client/clientFor.js +9 -1
  170. package/dist/client/errors.d.ts +82 -27
  171. package/dist/client/errors.d.ts.map +1 -1
  172. package/dist/client/errors.js +75 -19
  173. package/dist/client/makeClient.d.ts +494 -32
  174. package/dist/client/makeClient.d.ts.map +1 -1
  175. package/dist/client/makeClient.js +66 -24
  176. package/dist/client.d.ts +1 -0
  177. package/dist/client.d.ts.map +1 -1
  178. package/dist/client.js +2 -1
  179. package/dist/faker.d.ts.map +1 -1
  180. package/dist/http/Request.d.ts +1 -1
  181. package/dist/http/Request.d.ts.map +1 -1
  182. package/dist/http/Request.js +2 -2
  183. package/dist/ids.d.ts +42 -14
  184. package/dist/ids.d.ts.map +1 -1
  185. package/dist/ids.js +30 -5
  186. package/dist/index.d.ts +6 -7
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +8 -8
  189. package/dist/middleware.d.ts +13 -7
  190. package/dist/middleware.d.ts.map +1 -1
  191. package/dist/middleware.js +14 -8
  192. package/dist/rpc/Invalidation.d.ts +420 -0
  193. package/dist/rpc/Invalidation.d.ts.map +1 -0
  194. package/dist/rpc/Invalidation.js +168 -0
  195. package/dist/rpc/MiddlewareMaker.d.ts +11 -7
  196. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  197. package/dist/rpc/MiddlewareMaker.js +59 -38
  198. package/dist/rpc/RpcContextMap.d.ts +3 -3
  199. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  200. package/dist/rpc/RpcContextMap.js +4 -4
  201. package/dist/rpc/RpcMiddleware.d.ts +14 -10
  202. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  203. package/dist/rpc/RpcMiddleware.js +1 -1
  204. package/dist/rpc.d.ts +1 -1
  205. package/dist/rpc.d.ts.map +1 -1
  206. package/dist/rpc.js +2 -2
  207. package/dist/runtime.d.ts +19 -0
  208. package/dist/runtime.d.ts.map +1 -0
  209. package/dist/runtime.js +40 -0
  210. package/dist/setupRequest.d.ts +19 -0
  211. package/dist/setupRequest.d.ts.map +1 -0
  212. package/dist/setupRequest.js +69 -0
  213. package/dist/toast.d.ts +51 -0
  214. package/dist/toast.d.ts.map +1 -0
  215. package/dist/toast.js +34 -0
  216. package/dist/transform.d.ts +1 -1
  217. package/dist/transform.d.ts.map +1 -1
  218. package/dist/transform.js +4 -5
  219. package/dist/utils/effectify.d.ts +1 -1
  220. package/dist/utils/effectify.d.ts.map +1 -1
  221. package/dist/utils/effectify.js +2 -2
  222. package/dist/utils/extend.d.ts.map +1 -1
  223. package/dist/utils/gen.d.ts +4 -4
  224. package/dist/utils/gen.d.ts.map +1 -1
  225. package/dist/utils/logLevel.d.ts +2 -2
  226. package/dist/utils/logLevel.d.ts.map +1 -1
  227. package/dist/utils/logger.d.ts +4 -3
  228. package/dist/utils/logger.d.ts.map +1 -1
  229. package/dist/utils/logger.js +4 -4
  230. package/dist/utils.d.ts +34 -39
  231. package/dist/utils.d.ts.map +1 -1
  232. package/dist/utils.js +33 -37
  233. package/dist/validation/validators.d.ts.map +1 -1
  234. package/dist/validation.d.ts.map +1 -1
  235. package/dist/withToast.d.ts +30 -0
  236. package/dist/withToast.d.ts.map +1 -0
  237. package/dist/withToast.js +64 -0
  238. package/package.json +22 -247
  239. package/src/Array.ts +5 -5
  240. package/src/Chunk.ts +3 -3
  241. package/src/Config/SecretURL.ts +6 -3
  242. package/src/Config/internal/configSecretURL.ts +2 -2
  243. package/src/Config.ts +7 -0
  244. package/src/ConfigProvider.ts +5 -0
  245. package/src/{ServiceMap.ts → Context.ts} +56 -63
  246. package/src/Effect.ts +14 -16
  247. package/src/Emailer.ts +51 -0
  248. package/src/Inputify.type.ts +1 -1
  249. package/src/Layer.ts +11 -7
  250. package/src/Model/Repository/Registry.ts +35 -0
  251. package/src/Model/Repository/ext.ts +375 -0
  252. package/src/Model/Repository/internal/internal.ts +741 -0
  253. package/src/Model/Repository/legacy.ts +29 -0
  254. package/src/Model/Repository/makeRepo.ts +145 -0
  255. package/src/Model/Repository/service.ts +676 -0
  256. package/src/Model/Repository/validation.ts +31 -0
  257. package/src/Model/Repository.ts +6 -0
  258. package/src/Model/dsl.ts +129 -0
  259. package/src/Model/filter/filterApi.ts +60 -0
  260. package/src/Model/filter/types/errors.ts +47 -0
  261. package/src/Model/filter/types/fields.ts +50 -0
  262. package/src/Model/filter/types/path/common.ts +404 -0
  263. package/src/Model/filter/types/path/eager.ts +329 -0
  264. package/src/Model/filter/types/path/index.ts +4 -0
  265. package/src/Model/filter/types/utils.ts +128 -0
  266. package/src/Model/filter/types/validator.ts +46 -0
  267. package/src/Model/filter/types.ts +6 -0
  268. package/src/Model/query/dsl.ts +2694 -0
  269. package/src/Model/query/new-kid-interpreter.ts +484 -0
  270. package/src/Model/query.ts +13 -0
  271. package/src/Model.ts +4 -0
  272. package/src/NonEmptySet.ts +6 -4
  273. package/src/Option.ts +2 -0
  274. package/src/Pure.ts +22 -20
  275. package/src/QueueMaker.ts +19 -0
  276. package/src/RequestContext.ts +95 -0
  277. package/src/Schema/Class.ts +517 -59
  278. package/src/Schema/SchemaParser.ts +12 -0
  279. package/src/Schema/SpecialJsonSchema.ts +139 -0
  280. package/src/Schema/SpecialOpenApi.ts +130 -0
  281. package/src/Schema/brand.ts +22 -2
  282. package/src/Schema/email.ts +9 -4
  283. package/src/Schema/ext.ts +446 -91
  284. package/src/Schema/moreStrings.ts +147 -68
  285. package/src/Schema/numbers.ts +97 -28
  286. package/src/Schema/phoneNumber.ts +9 -5
  287. package/src/Schema/strings.ts +23 -14
  288. package/src/Schema.ts +389 -25
  289. package/src/Set.ts +6 -2
  290. package/src/Store.ts +277 -0
  291. package/src/_ext/Array.ts +4 -2
  292. package/src/_ext/misc.ts +4 -1
  293. package/src/_ext/ord.ext.ts +2 -1
  294. package/src/client/InvalidationKeys.ts +50 -0
  295. package/src/client/apiClientFactory.ts +234 -135
  296. package/src/client/clientFor.ts +105 -34
  297. package/src/client/errors.ts +100 -29
  298. package/src/client/makeClient.ts +594 -73
  299. package/src/client.ts +5 -4
  300. package/src/http/Request.ts +3 -3
  301. package/src/http.ts +1 -1
  302. package/src/ids.ts +33 -6
  303. package/src/index.ts +20 -23
  304. package/src/middleware.ts +13 -9
  305. package/src/rpc/Invalidation.ts +261 -0
  306. package/src/rpc/MiddlewareMaker.ts +88 -80
  307. package/src/rpc/README.md +2 -2
  308. package/src/rpc/RpcContextMap.ts +7 -6
  309. package/src/rpc/RpcMiddleware.ts +19 -13
  310. package/src/rpc.ts +4 -4
  311. package/src/runtime.ts +56 -0
  312. package/src/setupRequest.ts +134 -0
  313. package/src/toast.ts +54 -0
  314. package/src/transform.ts +4 -4
  315. package/src/utils/effectify.ts +1 -1
  316. package/src/utils/gen.ts +8 -8
  317. package/src/utils/logLevel.ts +1 -1
  318. package/src/utils/logger.ts +4 -3
  319. package/src/utils.ts +85 -158
  320. package/src/validation.ts +2 -2
  321. package/src/withToast.ts +133 -0
  322. package/test/dist/rpc.test.d.ts.map +1 -1
  323. package/test/dist/secretURL.test.d.ts.map +1 -0
  324. package/test/dist/special.test.d.ts.map +1 -0
  325. package/test/moreStrings.test.ts +1 -1
  326. package/test/rpc.test.ts +46 -6
  327. package/test/schema.test.ts +459 -30
  328. package/test/secretURL.test.ts +160 -0
  329. package/test/special.test.ts +1026 -0
  330. package/test/utils.test.ts +7 -7
  331. package/tsconfig.base.json +6 -5
  332. package/tsconfig.json +3 -1
  333. package/tsconfig.json.bak +2 -2
  334. package/tsconfig.src.json +29 -29
  335. package/tsconfig.test.json +2 -2
  336. package/dist/Operations.d.ts +0 -123
  337. package/dist/Operations.d.ts.map +0 -1
  338. package/dist/Operations.js +0 -29
  339. package/dist/ServiceMap.d.ts.map +0 -1
  340. package/dist/ServiceMap.js +0 -91
  341. package/eslint.config.mjs +0 -26
  342. package/src/Operations.ts +0 -55
@@ -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"
17
+ import type * as SchemaAST from "effect/SchemaAST"
5
18
  import type { Simplify } from "effect/Types"
6
19
  import { customRandom, nanoid, urlAlphabet } from "nanoid"
7
20
  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"
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,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
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
143
180
  const StringIdArb = (): S.LazyArbitrary<StringId> => (fc) =>
144
181
  fc
145
182
  .uint8Array({ minLength: length, maxLength: length })
146
183
  .map((_) => customRandom(urlAlphabet, size, (size) => _.subarray(0, size))() as StringId)
147
184
  /**
148
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).
149
189
  */
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
- ),
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,
161
200
  (s) => ({
162
201
  make: makeStringId,
163
- 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)))
164
209
  })
165
210
  )
166
211
  .pipe(withDefaultMake)
167
212
 
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>() {
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>() {
173
222
  return <Prefix extends string, Separator extends string = "-">(
174
223
  prefix: Prefix,
175
224
  name: string,
@@ -177,27 +226,26 @@ export function prefixedStringId<Brand extends StringId>() {
177
226
  ) => {
178
227
  type FullPrefix = `${Prefix}${Separator}`
179
228
  const pref = `${prefix}${separator ?? "-"}` as FullPrefix
180
- const arb = (): S.LazyArbitrary<string & Brand> => (fc) =>
229
+ const arb = (): S.LazyArbitrary<Type> => (fc) =>
181
230
  StringIdArb()(fc).map(
182
- (x) => (pref + x.substring(0, 50 - pref.length)) as Brand
231
+ (x) => (pref + x.substring(0, 50 - pref.length)) as Type
183
232
  )
184
233
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
185
- const s: S.Codec<string & Brand, string> = StringId
234
+ const s = StringIdSchemaBase
186
235
  .pipe(
187
- S.refine((x: string): x is string & Brand => x.startsWith(pref), {
188
- identifier: name,
189
- title: name
236
+ S.refine((x: string): x is Type => x.startsWith(pref), {
237
+ identifier: name
190
238
  }),
191
239
  S.annotate({
192
240
  toArbitrary: () => (fc) => arb()(fc)
193
241
  })
194
- ) as S.Codec<string & Brand, string>
242
+ )
195
243
  const schema = s.pipe(withDefaultMake)
196
- 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
197
245
 
198
246
  return extendM(
199
247
  schema,
200
- (ex): PrefixedStringUtils<Brand, Prefix, Separator> => ({
248
+ (ex): PrefixedStringUtils<Type, Prefix, Separator> => ({
201
249
  make,
202
250
  /**
203
251
  * Automatically adds the prefix.
@@ -208,35 +256,60 @@ export function prefixedStringId<Brand extends StringId>() {
208
256
  */
209
257
  prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
210
258
  prefix,
211
- 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
+ )
212
270
  })
213
271
  )
214
272
  }
215
273
  }
216
274
 
217
- export const brandedStringId = <
218
- Brand extends StringIdBrand
219
- >() =>
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> =>
220
282
  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>>
283
+ Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema<Id>
225
284
  )
226
285
 
227
286
  export interface PrefixedStringUtils<
228
- Brand extends StringId,
287
+ Type extends StringId,
229
288
  Prefix extends string,
230
289
  Separator extends string
231
290
  > {
232
- readonly make: () => Brand
233
- readonly unsafeFrom: (str: string) => Brand
234
- 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
235
294
  readonly prefix: Prefix
236
- readonly withDefault: S.withConstructorDefault<S.Codec<Brand, string> & S.WithoutConstructorDefault>
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>
237
301
  }
238
302
 
239
- 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> {}
240
313
 
241
314
  export type Url = string & UrlBrand
242
315
 
@@ -244,12 +317,18 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
244
317
  return validator.default.isURL(s, { require_tld: false })
245
318
  }
246
319
 
247
- 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
248
324
  .String
249
325
  .pipe(
326
+ S.annotate({
327
+ title: "Url",
328
+ format: "uri"
329
+ }),
250
330
  S.refine(isUrl, {
251
331
  identifier: "Url",
252
- title: "Url",
253
332
  jsonSchema: { format: "uri" }
254
333
  }),
255
334
  S.annotate({
@@ -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"
14
+ import type * as SchemaAST from "effect/SchemaAST"
3
15
  import type { Simplify } from "effect/Types"
4
- import { fromBrand, nominal } from "./brand.js"
5
- import { withDefaultConstructor, withDefaultMake } from "./ext.js"
6
- import { type B } from "./schema.js"
16
+ import { type 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,9 +13,13 @@ 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
24
  jsonSchema: { format: "phone" }
21
25
  }),
@@ -1,17 +1,20 @@
1
1
  import type * as B from "effect/Brand"
2
2
  import * as S from "effect/Schema"
3
+ import type * as SchemaAST from "effect/SchemaAST"
3
4
  import type { Simplify } from "effect/Types"
4
- import { fromBrand, nominal } from "./brand.js"
5
- import { withDefaultMake } from "./ext.js"
5
+ import { type BrandedSchema, fromBrand, nominal } from "./brand.ts"
6
+ import { withDefaultMake } from "./ext.ts"
6
7
 
7
8
  export type NonEmptyStringBrand = B.Brand<"NonEmptyString">
8
9
  export type NonEmptyString = string & NonEmptyStringBrand
9
- export const NonEmptyString = S
10
+ export interface NonEmptyStringSchema extends BrandedSchema<S.NonEmptyString, NonEmptyString> {
11
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString
12
+ }
13
+ export const NonEmptyString: NonEmptyStringSchema = S
10
14
  .NonEmptyString
11
15
  .pipe(
12
- fromBrand(nominal<NonEmptyString>(), {
16
+ fromBrand<NonEmptyString>(nominal<NonEmptyString>(), {
13
17
  identifier: "NonEmptyString",
14
- title: "NonEmptyString",
15
18
  jsonSchema: {}
16
19
  }),
17
20
  withDefaultMake
@@ -19,13 +22,15 @@ export const NonEmptyString = S
19
22
 
20
23
  export interface NonEmptyString64kBrand extends Simplify<B.Brand<"NonEmptyString64k"> & NonEmptyStringBrand> {}
21
24
  export type NonEmptyString64k = string & NonEmptyString64kBrand
22
- export const NonEmptyString64k = S
25
+ export interface NonEmptyString64kSchema extends BrandedSchema<S.NonEmptyString, NonEmptyString64k> {
26
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString64k
27
+ }
28
+ export const NonEmptyString64k: NonEmptyString64kSchema = S
23
29
  .NonEmptyString
24
30
  .pipe(
25
31
  S.check(S.isMaxLength(64 * 1024)),
26
- fromBrand(nominal<NonEmptyString64k>(), {
32
+ fromBrand<NonEmptyString64k>(nominal<NonEmptyString64k>(), {
27
33
  identifier: "NonEmptyString64k",
28
- title: "NonEmptyString64k",
29
34
  jsonSchema: {}
30
35
  }),
31
36
  withDefaultMake
@@ -33,13 +38,15 @@ export const NonEmptyString64k = S
33
38
 
34
39
  export interface NonEmptyString2kBrand extends Simplify<B.Brand<"NonEmptyString2k"> & NonEmptyString64kBrand> {}
35
40
  export type NonEmptyString2k = string & NonEmptyString2kBrand
36
- export const NonEmptyString2k = S
41
+ export interface NonEmptyString2kSchema extends BrandedSchema<S.NonEmptyString, NonEmptyString2k> {
42
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString2k
43
+ }
44
+ export const NonEmptyString2k: NonEmptyString2kSchema = S
37
45
  .NonEmptyString
38
46
  .pipe(
39
47
  S.check(S.isMaxLength(2 * 1024)),
40
- fromBrand(nominal<NonEmptyString2k>(), {
48
+ fromBrand<NonEmptyString2k>(nominal<NonEmptyString2k>(), {
41
49
  identifier: "NonEmptyString2k",
42
- title: "NonEmptyString2k",
43
50
  jsonSchema: {}
44
51
  }),
45
52
  withDefaultMake
@@ -47,13 +54,15 @@ export const NonEmptyString2k = S
47
54
 
48
55
  export interface NonEmptyString255Brand extends Simplify<B.Brand<"NonEmptyString255"> & NonEmptyString2kBrand> {}
49
56
  export type NonEmptyString255 = string & NonEmptyString255Brand
50
- export const NonEmptyString255 = S
57
+ export interface NonEmptyString255Schema extends BrandedSchema<S.NonEmptyString, NonEmptyString255> {
58
+ (i: string, options?: SchemaAST.ParseOptions): NonEmptyString255
59
+ }
60
+ export const NonEmptyString255: NonEmptyString255Schema = S
51
61
  .NonEmptyString
52
62
  .pipe(
53
63
  S.check(S.isMaxLength(255)),
54
- fromBrand(nominal<NonEmptyString255>(), {
64
+ fromBrand<NonEmptyString255>(nominal<NonEmptyString255>(), {
55
65
  identifier: "NonEmptyString255",
56
- title: "NonEmptyString255",
57
66
  jsonSchema: {}
58
67
  }),
59
68
  withDefaultMake