effect-app 4.0.0-beta.25 → 4.0.0-beta.250

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