shelving 1.130.1 → 1.132.0
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/api/Resource.js +2 -2
- package/db/ItemStore.js +2 -2
- package/db/Provider.js +5 -5
- package/db/QueryStore.js +3 -3
- package/db/ValidationProvider.js +3 -3
- package/error/ConflictError.d.ts +6 -0
- package/error/ConflictError.js +9 -0
- package/error/EnhancedError.d.ts +1 -0
- package/error/EnhancedError.js +1 -0
- package/error/ForbiddenError.d.ts +6 -0
- package/error/ForbiddenError.js +9 -0
- package/error/NotFoundError.d.ts +6 -0
- package/error/NotFoundError.js +9 -0
- package/error/{UnimplementedError.d.ts → NotImplementedError.d.ts} +2 -1
- package/error/{UnimplementedError.js → NotImplementedError.js} +3 -2
- package/error/UnauthorizedError.d.ts +6 -0
- package/error/UnauthorizedError.js +9 -0
- package/error/{ValueError.d.ts → ValidationError.d.ts} +2 -1
- package/error/{ValueError.js → ValidationError.js} +3 -2
- package/error/index.d.ts +6 -5
- package/error/index.js +6 -5
- package/firestore/lite/FirestoreLiteProvider.js +3 -3
- package/iterate/InspectIterator.js +4 -4
- package/package.json +1 -1
- package/react/createCacheContext.js +2 -2
- package/schema/ColorSchema.d.ts +3 -4
- package/schema/ColorSchema.js +2 -2
- package/schema/EmailSchema.d.ts +3 -3
- package/schema/EmailSchema.js +4 -5
- package/schema/KeySchema.d.ts +4 -1
- package/schema/KeySchema.js +9 -3
- package/schema/LinkSchema.d.ts +2 -2
- package/schema/LinkSchema.js +5 -5
- package/schema/NumberSchema.js +1 -1
- package/schema/PhoneSchema.d.ts +2 -2
- package/schema/PhoneSchema.js +2 -2
- package/schema/SlugSchema.d.ts +1 -1
- package/schema/SlugSchema.js +2 -3
- package/schema/StringSchema.d.ts +3 -32
- package/schema/StringSchema.js +4 -35
- package/schema/TextSchema.d.ts +40 -0
- package/schema/TextSchema.js +47 -0
- package/schema/index.d.ts +1 -0
- package/schema/index.js +1 -0
- package/sequence/InspectSequence.js +4 -4
- package/util/array.js +7 -7
- package/util/assert.js +3 -3
- package/util/async.js +4 -4
- package/util/boolean.js +6 -6
- package/util/class.js +2 -2
- package/util/color.js +3 -3
- package/util/data.js +3 -3
- package/util/date.js +3 -3
- package/util/dictionary.js +5 -5
- package/util/entity.js +2 -2
- package/util/file.js +2 -2
- package/util/function.js +2 -2
- package/util/hydrate.js +3 -3
- package/util/link.js +2 -2
- package/util/map.js +5 -5
- package/util/null.js +5 -5
- package/util/number.js +6 -6
- package/util/object.js +4 -4
- package/util/optional.js +2 -2
- package/util/path.js +2 -2
- package/util/regexp.js +4 -4
- package/util/sequence.js +2 -2
- package/util/serialise.js +2 -2
- package/util/set.js +3 -3
- package/util/source.js +2 -2
- package/util/string.d.ts +4 -4
- package/util/string.js +10 -10
- package/util/template.js +2 -2
- package/util/time.js +2 -2
- package/util/undefined.js +2 -2
- package/util/units.js +4 -4
- package/util/url.js +3 -3
- package/util/validate.js +2 -2
- package/error/PermissionError.d.ts +0 -5
- package/error/PermissionError.js +0 -8
- package/error/RequiredError.d.ts +0 -5
- package/error/RequiredError.js +0 -8
- package/error/StateError.d.ts +0 -5
- package/error/StateError.js +0 -8
package/api/Resource.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ValidationError } from "../error/ValidationError.js";
|
|
2
2
|
import { Feedback } from "../feedback/Feedback.js";
|
|
3
3
|
import { UNDEFINED_VALIDATOR } from "../util/validate.js";
|
|
4
4
|
/**
|
|
@@ -41,7 +41,7 @@ export class Resource {
|
|
|
41
41
|
}
|
|
42
42
|
catch (thrown) {
|
|
43
43
|
if (thrown instanceof Feedback)
|
|
44
|
-
throw new
|
|
44
|
+
throw new ValidationError("Invalid result for resource", thrown);
|
|
45
45
|
throw thrown;
|
|
46
46
|
}
|
|
47
47
|
}
|
package/db/ItemStore.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NotFoundError } from "../error/NotFoundError.js";
|
|
2
2
|
import { BooleanStore } from "../store/BooleanStore.js";
|
|
3
3
|
import { OptionalDataStore } from "../store/DataStore.js";
|
|
4
4
|
import { NONE } from "../util/constants.js";
|
|
@@ -14,7 +14,7 @@ export class ItemStore extends OptionalDataStore {
|
|
|
14
14
|
get data() {
|
|
15
15
|
const item = this.value;
|
|
16
16
|
if (!item)
|
|
17
|
-
throw new
|
|
17
|
+
throw new NotFoundError(`Item must exist in "${this.collection}"`, this.id);
|
|
18
18
|
return item;
|
|
19
19
|
}
|
|
20
20
|
/** Set the data of this store. */
|
package/db/Provider.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NotFoundError } from "../error/NotFoundError.js";
|
|
2
2
|
import { countArray, getOptionalFirstItem } from "../util/array.js";
|
|
3
3
|
/** Provider with a fully synchronous interface */
|
|
4
4
|
export class Provider {
|
|
5
5
|
requireItem(collection, id) {
|
|
6
6
|
const item = this.getItem(collection, id);
|
|
7
7
|
if (!item)
|
|
8
|
-
throw new
|
|
8
|
+
throw new NotFoundError(`Item must exist in "${collection}"`, id);
|
|
9
9
|
return item;
|
|
10
10
|
}
|
|
11
11
|
countQuery(collection, query) {
|
|
@@ -17,7 +17,7 @@ export class Provider {
|
|
|
17
17
|
requireFirst(collection, query) {
|
|
18
18
|
const first = this.getFirst(collection, query);
|
|
19
19
|
if (!first)
|
|
20
|
-
throw new
|
|
20
|
+
throw new NotFoundError(`First item must exist in "${collection}"`, query);
|
|
21
21
|
return first;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -26,7 +26,7 @@ export class AsyncProvider {
|
|
|
26
26
|
async requireItem(collection, id) {
|
|
27
27
|
const item = await this.getItem(collection, id);
|
|
28
28
|
if (!item)
|
|
29
|
-
throw new
|
|
29
|
+
throw new NotFoundError(`Item must exist in "${collection}"`, id);
|
|
30
30
|
return item;
|
|
31
31
|
}
|
|
32
32
|
async countQuery(collection, query) {
|
|
@@ -38,7 +38,7 @@ export class AsyncProvider {
|
|
|
38
38
|
async requireFirst(collection, query) {
|
|
39
39
|
const first = await this.getFirst(collection, query);
|
|
40
40
|
if (!first)
|
|
41
|
-
throw new
|
|
41
|
+
throw new NotFoundError(`First item must exist in "${collection}"`, query);
|
|
42
42
|
return first;
|
|
43
43
|
}
|
|
44
44
|
}
|
package/db/QueryStore.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { collection, query } from "firebase/firestore";
|
|
2
|
-
import {
|
|
2
|
+
import { NotFoundError } from "../error/NotFoundError.js";
|
|
3
3
|
import { ArrayStore } from "../store/ArrayStore.js";
|
|
4
4
|
import { BooleanStore } from "../store/BooleanStore.js";
|
|
5
5
|
import { NONE } from "../util/constants.js";
|
|
@@ -21,14 +21,14 @@ export class QueryStore extends ArrayStore {
|
|
|
21
21
|
get first() {
|
|
22
22
|
const first = this.optionalFirst;
|
|
23
23
|
if (!first)
|
|
24
|
-
throw new
|
|
24
|
+
throw new NotFoundError(`First item must exist in "${collection}"`, query);
|
|
25
25
|
return first;
|
|
26
26
|
}
|
|
27
27
|
/** Get the last item in this store. */
|
|
28
28
|
get last() {
|
|
29
29
|
const last = this.optionalLast;
|
|
30
30
|
if (!last)
|
|
31
|
-
throw new
|
|
31
|
+
throw new NotFoundError(`Last item must exist in "${collection}"`, query);
|
|
32
32
|
return last;
|
|
33
33
|
}
|
|
34
34
|
constructor(collection, query, provider, memory) {
|
package/db/ValidationProvider.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ValidationError } from "../error/ValidationError.js";
|
|
2
2
|
import { Feedback } from "../feedback/Feedback.js";
|
|
3
3
|
import { updateData } from "../util/update.js";
|
|
4
4
|
import { validateWithContext } from "../util/validate.js";
|
|
@@ -124,7 +124,7 @@ function _validateItem(collection, unsafeEntity, schema) {
|
|
|
124
124
|
catch (thrown) {
|
|
125
125
|
if (!(thrown instanceof Feedback))
|
|
126
126
|
throw thrown;
|
|
127
|
-
throw new
|
|
127
|
+
throw new ValidationError(`Invalid data for "${collection}"`, thrown.message);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
/** Validate a set of entities for this query reference. */
|
|
@@ -146,5 +146,5 @@ function* _yieldValidItems(collection, unsafeEntities, schema) {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
if (invalid)
|
|
149
|
-
throw new
|
|
149
|
+
throw new ValidationError(`Invalid data for "${collection}"`, messages);
|
|
150
150
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if the state of the program is not correct to execute a given operation. */
|
|
3
|
+
export declare class ConflictError extends EnhancedError {
|
|
4
|
+
readonly code = 509;
|
|
5
|
+
constructor(message?: string, context?: unknown);
|
|
6
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if the state of the program is not correct to execute a given operation. */
|
|
3
|
+
export class ConflictError extends EnhancedError {
|
|
4
|
+
code = 509;
|
|
5
|
+
constructor(message = "Conflict", context) {
|
|
6
|
+
super(message, context);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
ConflictError.prototype.name = "ConflictError";
|
package/error/EnhancedError.d.ts
CHANGED
package/error/EnhancedError.js
CHANGED
|
@@ -5,6 +5,7 @@ import { debug } from "../util/debug.js";
|
|
|
5
5
|
* - Context is converted to a string using `debug()`
|
|
6
6
|
*/
|
|
7
7
|
export class EnhancedError extends Error {
|
|
8
|
+
code = 500;
|
|
8
9
|
context;
|
|
9
10
|
constructor(message, context) {
|
|
10
11
|
const debugged = context !== undefined ? debug(context, 2) : "";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if an operation failed because the user is logged in but does not have sufficient privileges to access something. */
|
|
3
|
+
export declare class ForbiddenError extends EnhancedError {
|
|
4
|
+
readonly code = 403;
|
|
5
|
+
constructor(message?: string, context?: unknown);
|
|
6
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if an operation failed because the user is logged in but does not have sufficient privileges to access something. */
|
|
3
|
+
export class ForbiddenError extends EnhancedError {
|
|
4
|
+
code = 403;
|
|
5
|
+
constructor(message = "Forbidden", context) {
|
|
6
|
+
super(message, context);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
ForbiddenError.prototype.name = "ForbiddenError";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if if a value is required but doesn't exist. */
|
|
3
|
+
export class NotFoundError extends EnhancedError {
|
|
4
|
+
code = 404;
|
|
5
|
+
constructor(message = "Not found", context) {
|
|
6
|
+
super(message, context);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
NotFoundError.prototype.name = "NotFoundError";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EnhancedError } from "./EnhancedError.js";
|
|
2
2
|
/** Error thrown when functionality is called but is not implemented by an interface. */
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class NotImplementedError extends EnhancedError {
|
|
4
|
+
readonly code = 501;
|
|
4
5
|
constructor(message?: string, value?: unknown);
|
|
5
6
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { EnhancedError } from "./EnhancedError.js";
|
|
2
2
|
/** Error thrown when functionality is called but is not implemented by an interface. */
|
|
3
|
-
export class
|
|
3
|
+
export class NotImplementedError extends EnhancedError {
|
|
4
|
+
code = 501;
|
|
4
5
|
constructor(message = "Not implemented", value) {
|
|
5
6
|
super(message, value);
|
|
6
7
|
}
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
NotImplementedError.prototype.name = "NotImplementedError";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if an operation failed because the user is logged in but does not have sufficient privileges to access something. */
|
|
3
|
+
export declare class UnauthorizedError extends EnhancedError {
|
|
4
|
+
readonly code = 403;
|
|
5
|
+
constructor(message?: string, context?: unknown);
|
|
6
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EnhancedError } from "./EnhancedError.js";
|
|
2
|
+
/** Thrown if an operation failed because the user is logged in but does not have sufficient privileges to access something. */
|
|
3
|
+
export class UnauthorizedError extends EnhancedError {
|
|
4
|
+
code = 403;
|
|
5
|
+
constructor(message = "Unauthorized", context) {
|
|
6
|
+
super(message, context);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
UnauthorizedError.prototype.name = "UnauthorizedError";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EnhancedError } from "./EnhancedError.js";
|
|
2
2
|
/** Error thrown when a value isn't valid. */
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class ValidationError extends EnhancedError {
|
|
4
|
+
readonly code = 422;
|
|
4
5
|
constructor(message?: string, context?: unknown);
|
|
5
6
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { EnhancedError } from "./EnhancedError.js";
|
|
2
2
|
/** Error thrown when a value isn't valid. */
|
|
3
|
-
export class
|
|
3
|
+
export class ValidationError extends EnhancedError {
|
|
4
|
+
code = 422;
|
|
4
5
|
constructor(message = "Invalid value", context) {
|
|
5
6
|
super(message, context);
|
|
6
7
|
}
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
ValidationError.prototype.name = "ValidationError";
|
package/error/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * from "./EnhancedError.js";
|
|
2
|
-
export * from "./
|
|
2
|
+
export * from "./ConflictError.js";
|
|
3
3
|
export * from "./ConnectionError.js";
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./
|
|
4
|
+
export * from "./ForbiddenError.js";
|
|
5
|
+
export * from "./UnauthorizedError.js";
|
|
6
|
+
export * from "./NotFoundError.js";
|
|
7
|
+
export * from "./NotImplementedError.js";
|
|
8
|
+
export * from "./ValidationError.js";
|
package/error/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * from "./EnhancedError.js";
|
|
2
|
-
export * from "./
|
|
2
|
+
export * from "./ConflictError.js";
|
|
3
3
|
export * from "./ConnectionError.js";
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./
|
|
4
|
+
export * from "./ForbiddenError.js";
|
|
5
|
+
export * from "./UnauthorizedError.js";
|
|
6
|
+
export * from "./NotFoundError.js";
|
|
7
|
+
export * from "./NotImplementedError.js";
|
|
8
|
+
export * from "./ValidationError.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { addDoc, arrayRemove, arrayUnion, collection, deleteDoc, doc, documentId, getCount, getDoc, getDocs, increment, limit, orderBy, query, setDoc, updateDoc, where, } from "firebase/firestore/lite";
|
|
2
2
|
import { AsyncProvider } from "../../db/Provider.js";
|
|
3
|
-
import {
|
|
3
|
+
import { NotImplementedError } from "../../error/NotImplementedError.js";
|
|
4
4
|
import { getItem } from "../../util/item.js";
|
|
5
5
|
import { getObject } from "../../util/object.js";
|
|
6
6
|
import { getFilters, getLimit, getOrders } from "../../util/query.js";
|
|
@@ -76,7 +76,7 @@ export class FirestoreLiteProvider extends AsyncProvider {
|
|
|
76
76
|
return _getOptionalItem(snapshot);
|
|
77
77
|
}
|
|
78
78
|
getItemSequence() {
|
|
79
|
-
throw new
|
|
79
|
+
throw new NotImplementedError("FirestoreLiteProvider does not support realtime subscriptions");
|
|
80
80
|
}
|
|
81
81
|
async addItem(c, data) {
|
|
82
82
|
const reference = await addDoc(collection(this._firestore, c), data);
|
|
@@ -100,7 +100,7 @@ export class FirestoreLiteProvider extends AsyncProvider {
|
|
|
100
100
|
return snapshot.docs.map(_getItem);
|
|
101
101
|
}
|
|
102
102
|
getQuerySequence() {
|
|
103
|
-
throw new
|
|
103
|
+
throw new NotImplementedError("FirestoreLiteProvider does not support realtime subscriptions");
|
|
104
104
|
}
|
|
105
105
|
async setQuery(c, q, data) {
|
|
106
106
|
const snapshot = await getDocs(_getQuery(this._firestore, c, q));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConflictError } from "../error/ConflictError.js";
|
|
2
2
|
import { ThroughIterator } from "./ThroughIterator.js";
|
|
3
3
|
/** Used when the sequence hasn't inspected anything yet. */
|
|
4
4
|
const _NOVALUE = Symbol("shelving/InspectGenerator.NOVALUE");
|
|
@@ -20,21 +20,21 @@ export class InspectIterator extends ThroughIterator {
|
|
|
20
20
|
/** The first yielded value (throws if the iteration yielded no values, i.e. `this.count === 0`). */
|
|
21
21
|
get first() {
|
|
22
22
|
if (this._first === _NOVALUE)
|
|
23
|
-
throw new
|
|
23
|
+
throw new ConflictError("Iteration not started");
|
|
24
24
|
return this._first;
|
|
25
25
|
}
|
|
26
26
|
_first = _NOVALUE;
|
|
27
27
|
/** The last yielded value (throws if the iteration yielded no values, i.e. `this.count === 0`). */
|
|
28
28
|
get last() {
|
|
29
29
|
if (this._last === _NOVALUE)
|
|
30
|
-
throw new
|
|
30
|
+
throw new ConflictError("Iteration not started");
|
|
31
31
|
return this._last;
|
|
32
32
|
}
|
|
33
33
|
_last = _NOVALUE;
|
|
34
34
|
/** The returned value (throws if the iteration is not done, i.e. `this.done === false`). */
|
|
35
35
|
get returned() {
|
|
36
36
|
if (this._returned === _NOVALUE)
|
|
37
|
-
throw new
|
|
37
|
+
throw new ConflictError("Iteration not done");
|
|
38
38
|
return this._returned;
|
|
39
39
|
}
|
|
40
40
|
_returned = _NOVALUE;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, createElement, useContext, useRef } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { ConflictError } from "../error/ConflictError.js";
|
|
3
3
|
/**
|
|
4
4
|
* Create a cache context that can be provided to React elements and allows them to call `useCache()`
|
|
5
5
|
* - Cache is a `Map` indexed by strings that can be used to store any value.
|
|
@@ -10,7 +10,7 @@ export function createCacheContext() {
|
|
|
10
10
|
useCache() {
|
|
11
11
|
const cache = useContext(context);
|
|
12
12
|
if (!cache)
|
|
13
|
-
throw new
|
|
13
|
+
throw new ConflictError("useCache() must be used inside <Cache>");
|
|
14
14
|
return cache;
|
|
15
15
|
},
|
|
16
16
|
CacheContext({ children }) {
|
package/schema/ColorSchema.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { StringSchema } from "./StringSchema.js";
|
|
1
|
+
import { TextSchema, type TextSchemaOptions } from "./TextSchema.js";
|
|
3
2
|
/**
|
|
4
3
|
* Define a valid color hex string, e.g `#00CCFF`
|
|
5
4
|
*
|
|
@@ -9,8 +8,8 @@ import { StringSchema } from "./StringSchema.js";
|
|
|
9
8
|
*
|
|
10
9
|
* Colors are limited to 512 characters (this can be changed with `max`), but generally these won't be data: URIs so this is a reasonable limit.
|
|
11
10
|
*/
|
|
12
|
-
export declare class ColorSchema extends
|
|
13
|
-
constructor({ title, value, ...options }: Omit<
|
|
11
|
+
export declare class ColorSchema extends TextSchema {
|
|
12
|
+
constructor({ title, value, ...options }: Omit<TextSchemaOptions, "type" | "min" | "max" | "multiline" | "match">);
|
|
14
13
|
sanitize(insaneString: string): string;
|
|
15
14
|
}
|
|
16
15
|
/** Valid color hex string, e.g. `#00CCFF` (required because empty string is invalid). */
|
package/schema/ColorSchema.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { TextSchema } from "./TextSchema.js";
|
|
3
3
|
const COLOR_REGEXP = /^#[0-9A-F]{6}$/;
|
|
4
4
|
const NOT_HEX_REGEXP = /[^0-9A-F]/g;
|
|
5
5
|
/**
|
|
@@ -11,7 +11,7 @@ const NOT_HEX_REGEXP = /[^0-9A-F]/g;
|
|
|
11
11
|
*
|
|
12
12
|
* Colors are limited to 512 characters (this can be changed with `max`), but generally these won't be data: URIs so this is a reasonable limit.
|
|
13
13
|
*/
|
|
14
|
-
export class ColorSchema extends
|
|
14
|
+
export class ColorSchema extends TextSchema {
|
|
15
15
|
constructor({ title = "Color", value = "#000000", ...options }) {
|
|
16
16
|
super({
|
|
17
17
|
title,
|
package/schema/EmailSchema.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StringSchemaOptions } from "./StringSchema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { TextSchema } from "./TextSchema.js";
|
|
3
3
|
/**
|
|
4
4
|
* Define a valid email address.
|
|
5
5
|
*
|
|
@@ -17,9 +17,9 @@ import { StringSchema } from "./StringSchema.js";
|
|
|
17
17
|
* - Up to 10 segments of up to 63 characters each, separated by `.`
|
|
18
18
|
* - TLD is a segment of 2-63 characters, possibly in `xn--` international format.
|
|
19
19
|
*/
|
|
20
|
-
export declare class EmailSchema extends
|
|
20
|
+
export declare class EmailSchema extends TextSchema {
|
|
21
21
|
constructor({ title, ...options }: Omit<StringSchemaOptions, "type" | "min" | "max" | "match" | "multiline">);
|
|
22
|
-
sanitize(
|
|
22
|
+
sanitize(str: string): string;
|
|
23
23
|
}
|
|
24
24
|
/** Valid email, e.g. `test@test.com` */
|
|
25
25
|
export declare const EMAIL: EmailSchema;
|
package/schema/EmailSchema.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { TextSchema } from "./TextSchema.js";
|
|
3
3
|
const R_MATCH = /^[a-z0-9](?:[a-zA-Z0-9._+-]{0,62}[a-zA-Z0-9])?@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.){1,3}(?:[a-z]{2,63}|xn--[a-z0-9-]{0,58}[a-z0-9])$/;
|
|
4
4
|
/**
|
|
5
5
|
* Define a valid email address.
|
|
@@ -18,7 +18,7 @@ const R_MATCH = /^[a-z0-9](?:[a-zA-Z0-9._+-]{0,62}[a-zA-Z0-9])?@(?:[a-z0-9](?:[a
|
|
|
18
18
|
* - Up to 10 segments of up to 63 characters each, separated by `.`
|
|
19
19
|
* - TLD is a segment of 2-63 characters, possibly in `xn--` international format.
|
|
20
20
|
*/
|
|
21
|
-
export class EmailSchema extends
|
|
21
|
+
export class EmailSchema extends TextSchema {
|
|
22
22
|
constructor({ title = "Email", ...options }) {
|
|
23
23
|
super({
|
|
24
24
|
title,
|
|
@@ -30,9 +30,8 @@ export class EmailSchema extends StringSchema {
|
|
|
30
30
|
multiline: false,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
sanitize(
|
|
34
|
-
|
|
35
|
-
return typeof sanitizedString === "string" ? sanitizedString.toLowerCase() : sanitizedString;
|
|
33
|
+
sanitize(str) {
|
|
34
|
+
return super.sanitize(str).toLowerCase();
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
/** Valid email, e.g. `test@test.com` */
|
package/schema/KeySchema.d.ts
CHANGED
|
@@ -2,11 +2,14 @@ import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Define a valid database key.
|
|
4
4
|
*
|
|
5
|
+
* - Characters that are not a-z, A-Z, 0-9 are removed.
|
|
5
6
|
* - Default minimum key length is 1 character.
|
|
6
|
-
* - Default maximum key length is
|
|
7
|
+
* - Default maximum key length is 32 characters.
|
|
8
|
+
* - 32 characters is enough for UUIDs, as the 4 `-` hyphens are removed.
|
|
7
9
|
*/
|
|
8
10
|
export declare class KeySchema extends StringSchema {
|
|
9
11
|
constructor({ min, max, ...options }: StringSchemaOptions);
|
|
12
|
+
sanitize(str: string): string;
|
|
10
13
|
}
|
|
11
14
|
/** Valid database key. */
|
|
12
15
|
export declare const KEY: KeySchema;
|
package/schema/KeySchema.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
2
2
|
import { StringSchema } from "./StringSchema.js";
|
|
3
|
+
const R_NOT_CHAR = /[^a-zA-Z0-9]/g;
|
|
3
4
|
/**
|
|
4
5
|
* Define a valid database key.
|
|
5
6
|
*
|
|
7
|
+
* - Characters that are not a-z, A-Z, 0-9 are removed.
|
|
6
8
|
* - Default minimum key length is 1 character.
|
|
7
|
-
* - Default maximum key length is
|
|
9
|
+
* - Default maximum key length is 32 characters.
|
|
10
|
+
* - 32 characters is enough for UUIDs, as the 4 `-` hyphens are removed.
|
|
8
11
|
*/
|
|
9
12
|
export class KeySchema extends StringSchema {
|
|
10
|
-
constructor({ min = 1, max =
|
|
13
|
+
constructor({ min = 1, max = 32, ...options }) {
|
|
11
14
|
super({ min, max, ...options });
|
|
12
15
|
}
|
|
16
|
+
sanitize(str) {
|
|
17
|
+
return str.replace(R_NOT_CHAR, "");
|
|
18
|
+
}
|
|
13
19
|
}
|
|
14
20
|
/** Valid database key. */
|
|
15
|
-
export const KEY = new KeySchema({});
|
|
21
|
+
export const KEY = new KeySchema({ title: "ID" });
|
|
16
22
|
/** Valid optional database key. */
|
|
17
23
|
export const OPTIONAL_KEY = OPTIONAL(KEY);
|
package/schema/LinkSchema.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ImmutableArray } from "../util/array.js";
|
|
2
2
|
import { type AbsoluteLink } from "../util/link.js";
|
|
3
3
|
import type { StringSchemaOptions } from "./StringSchema.js";
|
|
4
|
-
import {
|
|
4
|
+
import { TextSchema } from "./TextSchema.js";
|
|
5
5
|
/** Allowed options for `LinkSchema` */
|
|
6
6
|
export interface LinkSchemaOptions extends Omit<StringSchemaOptions, "type" | "min" | "max" | "multiline"> {
|
|
7
7
|
readonly base?: AbsoluteLink | undefined;
|
|
@@ -14,7 +14,7 @@ export interface LinkSchemaOptions extends Omit<StringSchemaOptions, "type" | "m
|
|
|
14
14
|
* - URLs are limited to 512 characters, but generally these won't be data: URIs so this is a reasonable limit.
|
|
15
15
|
* - Falsy values are converted to `""` empty string.
|
|
16
16
|
*/
|
|
17
|
-
export declare class LinkSchema extends
|
|
17
|
+
export declare class LinkSchema extends TextSchema {
|
|
18
18
|
readonly base: AbsoluteLink | undefined;
|
|
19
19
|
readonly schemes: ImmutableArray<string> | undefined;
|
|
20
20
|
readonly hosts: ImmutableArray<string> | undefined;
|
package/schema/LinkSchema.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ValueFeedback } from "../feedback/Feedback.js";
|
|
2
2
|
import { getOptionalLinkURL } from "../util/link.js";
|
|
3
3
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
4
|
-
import {
|
|
4
|
+
import { TextSchema } from "./TextSchema.js";
|
|
5
5
|
/**
|
|
6
6
|
* Type of `StringSchema` that defines a valid URL link.
|
|
7
7
|
* - Checks URL scheme against a whitelist (always), and checks URL domain against a whitelist (optional).
|
|
8
8
|
* - URLs are limited to 512 characters, but generally these won't be data: URIs so this is a reasonable limit.
|
|
9
9
|
* - Falsy values are converted to `""` empty string.
|
|
10
10
|
*/
|
|
11
|
-
export class LinkSchema extends
|
|
11
|
+
export class LinkSchema extends TextSchema {
|
|
12
12
|
base;
|
|
13
13
|
schemes;
|
|
14
14
|
hosts;
|
|
@@ -27,10 +27,10 @@ export class LinkSchema extends StringSchema {
|
|
|
27
27
|
}
|
|
28
28
|
// Override to clean the URL using builtin helper functions and check the schemes and hosts against the whitelists.
|
|
29
29
|
validate(unsafeValue) {
|
|
30
|
-
const
|
|
31
|
-
const url = getOptionalLinkURL(
|
|
30
|
+
const str = super.validate(unsafeValue);
|
|
31
|
+
const url = getOptionalLinkURL(str, this.base, this.schemes, this.hosts);
|
|
32
32
|
if (!url)
|
|
33
|
-
throw new ValueFeedback(
|
|
33
|
+
throw new ValueFeedback(str ? "Invalid format" : "Required", str);
|
|
34
34
|
return url.href;
|
|
35
35
|
}
|
|
36
36
|
}
|
package/schema/NumberSchema.js
CHANGED
|
@@ -26,7 +26,7 @@ export class NumberSchema extends Schema {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
/** Valid number, e.g. `2048.12345` or `0` zero. */
|
|
29
|
-
export const NUMBER = new NumberSchema({});
|
|
29
|
+
export const NUMBER = new NumberSchema({ title: "Number" });
|
|
30
30
|
/** Valid optional number, e.g. `2048.12345` or `0` zero, or `null` */
|
|
31
31
|
export const OPTIONAL_NUMBER = OPTIONAL(NUMBER);
|
|
32
32
|
/** Valid integer number, e.g. `2048` or `0` zero. */
|
package/schema/PhoneSchema.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { StringSchemaOptions } from "./StringSchema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { TextSchema } from "./TextSchema.js";
|
|
3
3
|
/**
|
|
4
4
|
* Type of `StringSchema` that defines a valid phone number.
|
|
5
5
|
* - Multiple string formats are automatically converted to E.164 format (starting with `+` plus).
|
|
6
6
|
* - Falsy values are converted to `""` empty string.
|
|
7
7
|
*/
|
|
8
|
-
export declare class PhoneSchema extends
|
|
8
|
+
export declare class PhoneSchema extends TextSchema {
|
|
9
9
|
constructor({ title, ...options }: StringSchemaOptions);
|
|
10
10
|
sanitize(insaneString: string): string;
|
|
11
11
|
}
|
package/schema/PhoneSchema.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { TextSchema } from "./TextSchema.js";
|
|
3
3
|
// Valid phone number is max 16 digits made up of:
|
|
4
4
|
// - Country code (`+` plus character and 1-3 digits, e.g. `+44` or `+1`).
|
|
5
5
|
// - Subscriber number (5-12 digits — the Solomon Islands have five-digit phone numbers apparently).
|
|
@@ -9,7 +9,7 @@ const PHONE_REGEXP = /^\+[1-9][0-9]{0,2}[0-9]{5,12}$/;
|
|
|
9
9
|
* - Multiple string formats are automatically converted to E.164 format (starting with `+` plus).
|
|
10
10
|
* - Falsy values are converted to `""` empty string.
|
|
11
11
|
*/
|
|
12
|
-
export class PhoneSchema extends
|
|
12
|
+
export class PhoneSchema extends TextSchema {
|
|
13
13
|
constructor({ title = "Phone", ...options }) {
|
|
14
14
|
super({
|
|
15
15
|
title,
|
package/schema/SlugSchema.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class SlugSchema extends StringSchema {
|
|
10
10
|
constructor(options: Omit<StringSchemaOptions, "min" | "max" | "multiline">);
|
|
11
|
-
sanitize(
|
|
11
|
+
sanitize(str: string): string;
|
|
12
12
|
}
|
|
13
13
|
/** Valid slug, e.g. `this-is-a-slug` */
|
|
14
14
|
export declare const SLUG: SlugSchema;
|
package/schema/SlugSchema.js
CHANGED
|
@@ -14,11 +14,10 @@ export class SlugSchema extends StringSchema {
|
|
|
14
14
|
...options,
|
|
15
15
|
min: 2,
|
|
16
16
|
max: 32,
|
|
17
|
-
multiline: false,
|
|
18
17
|
});
|
|
19
18
|
}
|
|
20
|
-
sanitize(
|
|
21
|
-
return getSlug(
|
|
19
|
+
sanitize(str) {
|
|
20
|
+
return getSlug(str);
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
/** Valid slug, e.g. `this-is-a-slug` */
|