effect-app 4.0.0-beta.253 → 4.0.0-beta.255
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 +16 -0
- package/dist/Model/Repository/internal/internal.d.ts +1 -1
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +32 -6
- package/dist/Model/Repository/service.d.ts +18 -7
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Schema/moreStrings.d.ts +35 -83
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +10 -29
- package/dist/Schema/numbers.d.ts +24 -57
- package/dist/Schema/numbers.d.ts.map +1 -1
- package/dist/Schema/numbers.js +1 -6
- package/dist/Schema/strings.d.ts +16 -5
- package/dist/Schema/strings.d.ts.map +1 -1
- package/dist/Schema/strings.js +1 -1
- package/dist/ids.d.ts +2 -8
- package/dist/ids.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/Model/Repository/internal/internal.ts +42 -15
- package/src/Model/Repository/service.ts +17 -6
- package/src/Schema/moreStrings.ts +43 -32
- package/src/Schema/numbers.ts +16 -6
- package/src/Schema/strings.ts +11 -5
package/dist/ids.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,KAAK,EAAE,iBAAiB,EAAY,KAAK,aAAa,EAAmB,MAAM,mBAAmB,CAAA;AACjI,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAA;AAEjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,CAAC,MAAM,aAAa,CAAA;AAGhC,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,MAAM,CAAA;CAClC;AAED,MAAM,MAAM,SAAS,GAAG,iBAAiB,CAAA;AACzC;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS;gBAIkB,iBAAiB;IAGnD;;;;;OAKG;;;;IALH;;;;;OAKG;;CAKe,CAAA;AAExB,MAAM,WAAW,kBAAmB,SAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC;CAAG;AACjG,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,kBAAkB,CAAA;AACvD;;;;;GAKG;AACH,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,KAAK,EAAE,iBAAiB,EAAY,KAAK,aAAa,EAAmB,MAAM,mBAAmB,CAAA;AACjI,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAA;AAEjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,CAAC,MAAM,aAAa,CAAA;AAGhC,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,MAAM,CAAA;CAClC;AAED,MAAM,MAAM,SAAS,GAAG,iBAAiB,CAAA;AACzC;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS;gBAIkB,iBAAiB;IAGnD;;;;;OAKG;;;;IALH;;;;;OAKG;;CAKe,CAAA;AAExB,MAAM,WAAW,kBAAmB,SAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC;CAAG;AACjG,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,kBAAkB,CAAA;AACvD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,wCAAmC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-app",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.255",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"vitest": "^4.1.5"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"effect": "^4.0.0-beta.
|
|
27
|
+
"effect": "^4.0.0-beta.71"
|
|
28
28
|
},
|
|
29
29
|
"typesVersions": {
|
|
30
30
|
"*": {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Equivalence from "effect/Equivalence"
|
|
4
4
|
import { flow, pipe } from "effect/Function"
|
|
5
|
+
import * as HashMap from "effect/HashMap"
|
|
5
6
|
import * as HashSet from "effect/HashSet"
|
|
6
7
|
import * as Pipeable from "effect/Pipeable"
|
|
7
8
|
import * as Ref from "effect/Ref"
|
|
@@ -21,10 +22,10 @@ import * as Option from "../../../Option.js"
|
|
|
21
22
|
import * as S from "../../../Schema.js"
|
|
22
23
|
import { type Codec, NonNegativeInt } from "../../../Schema.js"
|
|
23
24
|
import { setupRequestContextFromCurrent } from "../../../setupRequest.ts"
|
|
24
|
-
import { type FilterArgs, getContextMap, type PersistenceModelType, type StoreConfig, StoreMaker } from "../../../Store.js"
|
|
25
|
+
import { type FilterArgs, getContextMap, type PersistenceModelType, type StoreConfig, storeId, StoreMaker } from "../../../Store.js"
|
|
25
26
|
import type { FieldValues } from "../../filter/types.js"
|
|
26
27
|
import * as Q from "../../query.js"
|
|
27
|
-
import type { ChangeFeed, Repository } from "../service.js"
|
|
28
|
+
import type { ChangeFeed, ChangeFeedEvent, Repository } from "../service.js"
|
|
28
29
|
import { ValidationError, ValidationResult } from "../validation.js"
|
|
29
30
|
|
|
30
31
|
const dedupe = Array.dedupeWith(Equivalence.String)
|
|
@@ -108,22 +109,48 @@ export function makeRepoInternal<
|
|
|
108
109
|
? args.publishEvents
|
|
109
110
|
: () => Effect.void
|
|
110
111
|
|
|
111
|
-
type
|
|
112
|
-
|
|
113
|
-
const
|
|
112
|
+
type ChangeFeedHandler = (evt: ChangeFeedEvent<T>) => Effect.Effect<void>
|
|
113
|
+
const changeFeedByNamespace = yield* Ref.make(HashMap.empty<string, HashSet.HashSet<ChangeFeedHandler>>())
|
|
114
|
+
const changeFeedWildcard = yield* Ref.make(HashSet.empty<ChangeFeedHandler>())
|
|
114
115
|
// clear all handlers when the repository's scope closes
|
|
115
|
-
yield* Effect.addFinalizer(() =>
|
|
116
|
+
yield* Effect.addFinalizer(() =>
|
|
117
|
+
Effect.all([
|
|
118
|
+
Ref.set(changeFeedByNamespace, HashMap.empty<string, HashSet.HashSet<ChangeFeedHandler>>()),
|
|
119
|
+
Ref.set(changeFeedWildcard, HashSet.empty<ChangeFeedHandler>())
|
|
120
|
+
], { discard: true })
|
|
121
|
+
)
|
|
116
122
|
const changeFeed: ChangeFeed<T> = {
|
|
117
|
-
publish: (
|
|
118
|
-
Effect.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
() =>
|
|
123
|
+
publish: ([items, op]) =>
|
|
124
|
+
Effect.gen(function*() {
|
|
125
|
+
const ns = yield* storeId
|
|
126
|
+
const evt: ChangeFeedEvent<T> = [items, op, ns]
|
|
127
|
+
const map = yield* Ref.get(changeFeedByNamespace)
|
|
128
|
+
const wild = yield* Ref.get(changeFeedWildcard)
|
|
129
|
+
const targeted = Option.getOrElse(HashMap.get(map, ns), () => HashSet.empty<ChangeFeedHandler>())
|
|
130
|
+
const all = HashSet.union(targeted, wild)
|
|
131
|
+
yield* Effect.forEach(all, (h) => h(evt), { concurrency: "unbounded", discard: true })
|
|
132
|
+
}),
|
|
133
|
+
subscribe: (handler, options) => {
|
|
134
|
+
const ns = options?.namespace
|
|
135
|
+
if (ns === undefined) {
|
|
136
|
+
return Effect.acquireRelease(
|
|
137
|
+
Ref.update(changeFeedWildcard, HashSet.add(handler)),
|
|
138
|
+
() => Ref.update(changeFeedWildcard, HashSet.remove(handler))
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
return Effect.acquireRelease(
|
|
142
|
+
Ref.update(changeFeedByNamespace, (m) => {
|
|
143
|
+
const cur = Option.getOrElse(HashMap.get(m, ns), () => HashSet.empty<ChangeFeedHandler>())
|
|
144
|
+
return HashMap.set(m, ns, HashSet.add(cur, handler))
|
|
145
|
+
}),
|
|
146
|
+
() =>
|
|
147
|
+
Ref.update(changeFeedByNamespace, (m) => {
|
|
148
|
+
const cur = Option.getOrElse(HashMap.get(m, ns), () => HashSet.empty<ChangeFeedHandler>())
|
|
149
|
+
const next = HashSet.remove(cur, handler)
|
|
150
|
+
return HashSet.size(next) === 0 ? HashMap.remove(m, ns) : HashMap.set(m, ns, next)
|
|
151
|
+
})
|
|
126
152
|
)
|
|
153
|
+
}
|
|
127
154
|
}
|
|
128
155
|
|
|
129
156
|
const allE = cms
|
|
@@ -10,19 +10,30 @@ import type { QAll, Query, QueryProjection, RawQuery } from "../query.js"
|
|
|
10
10
|
import type { Mapped } from "./legacy.js"
|
|
11
11
|
import type { ValidationResult } from "./validation.js"
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Event emitted by a repository's ChangeFeed.
|
|
15
|
+
*
|
|
16
|
+
* Tuple shape: `[items, op, namespace]` — `namespace` is the `storeId`
|
|
17
|
+
* context value at publish time (defaults to `"primary"`).
|
|
18
|
+
*/
|
|
19
|
+
export type ChangeFeedEvent<T> = readonly [items: T[], op: "save" | "remove", namespace: string]
|
|
20
|
+
|
|
13
21
|
/**
|
|
14
22
|
* Synchronous broadcast channel for repository change events.
|
|
15
23
|
*
|
|
16
|
-
* `publish` only completes after every
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
24
|
+
* `publish` only completes after every matching handler's Effect has
|
|
25
|
+
* finished — callers must await all handlers before continuing. Subscribers
|
|
26
|
+
* can target a single namespace via `options.namespace`, or omit it to
|
|
27
|
+
* receive events from every namespace (wildcard).
|
|
28
|
+
*
|
|
29
|
+
* Handlers are auto-removed when the subscriber's Scope closes; the full
|
|
30
|
+
* handler set is cleared when the repository's own scope closes.
|
|
21
31
|
*/
|
|
22
32
|
export interface ChangeFeed<T> {
|
|
23
33
|
readonly publish: (evt: [T[], "save" | "remove"]) => Effect.Effect<void>
|
|
24
34
|
readonly subscribe: (
|
|
25
|
-
handler: (evt:
|
|
35
|
+
handler: (evt: ChangeFeedEvent<T>) => Effect.Effect<void>,
|
|
36
|
+
options?: { readonly namespace?: string }
|
|
26
37
|
) => Effect.Effect<void, never, Scope.Scope>
|
|
27
38
|
}
|
|
28
39
|
|
|
@@ -21,6 +21,9 @@ import { withDefaultMake, type WithDefaults } from "./ext.js"
|
|
|
21
21
|
import { type B } from "./schema.js"
|
|
22
22
|
import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.js"
|
|
23
23
|
|
|
24
|
+
type BrandedStringSchema<A extends string> = S.Codec<A, string> & WithDefaults<S.Codec<A, string>>
|
|
25
|
+
type ConstructorDefaultBaseSchema<A> = S.Codec<A, string> & S.WithoutConstructorDefault
|
|
26
|
+
type WithConstructorDefaultSchema<A> = S.withConstructorDefault<ConstructorDefaultBaseSchema<A>>
|
|
24
27
|
const nonEmptyString = S.NonEmptyString
|
|
25
28
|
|
|
26
29
|
/**
|
|
@@ -36,7 +39,8 @@ export type NonEmptyString50 = string & NonEmptyString50Brand
|
|
|
36
39
|
/**
|
|
37
40
|
* A string that is at least 1 character long and a maximum of 50.
|
|
38
41
|
*/
|
|
39
|
-
export
|
|
42
|
+
export interface NonEmptyString50Schema extends BrandedStringSchema<NonEmptyString50> {}
|
|
43
|
+
export const NonEmptyString50: NonEmptyString50Schema = nonEmptyString.pipe(
|
|
40
44
|
S.check(S.isMaxLength(50)),
|
|
41
45
|
fromBrand<NonEmptyString50>(nominal<NonEmptyString50>(), {
|
|
42
46
|
identifier: "NonEmptyString50",
|
|
@@ -58,7 +62,8 @@ export type NonEmptyString64 = string & NonEmptyString64Brand
|
|
|
58
62
|
/**
|
|
59
63
|
* A string that is at least 1 character long and a maximum of 64.
|
|
60
64
|
*/
|
|
61
|
-
export
|
|
65
|
+
export interface NonEmptyString64Schema extends BrandedStringSchema<NonEmptyString64> {}
|
|
66
|
+
export const NonEmptyString64: NonEmptyString64Schema = nonEmptyString.pipe(
|
|
62
67
|
S.check(S.isMaxLength(64)),
|
|
63
68
|
fromBrand<NonEmptyString64>(nominal<NonEmptyString64>(), {
|
|
64
69
|
identifier: "NonEmptyString64",
|
|
@@ -81,7 +86,8 @@ export type NonEmptyString80 = string & NonEmptyString80Brand
|
|
|
81
86
|
* A string that is at least 1 character long and a maximum of 80.
|
|
82
87
|
*/
|
|
83
88
|
|
|
84
|
-
export
|
|
89
|
+
export interface NonEmptyString80Schema extends BrandedStringSchema<NonEmptyString80> {}
|
|
90
|
+
export const NonEmptyString80: NonEmptyString80Schema = nonEmptyString.pipe(
|
|
85
91
|
S.check(S.isMaxLength(80)),
|
|
86
92
|
fromBrand<NonEmptyString80>(nominal<NonEmptyString80>(), {
|
|
87
93
|
identifier: "NonEmptyString80",
|
|
@@ -103,7 +109,8 @@ export type NonEmptyString100 = string & NonEmptyString100Brand
|
|
|
103
109
|
/**
|
|
104
110
|
* A string that is at least 1 character long and a maximum of 100.
|
|
105
111
|
*/
|
|
106
|
-
export
|
|
112
|
+
export interface NonEmptyString100Schema extends BrandedStringSchema<NonEmptyString100> {}
|
|
113
|
+
export const NonEmptyString100: NonEmptyString100Schema = nonEmptyString.pipe(
|
|
107
114
|
S.check(S.isMaxLength(100)),
|
|
108
115
|
fromBrand<NonEmptyString100>(nominal<NonEmptyString100>(), {
|
|
109
116
|
identifier: "NonEmptyString100",
|
|
@@ -125,7 +132,8 @@ export type Min3String255 = string & Min3String255Brand
|
|
|
125
132
|
/**
|
|
126
133
|
* A string that is at least 3 character long and a maximum of 255.
|
|
127
134
|
*/
|
|
128
|
-
export
|
|
135
|
+
export interface Min3String255Schema extends BrandedStringSchema<Min3String255> {}
|
|
136
|
+
export const Min3String255: Min3String255Schema = pipe(
|
|
129
137
|
S.String,
|
|
130
138
|
S.check(S.isMinLength(3), S.isMaxLength(255)),
|
|
131
139
|
fromBrand<Min3String255>(nominal<Min3String255>(), {
|
|
@@ -145,12 +153,22 @@ export interface StringIdBrand extends Simplify<B.Brand<"StringId"> & NonEmptySt
|
|
|
145
153
|
*/
|
|
146
154
|
export type StringId = string & StringIdBrand
|
|
147
155
|
|
|
148
|
-
const makeStringId = (s?: string): StringId =>
|
|
149
|
-
s !== undefined ? S.decodeSync(StringId)(s) : nanoid() as unknown as StringId
|
|
150
156
|
const minLength = 6
|
|
151
157
|
const maxLength = 50
|
|
152
158
|
const size = 21
|
|
153
159
|
const length = 10 * size
|
|
160
|
+
/** Base `StringId` codec (without constructor default extensions). */
|
|
161
|
+
const StringIdSchemaBase = pipe(
|
|
162
|
+
S.String,
|
|
163
|
+
S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
|
|
164
|
+
fromBrand<StringId>(nominal<StringId>(), {
|
|
165
|
+
identifier: "StringId",
|
|
166
|
+
toArbitrary: () => (fc) => StringIdArb()(fc),
|
|
167
|
+
jsonSchema: {}
|
|
168
|
+
})
|
|
169
|
+
)
|
|
170
|
+
const makeStringId = (s?: string): StringId =>
|
|
171
|
+
s !== undefined ? S.decodeSync(StringIdSchemaBase)(s) : nanoid() as unknown as StringId
|
|
154
172
|
const StringIdArb = (): S.LazyArbitrary<StringId> => (fc) =>
|
|
155
173
|
fc
|
|
156
174
|
.uint8Array({ minLength: length, maxLength: length })
|
|
@@ -161,16 +179,12 @@ const StringIdArb = (): S.LazyArbitrary<StringId> => (fc) =>
|
|
|
161
179
|
* `.withConstructorDefault` => fresh `nanoid()` (construction-only; not
|
|
162
180
|
* applied during decode — see file-level note).
|
|
163
181
|
*/
|
|
164
|
-
export
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
toArbitrary: () => (fc) => StringIdArb()(fc),
|
|
171
|
-
jsonSchema: {}
|
|
172
|
-
})
|
|
173
|
-
),
|
|
182
|
+
export interface StringIdSchema extends BrandedStringSchema<StringId> {
|
|
183
|
+
readonly make: (s?: string) => StringId
|
|
184
|
+
readonly withConstructorDefault: WithConstructorDefaultSchema<StringId>
|
|
185
|
+
}
|
|
186
|
+
export const StringId: StringIdSchema = extendM(
|
|
187
|
+
StringIdSchemaBase,
|
|
174
188
|
(s) => ({
|
|
175
189
|
make: makeStringId,
|
|
176
190
|
/**
|
|
@@ -209,7 +223,7 @@ export function prefixedStringId<Type extends StringId>() {
|
|
|
209
223
|
(x) => (pref + x.substring(0, 50 - pref.length)) as Type
|
|
210
224
|
)
|
|
211
225
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
212
|
-
const s =
|
|
226
|
+
const s = StringIdSchemaBase
|
|
213
227
|
.pipe(
|
|
214
228
|
S.refine((x: string): x is Type => x.startsWith(pref), {
|
|
215
229
|
identifier: name
|
|
@@ -241,7 +255,7 @@ export function prefixedStringId<Type extends StringId>() {
|
|
|
241
255
|
* file-level note.
|
|
242
256
|
*/
|
|
243
257
|
withConstructorDefault: schema.pipe(
|
|
244
|
-
S.withConstructorDefault<
|
|
258
|
+
S.withConstructorDefault<ConstructorDefaultBaseSchema<Type>>(
|
|
245
259
|
Effect.sync(make)
|
|
246
260
|
)
|
|
247
261
|
)
|
|
@@ -258,18 +272,9 @@ export function prefixedStringId<Type extends StringId>() {
|
|
|
258
272
|
*/
|
|
259
273
|
export const brandedStringId = <
|
|
260
274
|
Id
|
|
261
|
-
>() =>
|
|
275
|
+
>(): BrandedStringIdSchema<Id> =>
|
|
262
276
|
withDefaultMake(
|
|
263
|
-
Object.assign(Object.create(StringId), StringId) as
|
|
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>>
|
|
277
|
+
Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema<Id>
|
|
273
278
|
)
|
|
274
279
|
|
|
275
280
|
export interface PrefixedStringUtils<
|
|
@@ -286,7 +291,12 @@ export interface PrefixedStringUtils<
|
|
|
286
291
|
* field is omitted from `.make(...)` input. NOT applied during decode —
|
|
287
292
|
* cannot be used to JIT-migrate database fields. See file-level note.
|
|
288
293
|
*/
|
|
289
|
-
readonly withConstructorDefault:
|
|
294
|
+
readonly withConstructorDefault: WithConstructorDefaultSchema<Type>
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface BrandedStringIdSchema<Id> extends S.Codec<Id, string>, WithDefaults<S.Codec<Id, string>> {
|
|
298
|
+
readonly withConstructorDefault: WithConstructorDefaultSchema<Id>
|
|
299
|
+
readonly make: () => Id
|
|
290
300
|
}
|
|
291
301
|
|
|
292
302
|
export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
|
|
@@ -297,7 +307,8 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
|
|
|
297
307
|
return validator.default.isURL(s, { require_tld: false })
|
|
298
308
|
}
|
|
299
309
|
|
|
300
|
-
export
|
|
310
|
+
export interface UrlSchema extends BrandedStringSchema<Url> {}
|
|
311
|
+
export const Url: UrlSchema = S
|
|
301
312
|
.String
|
|
302
313
|
.pipe(
|
|
303
314
|
S.annotate({
|
package/src/Schema/numbers.ts
CHANGED
|
@@ -13,14 +13,20 @@ import * as Effect from "effect/Effect"
|
|
|
13
13
|
import * as S from "effect/Schema"
|
|
14
14
|
import type { Simplify } from "effect/Types"
|
|
15
15
|
import { fromBrand, nominal } from "./brand.js"
|
|
16
|
-
import { withDefaultMake } from "./ext.js"
|
|
16
|
+
import { withDefaultMake, type WithDefaults } from "./ext.js"
|
|
17
17
|
import { type B } from "./schema.js"
|
|
18
18
|
|
|
19
|
+
type BrandedNumberSchema<A extends number> = S.Codec<A, number> & WithDefaults<S.Codec<A, number>>
|
|
20
|
+
type BrandedNumberSchemaWithConstructorDefault<A extends number> = BrandedNumberSchema<A> & {
|
|
21
|
+
readonly withConstructorDefault: S.Codec<A, number>
|
|
22
|
+
}
|
|
23
|
+
|
|
19
24
|
export interface PositiveIntBrand
|
|
20
25
|
extends Simplify<B.Brand<"PositiveInt"> & NonNegativeIntBrand & PositiveNumberBrand>
|
|
21
26
|
{}
|
|
22
27
|
/** Positive integer. `.withConstructorDefault` => `1` (construction-only). */
|
|
23
|
-
export
|
|
28
|
+
export interface PositiveIntSchema extends BrandedNumberSchemaWithConstructorDefault<PositiveInt> {}
|
|
29
|
+
export const PositiveInt: PositiveIntSchema = extendM(
|
|
24
30
|
S.Int.pipe(
|
|
25
31
|
S.check(S.isGreaterThan(0)),
|
|
26
32
|
fromBrand<PositiveInt>(nominal<PositiveInt>(), { identifier: "PositiveInt", jsonSchema: {} }),
|
|
@@ -39,7 +45,8 @@ export type PositiveInt = number & PositiveIntBrand
|
|
|
39
45
|
|
|
40
46
|
export interface NonNegativeIntBrand extends Simplify<B.Brand<"NonNegativeInt"> & IntBrand & NonNegativeNumberBrand> {}
|
|
41
47
|
/** Non-negative integer. `.withConstructorDefault` => `0` (construction-only). */
|
|
42
|
-
export
|
|
48
|
+
export interface NonNegativeIntSchema extends BrandedNumberSchemaWithConstructorDefault<NonNegativeInt> {}
|
|
49
|
+
export const NonNegativeInt: NonNegativeIntSchema = extendM(
|
|
43
50
|
S.Int.pipe(
|
|
44
51
|
S.check(S.isGreaterThanOrEqualTo(0)),
|
|
45
52
|
fromBrand<NonNegativeInt>(nominal<NonNegativeInt>(), {
|
|
@@ -61,7 +68,8 @@ export type NonNegativeInt = number & NonNegativeIntBrand
|
|
|
61
68
|
|
|
62
69
|
export interface IntBrand extends Simplify<B.Brand<"Int">> {}
|
|
63
70
|
/** Integer. `.withConstructorDefault` => `0` (construction-only). */
|
|
64
|
-
export
|
|
71
|
+
export interface IntSchema extends BrandedNumberSchemaWithConstructorDefault<Int> {}
|
|
72
|
+
export const Int: IntSchema = extendM(
|
|
65
73
|
S.Int.pipe(fromBrand<Int>(nominal<Int>(), { identifier: "Int", jsonSchema: {} }), withDefaultMake),
|
|
66
74
|
(s) => ({
|
|
67
75
|
/**
|
|
@@ -76,7 +84,8 @@ export type Int = number & IntBrand
|
|
|
76
84
|
|
|
77
85
|
export interface PositiveNumberBrand extends Simplify<B.Brand<"PositiveNumber"> & NonNegativeNumberBrand> {}
|
|
78
86
|
/** Positive finite number. `.withConstructorDefault` => `1` (construction-only). */
|
|
79
|
-
export
|
|
87
|
+
export interface PositiveNumberSchema extends BrandedNumberSchemaWithConstructorDefault<PositiveNumber> {}
|
|
88
|
+
export const PositiveNumber: PositiveNumberSchema = extendM(
|
|
80
89
|
S.Finite.pipe(
|
|
81
90
|
S.check(S.isGreaterThan(0)),
|
|
82
91
|
fromBrand<PositiveNumber>(nominal<PositiveNumber>(), {
|
|
@@ -98,7 +107,8 @@ export type PositiveNumber = number & PositiveNumberBrand
|
|
|
98
107
|
|
|
99
108
|
export interface NonNegativeNumberBrand extends Simplify<B.Brand<"NonNegativeNumber">> {}
|
|
100
109
|
/** Non-negative finite number. `.withConstructorDefault` => `0` (construction-only). */
|
|
101
|
-
export
|
|
110
|
+
export interface NonNegativeNumberSchema extends BrandedNumberSchemaWithConstructorDefault<NonNegativeNumber> {}
|
|
111
|
+
export const NonNegativeNumber: NonNegativeNumberSchema = extendM(
|
|
102
112
|
S
|
|
103
113
|
.Finite
|
|
104
114
|
.pipe(
|
package/src/Schema/strings.ts
CHANGED
|
@@ -2,11 +2,14 @@ import type * as B from "effect/Brand"
|
|
|
2
2
|
import * as S from "effect/Schema"
|
|
3
3
|
import type { Simplify } from "effect/Types"
|
|
4
4
|
import { fromBrand, nominal } from "./brand.js"
|
|
5
|
-
import { withDefaultMake } from "./ext.js"
|
|
5
|
+
import { withDefaultMake, type WithDefaults } from "./ext.js"
|
|
6
|
+
|
|
7
|
+
type BrandedStringSchema<A extends string> = S.Codec<A, string> & WithDefaults<S.Codec<A, string>>
|
|
6
8
|
|
|
7
9
|
export type NonEmptyStringBrand = B.Brand<"NonEmptyString">
|
|
8
10
|
export type NonEmptyString = string & NonEmptyStringBrand
|
|
9
|
-
export
|
|
11
|
+
export interface NonEmptyStringSchema extends BrandedStringSchema<NonEmptyString> {}
|
|
12
|
+
export const NonEmptyString: NonEmptyStringSchema = S
|
|
10
13
|
.NonEmptyString
|
|
11
14
|
.pipe(
|
|
12
15
|
fromBrand<NonEmptyString>(nominal<NonEmptyString>(), {
|
|
@@ -18,7 +21,8 @@ export const NonEmptyString = S
|
|
|
18
21
|
|
|
19
22
|
export interface NonEmptyString64kBrand extends Simplify<B.Brand<"NonEmptyString64k"> & NonEmptyStringBrand> {}
|
|
20
23
|
export type NonEmptyString64k = string & NonEmptyString64kBrand
|
|
21
|
-
export
|
|
24
|
+
export interface NonEmptyString64kSchema extends BrandedStringSchema<NonEmptyString64k> {}
|
|
25
|
+
export const NonEmptyString64k: NonEmptyString64kSchema = S
|
|
22
26
|
.NonEmptyString
|
|
23
27
|
.pipe(
|
|
24
28
|
S.check(S.isMaxLength(64 * 1024)),
|
|
@@ -31,7 +35,8 @@ export const NonEmptyString64k = S
|
|
|
31
35
|
|
|
32
36
|
export interface NonEmptyString2kBrand extends Simplify<B.Brand<"NonEmptyString2k"> & NonEmptyString64kBrand> {}
|
|
33
37
|
export type NonEmptyString2k = string & NonEmptyString2kBrand
|
|
34
|
-
export
|
|
38
|
+
export interface NonEmptyString2kSchema extends BrandedStringSchema<NonEmptyString2k> {}
|
|
39
|
+
export const NonEmptyString2k: NonEmptyString2kSchema = S
|
|
35
40
|
.NonEmptyString
|
|
36
41
|
.pipe(
|
|
37
42
|
S.check(S.isMaxLength(2 * 1024)),
|
|
@@ -44,7 +49,8 @@ export const NonEmptyString2k = S
|
|
|
44
49
|
|
|
45
50
|
export interface NonEmptyString255Brand extends Simplify<B.Brand<"NonEmptyString255"> & NonEmptyString2kBrand> {}
|
|
46
51
|
export type NonEmptyString255 = string & NonEmptyString255Brand
|
|
47
|
-
export
|
|
52
|
+
export interface NonEmptyString255Schema extends BrandedStringSchema<NonEmptyString255> {}
|
|
53
|
+
export const NonEmptyString255: NonEmptyString255Schema = S
|
|
48
54
|
.NonEmptyString
|
|
49
55
|
.pipe(
|
|
50
56
|
S.check(S.isMaxLength(255)),
|