effect-app 4.0.0-beta.22 → 4.0.0-beta.220
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.
- package/CHANGELOG.md +986 -0
- package/dist/Array.d.ts +1 -1
- package/dist/Chunk.d.ts +1 -1
- package/dist/Chunk.d.ts.map +1 -1
- package/dist/Config/SecretURL.d.ts +1 -1
- package/dist/Config/SecretURL.d.ts.map +1 -1
- package/dist/Config/SecretURL.js +2 -2
- package/dist/Config/internal/configSecretURL.d.ts +1 -1
- package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
- package/dist/Config.d.ts +7 -0
- package/dist/Config.d.ts.map +1 -0
- package/dist/Config.js +6 -0
- package/dist/ConfigProvider.d.ts +39 -0
- package/dist/ConfigProvider.d.ts.map +1 -0
- package/dist/ConfigProvider.js +42 -0
- package/dist/Context.d.ts +40 -0
- package/dist/Context.d.ts.map +1 -0
- package/dist/Context.js +67 -0
- package/dist/Effect.d.ts +9 -10
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +3 -6
- package/dist/Function.d.ts +1 -1
- package/dist/Function.d.ts.map +1 -1
- package/dist/Inputify.type.d.ts +1 -1
- package/dist/Layer.d.ts +7 -6
- package/dist/Layer.d.ts.map +1 -1
- package/dist/Layer.js +1 -1
- package/dist/NonEmptySet.d.ts +1 -1
- package/dist/NonEmptySet.d.ts.map +1 -1
- package/dist/Option.d.ts +1 -1
- package/dist/Option.d.ts.map +1 -1
- package/dist/Pure.d.ts +5 -5
- package/dist/Pure.d.ts.map +1 -1
- package/dist/Pure.js +13 -13
- package/dist/Schema/Class.d.ts +66 -20
- package/dist/Schema/Class.d.ts.map +1 -1
- package/dist/Schema/Class.js +189 -22
- package/dist/Schema/FastCheck.d.ts +1 -1
- package/dist/Schema/FastCheck.d.ts.map +1 -1
- package/dist/Schema/Methods.d.ts +1 -1
- package/dist/Schema/SchemaParser.d.ts +5 -0
- package/dist/Schema/SchemaParser.d.ts.map +1 -0
- package/dist/Schema/SchemaParser.js +6 -0
- package/dist/Schema/SpecialJsonSchema.d.ts +33 -0
- package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
- package/dist/Schema/SpecialJsonSchema.js +122 -0
- package/dist/Schema/SpecialOpenApi.d.ts +32 -0
- package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
- package/dist/Schema/SpecialOpenApi.js +123 -0
- package/dist/Schema/brand.d.ts +4 -2
- package/dist/Schema/brand.d.ts.map +1 -1
- package/dist/Schema/brand.js +1 -1
- package/dist/Schema/email.d.ts +1 -1
- package/dist/Schema/email.d.ts.map +1 -1
- package/dist/Schema/email.js +7 -4
- package/dist/Schema/ext.d.ts +367 -56
- package/dist/Schema/ext.d.ts.map +1 -1
- package/dist/Schema/ext.js +345 -53
- package/dist/Schema/moreStrings.d.ts +108 -26
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +54 -16
- package/dist/Schema/numbers.d.ts +55 -15
- package/dist/Schema/numbers.d.ts.map +1 -1
- package/dist/Schema/numbers.js +60 -12
- package/dist/Schema/phoneNumber.d.ts +1 -1
- package/dist/Schema/phoneNumber.d.ts.map +1 -1
- package/dist/Schema/phoneNumber.js +6 -3
- package/dist/Schema/schema.d.ts +1 -1
- package/dist/Schema/strings.d.ts +5 -5
- package/dist/Schema/strings.d.ts.map +1 -1
- package/dist/Schema/strings.js +1 -5
- package/dist/Schema.d.ts +217 -15
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +221 -16
- package/dist/Set.d.ts +1 -1
- package/dist/Set.d.ts.map +1 -1
- package/dist/TypeTest.d.ts +1 -1
- package/dist/Types.d.ts +1 -1
- package/dist/Widen.type.d.ts +1 -1
- package/dist/_ext/Array.d.ts +1 -1
- package/dist/_ext/Array.d.ts.map +1 -1
- package/dist/_ext/date.d.ts +1 -1
- package/dist/_ext/misc.d.ts +1 -1
- package/dist/_ext/ord.ext.d.ts +1 -1
- package/dist/_ext/ord.ext.d.ts.map +1 -1
- package/dist/builtin.d.ts +1 -1
- package/dist/builtin.d.ts.map +1 -1
- package/dist/client/InvalidationKeys.d.ts +29 -0
- package/dist/client/InvalidationKeys.d.ts.map +1 -0
- package/dist/client/InvalidationKeys.js +33 -0
- package/dist/client/apiClientFactory.d.ts +20 -32
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +96 -33
- package/dist/client/clientFor.d.ts +51 -17
- package/dist/client/clientFor.d.ts.map +1 -1
- package/dist/client/clientFor.js +9 -1
- package/dist/client/errors.d.ts +49 -25
- package/dist/client/errors.d.ts.map +1 -1
- package/dist/client/errors.js +43 -17
- package/dist/client/makeClient.d.ts +481 -33
- package/dist/client/makeClient.d.ts.map +1 -1
- package/dist/client/makeClient.js +66 -24
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/faker.d.ts +1 -1
- package/dist/faker.d.ts.map +1 -1
- package/dist/http/Request.d.ts +2 -2
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/internal/lib.d.ts +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/ids.d.ts +40 -12
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +25 -3
- package/dist/index.d.ts +5 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -8
- package/dist/logger.d.ts +1 -1
- package/dist/middleware.d.ts +14 -8
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +14 -8
- package/dist/rpc/Invalidation.d.ts +402 -0
- package/dist/rpc/Invalidation.d.ts.map +1 -0
- package/dist/rpc/Invalidation.js +150 -0
- package/dist/rpc/MiddlewareMaker.d.ts +5 -4
- package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
- package/dist/rpc/MiddlewareMaker.js +57 -37
- package/dist/rpc/RpcContextMap.d.ts +3 -3
- package/dist/rpc/RpcContextMap.d.ts.map +1 -1
- package/dist/rpc/RpcContextMap.js +4 -4
- package/dist/rpc/RpcMiddleware.d.ts +5 -4
- package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
- package/dist/rpc/RpcMiddleware.js +1 -1
- package/dist/rpc.d.ts +2 -2
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -2
- package/dist/transform.d.ts +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +3 -3
- package/dist/utils/effectify.d.ts +1 -1
- package/dist/utils/extend.d.ts +1 -1
- package/dist/utils/extend.d.ts.map +1 -1
- package/dist/utils/gen.d.ts +2 -2
- package/dist/utils/gen.d.ts.map +1 -1
- package/dist/utils/logLevel.d.ts +2 -2
- package/dist/utils/logLevel.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +3 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +3 -3
- package/dist/utils.d.ts +31 -38
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +12 -25
- package/dist/validation/validators.d.ts +1 -1
- package/dist/validation/validators.d.ts.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/package.json +46 -24
- package/src/Config/SecretURL.ts +2 -1
- package/src/Config.ts +14 -0
- package/src/ConfigProvider.ts +48 -0
- package/src/{ServiceMap.ts → Context.ts} +52 -59
- package/src/Effect.ts +12 -14
- package/src/Layer.ts +6 -5
- package/src/Pure.ts +17 -18
- package/src/Schema/Class.ts +270 -64
- package/src/Schema/SchemaParser.ts +12 -0
- package/src/Schema/SpecialJsonSchema.ts +137 -0
- package/src/Schema/SpecialOpenApi.ts +130 -0
- package/src/Schema/brand.ts +21 -1
- package/src/Schema/email.ts +7 -2
- package/src/Schema/ext.ts +425 -88
- package/src/Schema/moreStrings.ts +92 -37
- package/src/Schema/numbers.ts +64 -16
- package/src/Schema/phoneNumber.ts +5 -1
- package/src/Schema/strings.ts +4 -8
- package/src/Schema.ts +410 -20
- package/src/client/InvalidationKeys.ts +50 -0
- package/src/client/apiClientFactory.ts +224 -130
- package/src/client/clientFor.ts +95 -29
- package/src/client/errors.ts +52 -26
- package/src/client/makeClient.ts +572 -71
- package/src/client.ts +1 -0
- package/src/ids.ts +25 -3
- package/src/index.ts +5 -10
- package/src/middleware.ts +13 -9
- package/src/rpc/Invalidation.ts +226 -0
- package/src/rpc/MiddlewareMaker.ts +65 -60
- package/src/rpc/README.md +2 -2
- package/src/rpc/RpcContextMap.ts +6 -5
- package/src/rpc/RpcMiddleware.ts +5 -4
- package/src/rpc.ts +1 -1
- package/src/transform.ts +2 -2
- package/src/utils/gen.ts +1 -1
- package/src/utils/logger.ts +2 -2
- package/src/utils.ts +50 -132
- package/test/dist/rpc.test.d.ts.map +1 -1
- package/test/dist/secretURL.test.d.ts.map +1 -0
- package/test/dist/special.test.d.ts.map +1 -0
- package/test/dist/stream-error.types.d.ts +2 -0
- package/test/dist/stream-error.types.d.ts.map +1 -0
- package/test/dist/stream-error.types.js +27 -0
- package/test/rpc.test.ts +45 -6
- package/test/schema.test.ts +583 -9
- package/test/secretURL.test.ts +157 -0
- package/test/special.test.ts +1023 -0
- package/test/utils.test.ts +6 -6
- package/tsconfig.base.json +3 -4
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +29 -29
- package/tsconfig.test.json +2 -2
- package/dist/Operations.d.ts +0 -123
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -29
- package/dist/ServiceMap.d.ts +0 -44
- package/dist/ServiceMap.d.ts.map +0 -1
- package/dist/ServiceMap.js +0 -91
- package/eslint.config.mjs +0 -26
- package/src/Operations.ts +0 -55
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
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
|
+
*/
|
|
11
|
+
import { Effect, pipe } from "effect"
|
|
2
12
|
import type { Refinement } from "effect-app/Function"
|
|
3
13
|
import { extendM } from "effect-app/utils"
|
|
4
14
|
import * as S from "effect/Schema"
|
|
@@ -6,7 +16,7 @@ import type { Simplify } from "effect/Types"
|
|
|
6
16
|
import { customRandom, nanoid, urlAlphabet } from "nanoid"
|
|
7
17
|
import validator from "validator"
|
|
8
18
|
import { fromBrand, nominal } from "./brand.js"
|
|
9
|
-
import {
|
|
19
|
+
import { withDefaultMake, type WithDefaults } from "./ext.js"
|
|
10
20
|
import { type B } from "./schema.js"
|
|
11
21
|
import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.js"
|
|
12
22
|
|
|
@@ -27,9 +37,8 @@ export type NonEmptyString50 = string & NonEmptyString50Brand
|
|
|
27
37
|
*/
|
|
28
38
|
export const NonEmptyString50 = nonEmptyString.pipe(
|
|
29
39
|
S.check(S.isMaxLength(50)),
|
|
30
|
-
fromBrand(nominal<NonEmptyString50>(), {
|
|
40
|
+
fromBrand<NonEmptyString50>(nominal<NonEmptyString50>(), {
|
|
31
41
|
identifier: "NonEmptyString50",
|
|
32
|
-
title: "NonEmptyString50",
|
|
33
42
|
jsonSchema: {}
|
|
34
43
|
}),
|
|
35
44
|
withDefaultMake
|
|
@@ -50,9 +59,8 @@ export type NonEmptyString64 = string & NonEmptyString64Brand
|
|
|
50
59
|
*/
|
|
51
60
|
export const NonEmptyString64 = nonEmptyString.pipe(
|
|
52
61
|
S.check(S.isMaxLength(64)),
|
|
53
|
-
fromBrand(nominal<NonEmptyString64>(), {
|
|
62
|
+
fromBrand<NonEmptyString64>(nominal<NonEmptyString64>(), {
|
|
54
63
|
identifier: "NonEmptyString64",
|
|
55
|
-
title: "NonEmptyString64",
|
|
56
64
|
jsonSchema: {}
|
|
57
65
|
}),
|
|
58
66
|
withDefaultMake
|
|
@@ -74,9 +82,8 @@ export type NonEmptyString80 = string & NonEmptyString80Brand
|
|
|
74
82
|
|
|
75
83
|
export const NonEmptyString80 = nonEmptyString.pipe(
|
|
76
84
|
S.check(S.isMaxLength(80)),
|
|
77
|
-
fromBrand(nominal<NonEmptyString80>(), {
|
|
85
|
+
fromBrand<NonEmptyString80>(nominal<NonEmptyString80>(), {
|
|
78
86
|
identifier: "NonEmptyString80",
|
|
79
|
-
title: "NonEmptyString80",
|
|
80
87
|
jsonSchema: {}
|
|
81
88
|
}),
|
|
82
89
|
withDefaultMake
|
|
@@ -97,9 +104,8 @@ export type NonEmptyString100 = string & NonEmptyString100Brand
|
|
|
97
104
|
*/
|
|
98
105
|
export const NonEmptyString100 = nonEmptyString.pipe(
|
|
99
106
|
S.check(S.isMaxLength(100)),
|
|
100
|
-
fromBrand(nominal<NonEmptyString100>(), {
|
|
107
|
+
fromBrand<NonEmptyString100>(nominal<NonEmptyString100>(), {
|
|
101
108
|
identifier: "NonEmptyString100",
|
|
102
|
-
title: "NonEmptyString100",
|
|
103
109
|
jsonSchema: {}
|
|
104
110
|
}),
|
|
105
111
|
withDefaultMake
|
|
@@ -121,7 +127,10 @@ export type Min3String255 = string & Min3String255Brand
|
|
|
121
127
|
export const Min3String255 = pipe(
|
|
122
128
|
S.String,
|
|
123
129
|
S.check(S.isMinLength(3), S.isMaxLength(255)),
|
|
124
|
-
fromBrand(nominal<Min3String255>(), {
|
|
130
|
+
fromBrand<Min3String255>(nominal<Min3String255>(), {
|
|
131
|
+
identifier: "Min3String255",
|
|
132
|
+
jsonSchema: {}
|
|
133
|
+
}),
|
|
125
134
|
withDefaultMake
|
|
126
135
|
)
|
|
127
136
|
|
|
@@ -135,7 +144,8 @@ export interface StringIdBrand extends Simplify<B.Brand<"StringId"> & NonEmptySt
|
|
|
135
144
|
*/
|
|
136
145
|
export type StringId = string & StringIdBrand
|
|
137
146
|
|
|
138
|
-
const makeStringId = (): StringId =>
|
|
147
|
+
const makeStringId = (s?: string): StringId =>
|
|
148
|
+
s !== undefined ? S.decodeSync(StringId)(s) : nanoid() as unknown as StringId
|
|
139
149
|
const minLength = 6
|
|
140
150
|
const maxLength = 50
|
|
141
151
|
const size = 21
|
|
@@ -146,21 +156,29 @@ const StringIdArb = (): S.LazyArbitrary<StringId> => (fc) =>
|
|
|
146
156
|
.map((_) => customRandom(urlAlphabet, size, (size) => _.subarray(0, size))() as StringId)
|
|
147
157
|
/**
|
|
148
158
|
* A string that is at least 6 characters long and a maximum of 50.
|
|
159
|
+
*
|
|
160
|
+
* `.withConstructorDefault` => fresh `nanoid()` (construction-only; not
|
|
161
|
+
* applied during decode — see file-level note).
|
|
149
162
|
*/
|
|
150
163
|
export const StringId = extendM(
|
|
151
164
|
pipe(
|
|
152
165
|
S.String,
|
|
153
166
|
S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
|
|
154
|
-
fromBrand(nominal<StringId>(), {
|
|
167
|
+
fromBrand<StringId>(nominal<StringId>(), {
|
|
155
168
|
identifier: "StringId",
|
|
156
|
-
title: "StringId",
|
|
157
169
|
toArbitrary: () => (fc) => StringIdArb()(fc),
|
|
158
170
|
jsonSchema: {}
|
|
159
171
|
})
|
|
160
172
|
),
|
|
161
173
|
(s) => ({
|
|
162
174
|
make: makeStringId,
|
|
163
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Construction-only default: fresh `nanoid()`-shaped `StringId`. Applied
|
|
177
|
+
* only when the field is omitted from `.make(...)` input. NOT applied
|
|
178
|
+
* during decode — cannot be used to JIT-migrate database fields. See
|
|
179
|
+
* file-level note.
|
|
180
|
+
*/
|
|
181
|
+
withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(makeStringId)))
|
|
164
182
|
})
|
|
165
183
|
)
|
|
166
184
|
.pipe(withDefaultMake)
|
|
@@ -169,7 +187,15 @@ export const StringId = extendM(
|
|
|
169
187
|
|
|
170
188
|
// const prefixedStringIdUnsafeThunk = (prefix: string) => () => prefixedStringIdUnsafe(prefix)
|
|
171
189
|
|
|
172
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Build a `StringId` schema whose values are required to start with a fixed
|
|
192
|
+
* `prefix` (joined with `separator`, default `-`).
|
|
193
|
+
*
|
|
194
|
+
* The returned schema exposes `.withConstructorDefault` that mints a fresh
|
|
195
|
+
* prefixed id. Construction-only — not applied during decode; see file-level
|
|
196
|
+
* note.
|
|
197
|
+
*/
|
|
198
|
+
export function prefixedStringId<Type extends StringId>() {
|
|
173
199
|
return <Prefix extends string, Separator extends string = "-">(
|
|
174
200
|
prefix: Prefix,
|
|
175
201
|
name: string,
|
|
@@ -177,27 +203,26 @@ export function prefixedStringId<Brand extends StringId>() {
|
|
|
177
203
|
) => {
|
|
178
204
|
type FullPrefix = `${Prefix}${Separator}`
|
|
179
205
|
const pref = `${prefix}${separator ?? "-"}` as FullPrefix
|
|
180
|
-
const arb = (): S.LazyArbitrary<
|
|
206
|
+
const arb = (): S.LazyArbitrary<Type> => (fc) =>
|
|
181
207
|
StringIdArb()(fc).map(
|
|
182
|
-
(x) => (pref + x.substring(0, 50 - pref.length)) as
|
|
208
|
+
(x) => (pref + x.substring(0, 50 - pref.length)) as Type
|
|
183
209
|
)
|
|
184
210
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
185
|
-
const s
|
|
211
|
+
const s = StringId
|
|
186
212
|
.pipe(
|
|
187
|
-
S.refine((x: string): x is
|
|
188
|
-
identifier: name
|
|
189
|
-
title: name
|
|
213
|
+
S.refine((x: string): x is Type => x.startsWith(pref), {
|
|
214
|
+
identifier: name
|
|
190
215
|
}),
|
|
191
216
|
S.annotate({
|
|
192
217
|
toArbitrary: () => (fc) => arb()(fc)
|
|
193
218
|
})
|
|
194
|
-
)
|
|
219
|
+
)
|
|
195
220
|
const schema = s.pipe(withDefaultMake)
|
|
196
|
-
const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as
|
|
221
|
+
const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Type
|
|
197
222
|
|
|
198
223
|
return extendM(
|
|
199
224
|
schema,
|
|
200
|
-
(ex): PrefixedStringUtils<
|
|
225
|
+
(ex): PrefixedStringUtils<Type, Prefix, Separator> => ({
|
|
201
226
|
make,
|
|
202
227
|
/**
|
|
203
228
|
* Automatically adds the prefix.
|
|
@@ -208,32 +233,59 @@ export function prefixedStringId<Brand extends StringId>() {
|
|
|
208
233
|
*/
|
|
209
234
|
prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
|
|
210
235
|
prefix,
|
|
211
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Construction-only default: fresh prefixed id. Applied only when
|
|
238
|
+
* the field is omitted from `.make(...)` input. NOT applied during
|
|
239
|
+
* decode — cannot be used to JIT-migrate database fields. See
|
|
240
|
+
* file-level note.
|
|
241
|
+
*/
|
|
242
|
+
withConstructorDefault: schema.pipe(
|
|
243
|
+
S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>(
|
|
244
|
+
Effect.sync(make)
|
|
245
|
+
)
|
|
246
|
+
)
|
|
212
247
|
})
|
|
213
248
|
)
|
|
214
249
|
}
|
|
215
250
|
}
|
|
216
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Build a branded `StringId` schema for the given branded `Id` type.
|
|
254
|
+
*
|
|
255
|
+
* Exposes `.withConstructorDefault` that mints a fresh `nanoid()`-shaped id.
|
|
256
|
+
* Construction-only — not applied during decode; see file-level note.
|
|
257
|
+
*/
|
|
217
258
|
export const brandedStringId = <
|
|
218
|
-
|
|
259
|
+
Id
|
|
219
260
|
>() =>
|
|
220
261
|
withDefaultMake(
|
|
221
|
-
Object.assign(Object.create(StringId), StringId) as S.Codec<
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
262
|
+
Object.assign(Object.create(StringId), StringId) as S.Codec<Id, string> & {
|
|
263
|
+
/**
|
|
264
|
+
* Construction-only default: fresh `nanoid()`-shaped id. Applied only
|
|
265
|
+
* when the field is omitted from `.make(...)` input. NOT applied
|
|
266
|
+
* during decode — cannot be used to JIT-migrate database fields. See
|
|
267
|
+
* file-level note.
|
|
268
|
+
*/
|
|
269
|
+
withConstructorDefault: S.withConstructorDefault<S.Codec<Id, string> & S.WithoutConstructorDefault>
|
|
270
|
+
make: () => Id
|
|
271
|
+
} & WithDefaults<S.Codec<Id, string>>
|
|
225
272
|
)
|
|
226
273
|
|
|
227
274
|
export interface PrefixedStringUtils<
|
|
228
|
-
|
|
275
|
+
Type extends StringId,
|
|
229
276
|
Prefix extends string,
|
|
230
277
|
Separator extends string
|
|
231
278
|
> {
|
|
232
|
-
readonly make: () =>
|
|
233
|
-
readonly unsafeFrom: (str: string) =>
|
|
234
|
-
prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) =>
|
|
279
|
+
readonly make: () => Type
|
|
280
|
+
readonly unsafeFrom: (str: string) => Type
|
|
281
|
+
prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Type
|
|
235
282
|
readonly prefix: Prefix
|
|
236
|
-
|
|
283
|
+
/**
|
|
284
|
+
* Construction-only default: fresh prefixed id. Applied only when the
|
|
285
|
+
* field is omitted from `.make(...)` input. NOT applied during decode —
|
|
286
|
+
* cannot be used to JIT-migrate database fields. See file-level note.
|
|
287
|
+
*/
|
|
288
|
+
readonly withConstructorDefault: S.withConstructorDefault<S.Codec<Type, string> & S.WithoutConstructorDefault>
|
|
237
289
|
}
|
|
238
290
|
|
|
239
291
|
export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
|
|
@@ -247,9 +299,12 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
|
|
|
247
299
|
export const Url = S
|
|
248
300
|
.String
|
|
249
301
|
.pipe(
|
|
302
|
+
S.annotate({
|
|
303
|
+
title: "Url",
|
|
304
|
+
format: "uri"
|
|
305
|
+
}),
|
|
250
306
|
S.refine(isUrl, {
|
|
251
307
|
identifier: "Url",
|
|
252
|
-
title: "Url",
|
|
253
308
|
jsonSchema: { format: "uri" }
|
|
254
309
|
}),
|
|
255
310
|
S.annotate({
|
package/src/Schema/numbers.ts
CHANGED
|
@@ -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
|
+
*/
|
|
11
|
+
import { Effect } from "effect"
|
|
1
12
|
import { extendM } from "effect-app/utils"
|
|
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 {
|
|
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",
|
|
26
|
+
fromBrand<PositiveInt>(nominal<PositiveInt>(), { identifier: "PositiveInt", jsonSchema: {} }),
|
|
15
27
|
withDefaultMake
|
|
16
28
|
),
|
|
17
|
-
(s) => ({
|
|
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) => ({
|
|
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",
|
|
39
|
-
(s) => ({
|
|
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.
|
|
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) => ({
|
|
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
|
-
.
|
|
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) => ({
|
|
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
|
}),
|
package/src/Schema/strings.ts
CHANGED
|
@@ -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
|