@atproto/lex-schema 0.0.17 → 0.0.19
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 +20 -0
- package/dist/core/string-format.d.ts +10 -16
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +21 -11
- package/dist/core/string-format.js.map +1 -1
- package/dist/schema/blob.d.ts +6 -20
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +23 -28
- package/dist/schema/blob.js.map +1 -1
- package/package.json +3 -3
- package/src/core/string-format.ts +24 -20
- package/src/schema/blob.test.ts +223 -263
- package/src/schema/blob.ts +27 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atproto/lex-schema
|
|
2
2
|
|
|
3
|
+
## 0.0.19
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4806](https://github.com/bluesky-social/atproto/pull/4806) [`26d793a`](https://github.com/bluesky-social/atproto/commit/26d793af95a6fb3a50f9b2a97187d8ac4fecf676) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Export `AtUriString` utilities from `@atproto/syntax`
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`26d793a`](https://github.com/bluesky-social/atproto/commit/26d793af95a6fb3a50f9b2a97187d8ac4fecf676), [`26d793a`](https://github.com/bluesky-social/atproto/commit/26d793af95a6fb3a50f9b2a97187d8ac4fecf676), [`26d793a`](https://github.com/bluesky-social/atproto/commit/26d793af95a6fb3a50f9b2a97187d8ac4fecf676), [`55d06de`](https://github.com/bluesky-social/atproto/commit/55d06de80a1506908a04ed5c0834986cb5783797), [`26d793a`](https://github.com/bluesky-social/atproto/commit/26d793af95a6fb3a50f9b2a97187d8ac4fecf676)]:
|
|
10
|
+
- @atproto/syntax@0.5.4
|
|
11
|
+
|
|
12
|
+
## 0.0.18
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [#4828](https://github.com/bluesky-social/atproto/pull/4828) [`c62651d`](https://github.com/bluesky-social/atproto/commit/c62651dd69f1e18bd854b66e499b91fee9eaa856) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Accept legacy blob references in non-strict mode. Legacy blob references (objects with `cid` and `mimeType` properties) are now accepted when `strict: false`, which is the default behavior when `strictResponseProcessing` is disabled on the Client.
|
|
17
|
+
|
|
18
|
+
BREAKING: The `allowLegacy` option has been removed from the blob schema builder, and legacy blobs are now handled automatically based on the strictness mode: in strict mode they are rejected, and in non-strict mode they are accepted. Consumers should stop passing `allowLegacy` and rely on strictness configuration instead. Likewise, CLI consumers should stop using the removed `--allowLegacyBlobs` flag and use the default strict/non-strict behavior.
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [[`c62651d`](https://github.com/bluesky-social/atproto/commit/c62651dd69f1e18bd854b66e499b91fee9eaa856), [`f6f100c`](https://github.com/bluesky-social/atproto/commit/f6f100c33700a7ff58a1458109cc7420131feed0), [`c62651d`](https://github.com/bluesky-social/atproto/commit/c62651dd69f1e18bd854b66e499b91fee9eaa856), [`c62651d`](https://github.com/bluesky-social/atproto/commit/c62651dd69f1e18bd854b66e499b91fee9eaa856)]:
|
|
21
|
+
- @atproto/lex-data@0.0.15
|
|
22
|
+
|
|
3
23
|
## 0.0.17
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
import { AtIdentifierString, AtUriString, DatetimeString, DidString, HandleString, NsidString, RecordKeyString, TidString, UriString } from '@atproto/syntax';
|
|
2
2
|
import { CheckFn } from '../util/assertion-util.js';
|
|
3
|
-
export { type AtIdentifierString, asAtIdentifierString, ifAtIdentifierString, isAtIdentifierString, } from '@atproto/syntax';
|
|
3
|
+
export { type AtIdentifierString, asAtIdentifierString, assertAtIdentifierString, ifAtIdentifierString, isAtIdentifierString, } from '@atproto/syntax';
|
|
4
4
|
export { isDidIdentifier, isHandleIdentifier } from '@atproto/syntax';
|
|
5
|
-
export { type DatetimeString, asDatetimeString, ifDatetimeString, isDatetimeString, } from '@atproto/syntax';
|
|
5
|
+
export { type DatetimeString, asDatetimeString, assertDatetimeString, ifDatetimeString, isDatetimeString, } from '@atproto/syntax';
|
|
6
6
|
/**
|
|
7
7
|
* Matches any ISO-ish datetime string. This is a more lenient check than
|
|
8
8
|
* the strict {@link isDatetimeString} guard, which only allows datetimes that
|
|
9
9
|
* fully conform to the AT Protocol specification (e.g. must include timezone).
|
|
10
10
|
*/
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function isDatetimeStringLenient<I>(input: I): input is I & DatetimeString;
|
|
12
12
|
export { currentDatetimeString, toDatetimeString } from '@atproto/syntax';
|
|
13
|
+
export { type AtUriString, asAtUriString, assertAtUriString, ifAtUriString, isAtUriString, } from '@atproto/syntax';
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
+
* Lenient version of {@link isAtUriString} that does not enforce the validity
|
|
16
|
+
* of the record key (rkey) path component (if present).
|
|
15
17
|
*
|
|
16
|
-
* @
|
|
17
|
-
* @returns `true` if the value is a valid AT URI
|
|
18
|
-
*/
|
|
19
|
-
export declare const isAtUriString: CheckFn<AtUriString>;
|
|
20
|
-
export type {
|
|
21
|
-
/**
|
|
22
|
-
* An AT URI string pointing to a resource in the AT Protocol network.
|
|
23
|
-
*
|
|
24
|
-
* @example `"at://did:plc:1234.../app.bsky.feed.post/3k2..."`
|
|
18
|
+
* @see {@link isAtUriString}
|
|
25
19
|
*/
|
|
26
|
-
AtUriString
|
|
20
|
+
export declare function isAtUriStringLenient<I>(input: I): input is I & AtUriString;
|
|
27
21
|
/**
|
|
28
22
|
* Type guard that checks if a value is a valid CID string.
|
|
29
23
|
*
|
|
@@ -161,8 +155,8 @@ type StringFormats = {
|
|
|
161
155
|
export type StringFormat = Extract<keyof StringFormats, string>;
|
|
162
156
|
export type StringFormatValidationOptions = {
|
|
163
157
|
/**
|
|
164
|
-
* Allows to be more lenient in validation by using a "
|
|
165
|
-
* function, if available. The behavior of the
|
|
158
|
+
* Allows to be more lenient in validation by using a "lenient" verification
|
|
159
|
+
* function, if available. The behavior of the lenient verifier depends on the
|
|
166
160
|
* specific format, but generally it may allow for a wider range of valid
|
|
167
161
|
* inputs, including values that are not compliant with the AT Protocol
|
|
168
162
|
* specification.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string-format.d.ts","sourceRoot":"","sources":["../../src/core/string-format.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,SAAS,EACT,YAAY,EACZ,UAAU,EACV,eAAe,EACf,SAAS,EACT,SAAS,EAWV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAWnD,OAAO,EACL,KAAK,kBAAkB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAErE,OAAO,EACL,KAAK,cAAc,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,iBAAiB,CAAA;AAExB;;;;GAIG;AACH,wBAAgB,
|
|
1
|
+
{"version":3,"file":"string-format.d.ts","sourceRoot":"","sources":["../../src/core/string-format.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.STRING_FORMATS = exports.isUriString = exports.isTidString = exports.isRecordKeyString = exports.isNsidString = exports.isLanguageString = exports.isHandleString = exports.isDidString = exports.isCidString = exports.isAtUriString = exports.toDatetimeString = exports.currentDatetimeString = exports.isDatetimeString = exports.ifDatetimeString = exports.asDatetimeString = exports.isHandleIdentifier = exports.isDidIdentifier = exports.isAtIdentifierString = exports.ifAtIdentifierString = exports.asAtIdentifierString = void 0;
|
|
4
|
-
exports.
|
|
3
|
+
exports.STRING_FORMATS = exports.isUriString = exports.isTidString = exports.isRecordKeyString = exports.isNsidString = exports.isLanguageString = exports.isHandleString = exports.isDidString = exports.isCidString = exports.isAtUriString = exports.ifAtUriString = exports.assertAtUriString = exports.asAtUriString = exports.toDatetimeString = exports.currentDatetimeString = exports.isDatetimeString = exports.ifDatetimeString = exports.assertDatetimeString = exports.asDatetimeString = exports.isHandleIdentifier = exports.isDidIdentifier = exports.isAtIdentifierString = exports.ifAtIdentifierString = exports.assertAtIdentifierString = exports.asAtIdentifierString = void 0;
|
|
4
|
+
exports.isDatetimeStringLenient = isDatetimeStringLenient;
|
|
5
|
+
exports.isAtUriStringLenient = isAtUriStringLenient;
|
|
5
6
|
exports.isStringFormat = isStringFormat;
|
|
6
7
|
exports.assertStringFormat = assertStringFormat;
|
|
7
8
|
exports.asStringFormat = asStringFormat;
|
|
@@ -18,6 +19,7 @@ const syntax_1 = require("@atproto/syntax");
|
|
|
18
19
|
// and re-export here, e.g. language tags, NSIDs, record keys, etc.
|
|
19
20
|
var syntax_2 = require("@atproto/syntax");
|
|
20
21
|
Object.defineProperty(exports, "asAtIdentifierString", { enumerable: true, get: function () { return syntax_2.asAtIdentifierString; } });
|
|
22
|
+
Object.defineProperty(exports, "assertAtIdentifierString", { enumerable: true, get: function () { return syntax_2.assertAtIdentifierString; } });
|
|
21
23
|
Object.defineProperty(exports, "ifAtIdentifierString", { enumerable: true, get: function () { return syntax_2.ifAtIdentifierString; } });
|
|
22
24
|
Object.defineProperty(exports, "isAtIdentifierString", { enumerable: true, get: function () { return syntax_2.isAtIdentifierString; } });
|
|
23
25
|
// AtIdentifierString utilities
|
|
@@ -26,6 +28,7 @@ Object.defineProperty(exports, "isDidIdentifier", { enumerable: true, get: funct
|
|
|
26
28
|
Object.defineProperty(exports, "isHandleIdentifier", { enumerable: true, get: function () { return syntax_3.isHandleIdentifier; } });
|
|
27
29
|
var syntax_4 = require("@atproto/syntax");
|
|
28
30
|
Object.defineProperty(exports, "asDatetimeString", { enumerable: true, get: function () { return syntax_4.asDatetimeString; } });
|
|
31
|
+
Object.defineProperty(exports, "assertDatetimeString", { enumerable: true, get: function () { return syntax_4.assertDatetimeString; } });
|
|
29
32
|
Object.defineProperty(exports, "ifDatetimeString", { enumerable: true, get: function () { return syntax_4.ifDatetimeString; } });
|
|
30
33
|
Object.defineProperty(exports, "isDatetimeString", { enumerable: true, get: function () { return syntax_4.isDatetimeString; } });
|
|
31
34
|
/**
|
|
@@ -33,7 +36,7 @@ Object.defineProperty(exports, "isDatetimeString", { enumerable: true, get: func
|
|
|
33
36
|
* the strict {@link isDatetimeString} guard, which only allows datetimes that
|
|
34
37
|
* fully conform to the AT Protocol specification (e.g. must include timezone).
|
|
35
38
|
*/
|
|
36
|
-
function
|
|
39
|
+
function isDatetimeStringLenient(input) {
|
|
37
40
|
// @NOTE the returned type assertion is inaccurate wrt. the DatetimeString
|
|
38
41
|
// type definition. A more accurate solution would be to use a branded type
|
|
39
42
|
// instead of a template literal for the "datetime" format
|
|
@@ -51,13 +54,20 @@ function isDatetimeStringLoose(input) {
|
|
|
51
54
|
var syntax_5 = require("@atproto/syntax");
|
|
52
55
|
Object.defineProperty(exports, "currentDatetimeString", { enumerable: true, get: function () { return syntax_5.currentDatetimeString; } });
|
|
53
56
|
Object.defineProperty(exports, "toDatetimeString", { enumerable: true, get: function () { return syntax_5.toDatetimeString; } });
|
|
57
|
+
var syntax_6 = require("@atproto/syntax");
|
|
58
|
+
Object.defineProperty(exports, "asAtUriString", { enumerable: true, get: function () { return syntax_6.asAtUriString; } });
|
|
59
|
+
Object.defineProperty(exports, "assertAtUriString", { enumerable: true, get: function () { return syntax_6.assertAtUriString; } });
|
|
60
|
+
Object.defineProperty(exports, "ifAtUriString", { enumerable: true, get: function () { return syntax_6.ifAtUriString; } });
|
|
61
|
+
Object.defineProperty(exports, "isAtUriString", { enumerable: true, get: function () { return syntax_6.isAtUriString; } });
|
|
54
62
|
/**
|
|
55
|
-
*
|
|
63
|
+
* Lenient version of {@link isAtUriString} that does not enforce the validity
|
|
64
|
+
* of the record key (rkey) path component (if present).
|
|
56
65
|
*
|
|
57
|
-
* @
|
|
58
|
-
* @returns `true` if the value is a valid AT URI
|
|
66
|
+
* @see {@link isAtUriString}
|
|
59
67
|
*/
|
|
60
|
-
|
|
68
|
+
function isAtUriStringLenient(input) {
|
|
69
|
+
return (0, syntax_1.isAtUriString)(input, { strict: false });
|
|
70
|
+
}
|
|
61
71
|
/**
|
|
62
72
|
* Type guard that checks if a value is a valid CID string.
|
|
63
73
|
*
|
|
@@ -117,9 +127,9 @@ exports.isUriString = syntax_1.isValidUri;
|
|
|
117
127
|
const stringFormatVerifiers = /*#__PURE__*/ Object.freeze({
|
|
118
128
|
__proto__: null,
|
|
119
129
|
'at-identifier': [syntax_1.isAtIdentifierString],
|
|
120
|
-
'at-uri': [
|
|
130
|
+
'at-uri': [syntax_1.isAtUriString, isAtUriStringLenient],
|
|
121
131
|
cid: [exports.isCidString],
|
|
122
|
-
datetime: [syntax_1.isDatetimeString,
|
|
132
|
+
datetime: [syntax_1.isDatetimeString, isDatetimeStringLenient],
|
|
123
133
|
did: [exports.isDidString],
|
|
124
134
|
handle: [exports.isHandleString],
|
|
125
135
|
language: [exports.isLanguageString],
|
|
@@ -152,8 +162,8 @@ function isStringFormat(input, format, options) {
|
|
|
152
162
|
// Fool-proof
|
|
153
163
|
if (!formatVerifier)
|
|
154
164
|
throw new TypeError(`Unknown string format: ${format}`);
|
|
155
|
-
const check = options?.strict === false
|
|
156
|
-
? formatVerifier[1]
|
|
165
|
+
const check = options?.strict === false && formatVerifier.length > 1
|
|
166
|
+
? formatVerifier[1]
|
|
157
167
|
: formatVerifier[0];
|
|
158
168
|
return check(input);
|
|
159
169
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string-format.js","sourceRoot":"","sources":["../../src/core/string-format.ts"],"names":[],"mappings":"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","sourcesContent":["import { isValidISODateString } from 'iso-datestring-validator'\nimport { validateCidString } from '@atproto/lex-data'\nimport {\n AtIdentifierString,\n AtUriString,\n DatetimeString,\n DidString,\n HandleString,\n NsidString,\n RecordKeyString,\n TidString,\n UriString,\n isAtIdentifierString,\n isDatetimeString,\n isValidAtUri,\n isValidDid,\n isValidHandle,\n isValidLanguage,\n isValidNsid,\n isValidRecordKey,\n isValidTid,\n isValidUri,\n} from '@atproto/syntax'\nimport { CheckFn } from '../util/assertion-util.js'\n\n// -----------------------------------------------------------------------------\n// Individual string format types and type guards\n// -----------------------------------------------------------------------------\n\n// Re-exporting from @atproto/syntax without modification to preserve types and\n// documentation for types and utilities that are already well-defined there.\n// @TODO rework other string formats in @atproto/syntax to follow this pattern\n// and re-export here, e.g. language tags, NSIDs, record keys, etc.\n\nexport {\n type AtIdentifierString,\n asAtIdentifierString,\n ifAtIdentifierString,\n isAtIdentifierString,\n} from '@atproto/syntax'\n\n// AtIdentifierString utilities\nexport { isDidIdentifier, isHandleIdentifier } from '@atproto/syntax'\n\nexport {\n type DatetimeString,\n asDatetimeString,\n ifDatetimeString,\n isDatetimeString,\n} from '@atproto/syntax'\n\n/**\n * Matches any ISO-ish datetime string. This is a more lenient check than\n * the strict {@link isDatetimeString} guard, which only allows datetimes that\n * fully conform to the AT Protocol specification (e.g. must include timezone).\n */\nexport function isDatetimeStringLoose<I>(\n input: I,\n): input is I & DatetimeString {\n // @NOTE the returned type assertion is inaccurate wrt. the DatetimeString\n // type definition. A more accurate solution would be to use a branded type\n // instead of a template literal for the \"datetime\" format\n if (typeof input !== 'string') return false\n try {\n return isValidISODateString(input)\n } catch {\n // @NOTE isValidISODateString throws on some inputs\n return false\n }\n}\n\n// DatetimeString utilities\nexport { currentDatetimeString, toDatetimeString } from '@atproto/syntax'\n\n/**\n * Type guard that checks if a value is a valid AT URI.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid AT URI\n */\nexport const isAtUriString: CheckFn<AtUriString> = isValidAtUri\nexport type {\n /**\n * An AT URI string pointing to a resource in the AT Protocol network.\n *\n * @example `\"at://did:plc:1234.../app.bsky.feed.post/3k2...\"`\n */\n AtUriString,\n}\n\n/**\n * Type guard that checks if a value is a valid CID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid CID string\n */\nexport const isCidString = ((v) => validateCidString(v)) as CheckFn<CidString>\n/**\n * A Content Identifier (CID) string.\n *\n * CIDs are self-describing content addresses used to identify data by its hash.\n *\n * @example `\"bafyreig...\"`\n */\nexport type CidString = string\n\n/**\n * Type guard that checks if a value is a valid DID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid DID string\n */\nexport const isDidString: CheckFn<DidString> = isValidDid\nexport type {\n /**\n * A Decentralized Identifier (DID) string.\n *\n * DIDs are globally unique identifiers that don't require a central authority.\n *\n * @example `\"did:plc:1234abcd...\"` or `\"did:web:example.com\"`\n */\n DidString,\n}\n\n/**\n * Type guard that checks if a value is a valid handle string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid handle string\n */\nexport const isHandleString: CheckFn<HandleString> = isValidHandle\nexport type {\n /**\n * A handle string - a human-readable identifier for users.\n *\n * @example `\"alice.bsky.social\"` or `\"bob.example.com\"`\n */\n HandleString,\n}\n\n/**\n * Type guard that checks if a value is a valid BCP-47 language tag.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid language string\n */\nexport const isLanguageString = isValidLanguage as CheckFn<LanguageString>\n/**\n * A BCP-47 language tag string.\n *\n * @example `\"en\"`, `\"en-US\"`, `\"zh-Hans\"`\n */\nexport type LanguageString = string\n\n/**\n * Type guard that checks if a value is a valid NSID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid NSID string\n */\nexport const isNsidString: CheckFn<NsidString> = isValidNsid\nexport type {\n /**\n * A Namespaced Identifier (NSID) string identifying a lexicon.\n *\n * NSIDs use reverse-domain notation to identify schemas.\n *\n * @example `\"app.bsky.feed.post\"`, `\"com.atproto.repo.createRecord\"`\n */\n NsidString,\n}\n\n/**\n * Type guard that checks if a value is a valid record key string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid record key string\n */\nexport const isRecordKeyString: CheckFn<RecordKeyString> = isValidRecordKey\nexport type {\n /**\n * A record key string identifying a record within a collection.\n *\n * @example `\"3k2...\"` (TID format) or `\"self\"` (literal key)\n */\n RecordKeyString,\n}\n\n/**\n * Type guard that checks if a value is a valid TID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid TID string\n */\nexport const isTidString: CheckFn<TidString> = isValidTid\nexport type {\n /**\n * A Timestamp Identifier (TID) string.\n *\n * TIDs are time-based identifiers used for record keys.\n *\n * @example `\"3k2...\"`\n */\n TidString,\n}\n\n/**\n * Type guard that checks if a value is a valid URI string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid URI string\n */\nexport const isUriString: CheckFn<UriString> = isValidUri\nexport type {\n /**\n * A standard URI string.\n *\n * @example `\"https://example.com/path\"`\n */\n UriString,\n}\n\n// -----------------------------------------------------------------------------\n// String format registry\n// -----------------------------------------------------------------------------\n\ntype StringFormats = {\n 'at-identifier': AtIdentifierString\n 'at-uri': AtUriString\n cid: CidString\n datetime: DatetimeString\n did: DidString\n handle: HandleString\n language: LanguageString\n nsid: NsidString\n 'record-key': RecordKeyString\n tid: TidString\n uri: UriString\n}\n\n/**\n * Union type of all valid string format names.\n */\nexport type StringFormat = Extract<keyof StringFormats, string>\n\nconst stringFormatVerifiers: {\n readonly [K in StringFormat]: readonly [\n strict: CheckFn<StringFormats[K]>,\n loose?: CheckFn<StringFormats[K]>,\n ]\n} = /*#__PURE__*/ Object.freeze({\n __proto__: null,\n\n 'at-identifier': [isAtIdentifierString],\n 'at-uri': [isAtUriString],\n cid: [isCidString],\n datetime: [isDatetimeString, isDatetimeStringLoose],\n did: [isDidString],\n handle: [isHandleString],\n language: [isLanguageString],\n nsid: [isNsidString],\n 'record-key': [isRecordKeyString],\n tid: [isTidString],\n uri: [isUriString],\n})\n\nexport type StringFormatValidationOptions = {\n /**\n * Allows to be more lenient in validation by using a \"loose\" verification\n * function, if available. The behavior of the loose verifier depends on the\n * specific format, but generally it may allow for a wider range of valid\n * inputs, including values that are not compliant with the AT Protocol\n * specification.\n *\n * @default true\n */\n strict?: boolean\n}\n\n/**\n * Infers the string type for a given format name.\n *\n * @typeParam F - The format name\n *\n * @example\n * ```typescript\n * type Did = InferStringFormat<'did'>\n * // Result: DidString\n * ```\n */\nexport type InferStringFormat<F extends StringFormat> = F extends StringFormat\n ? StringFormats[F]\n : never\n\n/**\n * Type guard that checks if a string matches a specific format.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to check\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @returns `true` if the string matches the format\n *\n * @example\n * ```typescript\n * const value: string = 'did:plc:1234...'\n * if (isStringFormat(value, 'did')) {\n * // value is typed as DidString\n * console.log('Valid DID:', value)\n * }\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): input is I & StringFormats[F] {\n const formatVerifier = stringFormatVerifiers[format]\n // Fool-proof\n if (!formatVerifier) throw new TypeError(`Unknown string format: ${format}`)\n\n const check: CheckFn<StringFormats[F]> =\n options?.strict === false\n ? formatVerifier[1] ?? formatVerifier[0]\n : formatVerifier[0]\n\n return check(input)\n}\n\n/**\n * Asserts that a string matches a specific format, throwing if invalid.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to check\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @throws {TypeError} If the string doesn't match the format\n *\n * @example\n * ```typescript\n * assertStringFormat(value, 'handle')\n * // value is now typed as HandleString\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function assertStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): asserts input is I & StringFormats[F] {\n if (!isStringFormat(input, format, options)) {\n throw new TypeError(`Invalid string format (${format}): ${input}`)\n }\n}\n\n/**\n * Validates and returns a string as the specified format type, throwing if invalid.\n *\n * This is useful when you need to convert a string to a format type in an expression.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to validate against\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @returns The input typed as the format type\n * @throws {TypeError} If the string doesn't match the format\n *\n * @example\n * ```typescript\n * const did = asStringFormat(userInput, 'did')\n * // did is typed as DidString\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function asStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): I & StringFormats[F] {\n assertStringFormat(input, format, options)\n return input\n}\n\n/**\n * Returns the string as the format type if valid, otherwise returns `undefined`.\n *\n * This is useful for optional validation where you want to handle invalid values\n * without throwing.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to validate against\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @returns The typed string if valid, otherwise `undefined`\n *\n * @example\n * ```typescript\n * const did = ifStringFormat(maybeInvalid, 'did')\n * if (did) {\n * // did is typed as DidString\n * }\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function ifStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): undefined | (I & StringFormats[F]) {\n return isStringFormat(input, format, options) ? input : undefined\n}\n\n/**\n * Array of all valid string format names.\n *\n * @example\n * ```typescript\n * for (const format of STRING_FORMATS) {\n * console.log(format) // 'at-identifier', 'at-uri', 'cid', ...\n * }\n * ```\n */\nexport const STRING_FORMATS = /*#__PURE__*/ Object.freeze(\n /*#__PURE__*/ Object.keys(stringFormatVerifiers),\n) as readonly StringFormat[]\n"]}
|
|
1
|
+
{"version":3,"file":"string-format.js","sourceRoot":"","sources":["../../src/core/string-format.ts"],"names":[],"mappings":"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","sourcesContent":["import { isValidISODateString } from 'iso-datestring-validator'\nimport { validateCidString } from '@atproto/lex-data'\nimport {\n AtIdentifierString,\n AtUriString,\n DatetimeString,\n DidString,\n HandleString,\n NsidString,\n RecordKeyString,\n TidString,\n UriString,\n isAtIdentifierString,\n isAtUriString,\n isDatetimeString,\n isValidDid,\n isValidHandle,\n isValidLanguage,\n isValidNsid,\n isValidRecordKey,\n isValidTid,\n isValidUri,\n} from '@atproto/syntax'\nimport { CheckFn } from '../util/assertion-util.js'\n\n// -----------------------------------------------------------------------------\n// Individual string format types and type guards\n// -----------------------------------------------------------------------------\n\n// Re-exporting from @atproto/syntax without modification to preserve types and\n// documentation for types and utilities that are already well-defined there.\n// @TODO rework other string formats in @atproto/syntax to follow this pattern\n// and re-export here, e.g. language tags, NSIDs, record keys, etc.\n\nexport {\n type AtIdentifierString,\n asAtIdentifierString,\n assertAtIdentifierString,\n ifAtIdentifierString,\n isAtIdentifierString,\n} from '@atproto/syntax'\n\n// AtIdentifierString utilities\nexport { isDidIdentifier, isHandleIdentifier } from '@atproto/syntax'\n\nexport {\n type DatetimeString,\n asDatetimeString,\n assertDatetimeString,\n ifDatetimeString,\n isDatetimeString,\n} from '@atproto/syntax'\n\n/**\n * Matches any ISO-ish datetime string. This is a more lenient check than\n * the strict {@link isDatetimeString} guard, which only allows datetimes that\n * fully conform to the AT Protocol specification (e.g. must include timezone).\n */\nexport function isDatetimeStringLenient<I>(\n input: I,\n): input is I & DatetimeString {\n // @NOTE the returned type assertion is inaccurate wrt. the DatetimeString\n // type definition. A more accurate solution would be to use a branded type\n // instead of a template literal for the \"datetime\" format\n if (typeof input !== 'string') return false\n try {\n return isValidISODateString(input)\n } catch {\n // @NOTE isValidISODateString throws on some inputs\n return false\n }\n}\n\n// DatetimeString utilities\nexport { currentDatetimeString, toDatetimeString } from '@atproto/syntax'\n\nexport {\n type AtUriString,\n asAtUriString,\n assertAtUriString,\n ifAtUriString,\n isAtUriString,\n} from '@atproto/syntax'\n\n/**\n * Lenient version of {@link isAtUriString} that does not enforce the validity\n * of the record key (rkey) path component (if present).\n *\n * @see {@link isAtUriString}\n */\nexport function isAtUriStringLenient<I>(input: I): input is I & AtUriString {\n return isAtUriString(input, { strict: false })\n}\n\n/**\n * Type guard that checks if a value is a valid CID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid CID string\n */\nexport const isCidString = ((v) => validateCidString(v)) as CheckFn<CidString>\n/**\n * A Content Identifier (CID) string.\n *\n * CIDs are self-describing content addresses used to identify data by its hash.\n *\n * @example `\"bafyreig...\"`\n */\nexport type CidString = string\n\n/**\n * Type guard that checks if a value is a valid DID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid DID string\n */\nexport const isDidString: CheckFn<DidString> = isValidDid\nexport type {\n /**\n * A Decentralized Identifier (DID) string.\n *\n * DIDs are globally unique identifiers that don't require a central authority.\n *\n * @example `\"did:plc:1234abcd...\"` or `\"did:web:example.com\"`\n */\n DidString,\n}\n\n/**\n * Type guard that checks if a value is a valid handle string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid handle string\n */\nexport const isHandleString: CheckFn<HandleString> = isValidHandle\nexport type {\n /**\n * A handle string - a human-readable identifier for users.\n *\n * @example `\"alice.bsky.social\"` or `\"bob.example.com\"`\n */\n HandleString,\n}\n\n/**\n * Type guard that checks if a value is a valid BCP-47 language tag.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid language string\n */\nexport const isLanguageString = isValidLanguage as CheckFn<LanguageString>\n/**\n * A BCP-47 language tag string.\n *\n * @example `\"en\"`, `\"en-US\"`, `\"zh-Hans\"`\n */\nexport type LanguageString = string\n\n/**\n * Type guard that checks if a value is a valid NSID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid NSID string\n */\nexport const isNsidString: CheckFn<NsidString> = isValidNsid\nexport type {\n /**\n * A Namespaced Identifier (NSID) string identifying a lexicon.\n *\n * NSIDs use reverse-domain notation to identify schemas.\n *\n * @example `\"app.bsky.feed.post\"`, `\"com.atproto.repo.createRecord\"`\n */\n NsidString,\n}\n\n/**\n * Type guard that checks if a value is a valid record key string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid record key string\n */\nexport const isRecordKeyString: CheckFn<RecordKeyString> = isValidRecordKey\nexport type {\n /**\n * A record key string identifying a record within a collection.\n *\n * @example `\"3k2...\"` (TID format) or `\"self\"` (literal key)\n */\n RecordKeyString,\n}\n\n/**\n * Type guard that checks if a value is a valid TID string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid TID string\n */\nexport const isTidString: CheckFn<TidString> = isValidTid\nexport type {\n /**\n * A Timestamp Identifier (TID) string.\n *\n * TIDs are time-based identifiers used for record keys.\n *\n * @example `\"3k2...\"`\n */\n TidString,\n}\n\n/**\n * Type guard that checks if a value is a valid URI string.\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid URI string\n */\nexport const isUriString: CheckFn<UriString> = isValidUri\nexport type {\n /**\n * A standard URI string.\n *\n * @example `\"https://example.com/path\"`\n */\n UriString,\n}\n\n// -----------------------------------------------------------------------------\n// String format registry\n// -----------------------------------------------------------------------------\n\ntype StringFormats = {\n 'at-identifier': AtIdentifierString\n 'at-uri': AtUriString\n cid: CidString\n datetime: DatetimeString\n did: DidString\n handle: HandleString\n language: LanguageString\n nsid: NsidString\n 'record-key': RecordKeyString\n tid: TidString\n uri: UriString\n}\n\n/**\n * Union type of all valid string format names.\n */\nexport type StringFormat = Extract<keyof StringFormats, string>\n\nconst stringFormatVerifiers: {\n readonly [K in StringFormat]: readonly [\n strict: CheckFn<StringFormats[K]>,\n lenient?: CheckFn<StringFormats[K]>,\n ]\n} = /*#__PURE__*/ Object.freeze({\n __proto__: null,\n\n 'at-identifier': [isAtIdentifierString],\n 'at-uri': [isAtUriString, isAtUriStringLenient],\n cid: [isCidString],\n datetime: [isDatetimeString, isDatetimeStringLenient],\n did: [isDidString],\n handle: [isHandleString],\n language: [isLanguageString],\n nsid: [isNsidString],\n 'record-key': [isRecordKeyString],\n tid: [isTidString],\n uri: [isUriString],\n})\n\nexport type StringFormatValidationOptions = {\n /**\n * Allows to be more lenient in validation by using a \"lenient\" verification\n * function, if available. The behavior of the lenient verifier depends on the\n * specific format, but generally it may allow for a wider range of valid\n * inputs, including values that are not compliant with the AT Protocol\n * specification.\n *\n * @default true\n */\n strict?: boolean\n}\n\n/**\n * Infers the string type for a given format name.\n *\n * @typeParam F - The format name\n *\n * @example\n * ```typescript\n * type Did = InferStringFormat<'did'>\n * // Result: DidString\n * ```\n */\nexport type InferStringFormat<F extends StringFormat> = F extends StringFormat\n ? StringFormats[F]\n : never\n\n/**\n * Type guard that checks if a string matches a specific format.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to check\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @returns `true` if the string matches the format\n *\n * @example\n * ```typescript\n * const value: string = 'did:plc:1234...'\n * if (isStringFormat(value, 'did')) {\n * // value is typed as DidString\n * console.log('Valid DID:', value)\n * }\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): input is I & StringFormats[F] {\n const formatVerifier = stringFormatVerifiers[format]\n // Fool-proof\n if (!formatVerifier) throw new TypeError(`Unknown string format: ${format}`)\n\n const check: CheckFn<StringFormats[F]> =\n options?.strict === false && formatVerifier.length > 1\n ? formatVerifier[1]!\n : formatVerifier[0]\n\n return check(input)\n}\n\n/**\n * Asserts that a string matches a specific format, throwing if invalid.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to check\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @throws {TypeError} If the string doesn't match the format\n *\n * @example\n * ```typescript\n * assertStringFormat(value, 'handle')\n * // value is now typed as HandleString\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function assertStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): asserts input is I & StringFormats[F] {\n if (!isStringFormat(input, format, options)) {\n throw new TypeError(`Invalid string format (${format}): ${input}`)\n }\n}\n\n/**\n * Validates and returns a string as the specified format type, throwing if invalid.\n *\n * This is useful when you need to convert a string to a format type in an expression.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to validate against\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @returns The input typed as the format type\n * @throws {TypeError} If the string doesn't match the format\n *\n * @example\n * ```typescript\n * const did = asStringFormat(userInput, 'did')\n * // did is typed as DidString\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function asStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): I & StringFormats[F] {\n assertStringFormat(input, format, options)\n return input\n}\n\n/**\n * Returns the string as the format type if valid, otherwise returns `undefined`.\n *\n * This is useful for optional validation where you want to handle invalid values\n * without throwing.\n *\n * @typeParam I - The input string type\n * @typeParam F - The format to validate against\n * @param input - The string to validate\n * @param format - The format name to validate against\n * @returns The typed string if valid, otherwise `undefined`\n *\n * @example\n * ```typescript\n * const did = ifStringFormat(maybeInvalid, 'did')\n * if (did) {\n * // did is typed as DidString\n * }\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function ifStringFormat<I extends string, F extends StringFormat>(\n input: I,\n format: F,\n options?: StringFormatValidationOptions,\n): undefined | (I & StringFormats[F]) {\n return isStringFormat(input, format, options) ? input : undefined\n}\n\n/**\n * Array of all valid string format names.\n *\n * @example\n * ```typescript\n * for (const format of STRING_FORMATS) {\n * console.log(format) // 'at-identifier', 'at-uri', 'cid', ...\n * }\n * ```\n */\nexport const STRING_FORMATS = /*#__PURE__*/ Object.freeze(\n /*#__PURE__*/ Object.keys(stringFormatVerifiers),\n) as readonly StringFormat[]\n"]}
|
package/dist/schema/blob.d.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import { BlobRef, LegacyBlobRef, isBlobRef, isLegacyBlobRef } from '@atproto/lex-data';
|
|
1
|
+
import { BlobRef, LegacyBlobRef, TypedBlobRef, isBlobRef, isLegacyBlobRef, isTypedBlobRef } from '@atproto/lex-data';
|
|
2
2
|
import { Schema, ValidationContext } from '../core.js';
|
|
3
3
|
/**
|
|
4
4
|
* Configuration options for blob schema validation.
|
|
5
5
|
*/
|
|
6
6
|
export type BlobSchemaOptions = {
|
|
7
|
-
/**
|
|
8
|
-
* Whether to allow legacy blob references format
|
|
9
|
-
*
|
|
10
|
-
* @default false
|
|
11
|
-
* @see {@link LegacyBlobRef}
|
|
12
|
-
*/
|
|
13
|
-
allowLegacy?: boolean;
|
|
14
7
|
/**
|
|
15
8
|
* List of accepted MIME types (supports wildcards like 'image/*' or '*\/*')
|
|
16
9
|
*
|
|
@@ -24,8 +17,8 @@ export type BlobSchemaOptions = {
|
|
|
24
17
|
*/
|
|
25
18
|
maxSize?: number;
|
|
26
19
|
};
|
|
27
|
-
export type { BlobRef, LegacyBlobRef };
|
|
28
|
-
export { isBlobRef, isLegacyBlobRef };
|
|
20
|
+
export type { BlobRef, LegacyBlobRef, TypedBlobRef };
|
|
21
|
+
export { isBlobRef, isLegacyBlobRef, isTypedBlobRef };
|
|
29
22
|
/**
|
|
30
23
|
* Schema for validating blob references in AT Protocol.
|
|
31
24
|
*
|
|
@@ -41,13 +34,11 @@ export { isBlobRef, isLegacyBlobRef };
|
|
|
41
34
|
* const result = schema.validate(blobRef)
|
|
42
35
|
* ```
|
|
43
36
|
*/
|
|
44
|
-
export declare class BlobSchema<const TOptions extends BlobSchemaOptions = NonNullable<unknown>> extends Schema<
|
|
45
|
-
allowLegacy: true;
|
|
46
|
-
} ? BlobRef | LegacyBlobRef : BlobRef> {
|
|
37
|
+
export declare class BlobSchema<const TOptions extends BlobSchemaOptions = NonNullable<unknown>> extends Schema<BlobRef> {
|
|
47
38
|
readonly options?: TOptions | undefined;
|
|
48
39
|
readonly type: "blob";
|
|
49
40
|
constructor(options?: TOptions | undefined);
|
|
50
|
-
validateInContext(input: unknown, ctx: ValidationContext): import("../core.js").ValidationResult<
|
|
41
|
+
validateInContext(input: unknown, ctx: ValidationContext): import("../core.js").ValidationResult<BlobRef>;
|
|
51
42
|
matchesMime(mime: string): boolean;
|
|
52
43
|
}
|
|
53
44
|
/**
|
|
@@ -69,12 +60,7 @@ export declare class BlobSchema<const TOptions extends BlobSchemaOptions = NonNu
|
|
|
69
60
|
*
|
|
70
61
|
* // Any image type with size limit
|
|
71
62
|
* const avatarSchema = l.blob({ accept: ['image/*'], maxSize: 1000000 })
|
|
72
|
-
*
|
|
73
|
-
* // Allow legacy format
|
|
74
|
-
* const legacySchema = l.blob({ allowLegacy: true })
|
|
75
63
|
* ```
|
|
76
64
|
*/
|
|
77
|
-
export declare const blob: <O extends BlobSchemaOptions = {
|
|
78
|
-
allowLegacy?: false;
|
|
79
|
-
}>(options?: O) => BlobSchema<O>;
|
|
65
|
+
export declare const blob: <O extends BlobSchemaOptions = {}>(options?: O) => BlobSchema<O>;
|
|
80
66
|
//# sourceMappingURL=blob.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../../src/schema/blob.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,aAAa,EACb,SAAS,EACT,eAAe,
|
|
1
|
+
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../../src/schema/blob.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,aAAa,EACb,YAAY,EAEZ,SAAS,EACT,eAAe,EACf,cAAc,EACf,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGtD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IAEjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,CAAA;AAErD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,UAAU,CACrB,KAAK,CAAC,QAAQ,SAAS,iBAAiB,GAAG,WAAW,CAAC,OAAO,CAAC,CAC/D,SAAQ,MAAM,CAAC,OAAO,CAAC;IAGX,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ;IAFvC,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAS;gBAEV,OAAO,CAAC,EAAE,QAAQ,YAAA;IAIvC,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB;IA8BxD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAKnC;AA+BD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,IAAI,GACf,CAAC,SAAS,iBAAiB,iBACjB,CAAC,kBAEX,CAAA"}
|
package/dist/schema/blob.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.blob = exports.BlobSchema = exports.isLegacyBlobRef = exports.isBlobRef = void 0;
|
|
3
|
+
exports.blob = exports.BlobSchema = exports.isTypedBlobRef = exports.isLegacyBlobRef = exports.isBlobRef = void 0;
|
|
4
4
|
const lex_data_1 = require("@atproto/lex-data");
|
|
5
5
|
Object.defineProperty(exports, "isBlobRef", { enumerable: true, get: function () { return lex_data_1.isBlobRef; } });
|
|
6
6
|
Object.defineProperty(exports, "isLegacyBlobRef", { enumerable: true, get: function () { return lex_data_1.isLegacyBlobRef; } });
|
|
7
|
+
Object.defineProperty(exports, "isTypedBlobRef", { enumerable: true, get: function () { return lex_data_1.isTypedBlobRef; } });
|
|
7
8
|
const core_js_1 = require("../core.js");
|
|
8
9
|
const memoize_js_1 = require("../util/memoize.js");
|
|
9
10
|
/**
|
|
@@ -29,20 +30,28 @@ class BlobSchema extends core_js_1.Schema {
|
|
|
29
30
|
this.options = options;
|
|
30
31
|
}
|
|
31
32
|
validateInContext(input, ctx) {
|
|
32
|
-
const blob = parseValue.call(ctx, input
|
|
33
|
+
const blob = parseValue.call(ctx, input);
|
|
33
34
|
if (!blob) {
|
|
34
35
|
return ctx.issueUnexpectedType(input, 'blob');
|
|
35
36
|
}
|
|
36
37
|
// In non-strict mode, we allow blob refs to pass through without MIME
|
|
37
38
|
// type or size checks.
|
|
38
|
-
if (ctx.options.strict) {
|
|
39
|
-
const accept = this.options
|
|
39
|
+
if (ctx.options.strict && this.options != null) {
|
|
40
|
+
const { accept } = this.options;
|
|
40
41
|
if (accept && !matchesMime(blob.mimeType, accept)) {
|
|
41
42
|
return ctx.issueInvalidPropertyValue(blob, 'mimeType', accept);
|
|
42
43
|
}
|
|
43
|
-
const maxSize = this.options
|
|
44
|
-
if (maxSize != null
|
|
45
|
-
|
|
44
|
+
const { maxSize } = this.options;
|
|
45
|
+
if (maxSize != null) {
|
|
46
|
+
const size = (0, lex_data_1.getBlobSize)(blob);
|
|
47
|
+
if (size === undefined) {
|
|
48
|
+
// Unable to enforce size constraint if size is not available (legacy
|
|
49
|
+
// blob ref), so we treat it as a validation failure in strict mode.
|
|
50
|
+
return ctx.issueInvalidPropertyType(blob, 'size', 'integer');
|
|
51
|
+
}
|
|
52
|
+
else if (size > maxSize) {
|
|
53
|
+
return ctx.issueTooBig(blob, 'blob', maxSize, size);
|
|
54
|
+
}
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
57
|
return ctx.success(blob);
|
|
@@ -55,30 +64,19 @@ class BlobSchema extends core_js_1.Schema {
|
|
|
55
64
|
}
|
|
56
65
|
}
|
|
57
66
|
exports.BlobSchema = BlobSchema;
|
|
58
|
-
function parseValue(input
|
|
59
|
-
// If there is a $type property, we treat if as a potential
|
|
67
|
+
function parseValue(input) {
|
|
68
|
+
// If there is a $type property, we treat if as a potential TypedBlobRef and
|
|
60
69
|
// validate accordingly.
|
|
61
70
|
if (input?.$type !== undefined) {
|
|
62
71
|
// Use the context's option for the "strict" check
|
|
63
|
-
return (0, lex_data_1.
|
|
72
|
+
return (0, lex_data_1.isTypedBlobRef)(input, this.options) ? input : null;
|
|
64
73
|
}
|
|
65
74
|
// If there is no $type property, we may be dealing with a legacy blob ref. If
|
|
66
|
-
// legacy refs are allowed,
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (options?.allowLegacy) {
|
|
71
|
-
if ((0, lex_data_1.isLegacyBlobRef)(input)) {
|
|
75
|
+
// legacy refs are allowed (non-strict mode), we check if the input matches
|
|
76
|
+
// the legacy format.
|
|
77
|
+
if (!this.options.strict) {
|
|
78
|
+
if ((0, lex_data_1.isLegacyBlobRef)(input, this.options))
|
|
72
79
|
return input;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else if (!this.options.strict && this.options.mode === 'parse') {
|
|
76
|
-
if ((0, lex_data_1.isLegacyBlobRef)(input)) {
|
|
77
|
-
const { cid, mimeType } = input;
|
|
78
|
-
const ref = (0, lex_data_1.parseCidSafe)(cid);
|
|
79
|
-
if (ref)
|
|
80
|
-
return { $type: 'blob', ref, mimeType, size: -1 };
|
|
81
|
-
}
|
|
82
80
|
}
|
|
83
81
|
return null;
|
|
84
82
|
}
|
|
@@ -113,9 +111,6 @@ function matchesMime(mime, accepted) {
|
|
|
113
111
|
*
|
|
114
112
|
* // Any image type with size limit
|
|
115
113
|
* const avatarSchema = l.blob({ accept: ['image/*'], maxSize: 1000000 })
|
|
116
|
-
*
|
|
117
|
-
* // Allow legacy format
|
|
118
|
-
* const legacySchema = l.blob({ allowLegacy: true })
|
|
119
114
|
* ```
|
|
120
115
|
*/
|
|
121
116
|
exports.blob = (0, memoize_js_1.memoizedOptions)(function (options) {
|
package/dist/schema/blob.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob.js","sourceRoot":"","sources":["../../src/schema/blob.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"blob.js","sourceRoot":"","sources":["../../src/schema/blob.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BlobRef,\n LegacyBlobRef,\n TypedBlobRef,\n getBlobSize,\n isBlobRef,\n isLegacyBlobRef,\n isTypedBlobRef,\n} from '@atproto/lex-data'\nimport { Schema, ValidationContext } from '../core.js'\nimport { memoizedOptions } from '../util/memoize.js'\n\n/**\n * Configuration options for blob schema validation.\n */\nexport type BlobSchemaOptions = {\n /**\n * List of accepted MIME types (supports wildcards like 'image/*' or '*\\/*')\n *\n * @default undefined // accepts all MIME types\n */\n accept?: string[]\n\n /**\n * Maximum blob size in bytes\n *\n * @default undefined // no size limit\n */\n maxSize?: number\n}\n\nexport type { BlobRef, LegacyBlobRef, TypedBlobRef }\nexport { isBlobRef, isLegacyBlobRef, isTypedBlobRef }\n\n/**\n * Schema for validating blob references in AT Protocol.\n *\n * Validates BlobRef objects which contain a CID reference to binary data,\n * along with metadata like MIME type and size. Can optionally accept\n * legacy blob reference format.\n *\n * @template TOptions - The configuration options type\n *\n * @example\n * ```ts\n * const schema = new BlobSchema({ accept: ['image/*'], maxSize: 1000000 })\n * const result = schema.validate(blobRef)\n * ```\n */\nexport class BlobSchema<\n const TOptions extends BlobSchemaOptions = NonNullable<unknown>,\n> extends Schema<BlobRef> {\n readonly type = 'blob' as const\n\n constructor(readonly options?: TOptions) {\n super()\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n const blob = parseValue.call(ctx, input)\n if (!blob) {\n return ctx.issueUnexpectedType(input, 'blob')\n }\n\n // In non-strict mode, we allow blob refs to pass through without MIME\n // type or size checks.\n if (ctx.options.strict && this.options != null) {\n const { accept } = this.options\n if (accept && !matchesMime(blob.mimeType, accept)) {\n return ctx.issueInvalidPropertyValue(blob, 'mimeType', accept)\n }\n\n const { maxSize } = this.options\n if (maxSize != null) {\n const size = getBlobSize(blob)\n if (size === undefined) {\n // Unable to enforce size constraint if size is not available (legacy\n // blob ref), so we treat it as a validation failure in strict mode.\n return ctx.issueInvalidPropertyType(blob, 'size' as any, 'integer')\n } else if (size > maxSize) {\n return ctx.issueTooBig(blob, 'blob', maxSize, size)\n }\n }\n }\n\n return ctx.success(blob)\n }\n\n matchesMime(mime: string): boolean {\n const accept = this.options?.accept\n if (!accept) return true\n return matchesMime(mime, accept)\n }\n}\n\nfunction parseValue(this: ValidationContext, input: unknown): BlobRef | null {\n // If there is a $type property, we treat if as a potential TypedBlobRef and\n // validate accordingly.\n if ((input as any)?.$type !== undefined) {\n // Use the context's option for the \"strict\" check\n return isTypedBlobRef(input, this.options) ? input : null\n }\n\n // If there is no $type property, we may be dealing with a legacy blob ref. If\n // legacy refs are allowed (non-strict mode), we check if the input matches\n // the legacy format.\n if (!this.options.strict) {\n if (isLegacyBlobRef(input, this.options)) return input\n }\n\n return null\n}\n\nfunction matchesMime(mime: string, accepted: string[]): boolean {\n if (accepted.includes('*/*')) return true\n if (accepted.includes(mime)) return true\n for (const value of accepted) {\n if (value.endsWith('/*') && mime.startsWith(value.slice(0, -1))) {\n return true\n }\n }\n return false\n}\n\n/**\n * Creates a blob schema for validating blob references with optional constraints.\n *\n * Blob references are used in AT Protocol to reference binary data stored\n * separately from records. They contain a CID, MIME type, and size information.\n *\n * @param options - Optional configuration for MIME type filtering and size limits\n * @returns A new {@link BlobSchema} instance\n *\n * @example\n * ```ts\n * // Basic blob reference\n * const fileSchema = l.blob()\n *\n * // Image files only\n * const imageSchema = l.blob({ accept: ['image/png', 'image/jpeg', 'image/gif'] })\n *\n * // Any image type with size limit\n * const avatarSchema = l.blob({ accept: ['image/*'], maxSize: 1000000 })\n * ```\n */\nexport const blob = /*#__PURE__*/ memoizedOptions(function <\n O extends BlobSchemaOptions = NonNullable<unknown>,\n>(options?: O) {\n return new BlobSchema(options)\n})\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lex-schema",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Lexicon schema system for AT Lexicons",
|
|
6
6
|
"keywords": [
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"@standard-schema/spec": "^1.1.0",
|
|
39
39
|
"iso-datestring-validator": "^2.2.2",
|
|
40
40
|
"tslib": "^2.8.1",
|
|
41
|
-
"@atproto/syntax": "^0.5.
|
|
42
|
-
"@atproto/lex-data": "^0.0.
|
|
41
|
+
"@atproto/syntax": "^0.5.4",
|
|
42
|
+
"@atproto/lex-data": "^0.0.15"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"vitest": "^4.0.16"
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
TidString,
|
|
12
12
|
UriString,
|
|
13
13
|
isAtIdentifierString,
|
|
14
|
+
isAtUriString,
|
|
14
15
|
isDatetimeString,
|
|
15
|
-
isValidAtUri,
|
|
16
16
|
isValidDid,
|
|
17
17
|
isValidHandle,
|
|
18
18
|
isValidLanguage,
|
|
@@ -35,6 +35,7 @@ import { CheckFn } from '../util/assertion-util.js'
|
|
|
35
35
|
export {
|
|
36
36
|
type AtIdentifierString,
|
|
37
37
|
asAtIdentifierString,
|
|
38
|
+
assertAtIdentifierString,
|
|
38
39
|
ifAtIdentifierString,
|
|
39
40
|
isAtIdentifierString,
|
|
40
41
|
} from '@atproto/syntax'
|
|
@@ -45,6 +46,7 @@ export { isDidIdentifier, isHandleIdentifier } from '@atproto/syntax'
|
|
|
45
46
|
export {
|
|
46
47
|
type DatetimeString,
|
|
47
48
|
asDatetimeString,
|
|
49
|
+
assertDatetimeString,
|
|
48
50
|
ifDatetimeString,
|
|
49
51
|
isDatetimeString,
|
|
50
52
|
} from '@atproto/syntax'
|
|
@@ -54,7 +56,7 @@ export {
|
|
|
54
56
|
* the strict {@link isDatetimeString} guard, which only allows datetimes that
|
|
55
57
|
* fully conform to the AT Protocol specification (e.g. must include timezone).
|
|
56
58
|
*/
|
|
57
|
-
export function
|
|
59
|
+
export function isDatetimeStringLenient<I>(
|
|
58
60
|
input: I,
|
|
59
61
|
): input is I & DatetimeString {
|
|
60
62
|
// @NOTE the returned type assertion is inaccurate wrt. the DatetimeString
|
|
@@ -72,20 +74,22 @@ export function isDatetimeStringLoose<I>(
|
|
|
72
74
|
// DatetimeString utilities
|
|
73
75
|
export { currentDatetimeString, toDatetimeString } from '@atproto/syntax'
|
|
74
76
|
|
|
77
|
+
export {
|
|
78
|
+
type AtUriString,
|
|
79
|
+
asAtUriString,
|
|
80
|
+
assertAtUriString,
|
|
81
|
+
ifAtUriString,
|
|
82
|
+
isAtUriString,
|
|
83
|
+
} from '@atproto/syntax'
|
|
84
|
+
|
|
75
85
|
/**
|
|
76
|
-
*
|
|
86
|
+
* Lenient version of {@link isAtUriString} that does not enforce the validity
|
|
87
|
+
* of the record key (rkey) path component (if present).
|
|
77
88
|
*
|
|
78
|
-
* @
|
|
79
|
-
* @returns `true` if the value is a valid AT URI
|
|
89
|
+
* @see {@link isAtUriString}
|
|
80
90
|
*/
|
|
81
|
-
export
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* An AT URI string pointing to a resource in the AT Protocol network.
|
|
85
|
-
*
|
|
86
|
-
* @example `"at://did:plc:1234.../app.bsky.feed.post/3k2..."`
|
|
87
|
-
*/
|
|
88
|
-
AtUriString,
|
|
91
|
+
export function isAtUriStringLenient<I>(input: I): input is I & AtUriString {
|
|
92
|
+
return isAtUriString(input, { strict: false })
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/**
|
|
@@ -246,15 +250,15 @@ export type StringFormat = Extract<keyof StringFormats, string>
|
|
|
246
250
|
const stringFormatVerifiers: {
|
|
247
251
|
readonly [K in StringFormat]: readonly [
|
|
248
252
|
strict: CheckFn<StringFormats[K]>,
|
|
249
|
-
|
|
253
|
+
lenient?: CheckFn<StringFormats[K]>,
|
|
250
254
|
]
|
|
251
255
|
} = /*#__PURE__*/ Object.freeze({
|
|
252
256
|
__proto__: null,
|
|
253
257
|
|
|
254
258
|
'at-identifier': [isAtIdentifierString],
|
|
255
|
-
'at-uri': [isAtUriString],
|
|
259
|
+
'at-uri': [isAtUriString, isAtUriStringLenient],
|
|
256
260
|
cid: [isCidString],
|
|
257
|
-
datetime: [isDatetimeString,
|
|
261
|
+
datetime: [isDatetimeString, isDatetimeStringLenient],
|
|
258
262
|
did: [isDidString],
|
|
259
263
|
handle: [isHandleString],
|
|
260
264
|
language: [isLanguageString],
|
|
@@ -266,8 +270,8 @@ const stringFormatVerifiers: {
|
|
|
266
270
|
|
|
267
271
|
export type StringFormatValidationOptions = {
|
|
268
272
|
/**
|
|
269
|
-
* Allows to be more lenient in validation by using a "
|
|
270
|
-
* function, if available. The behavior of the
|
|
273
|
+
* Allows to be more lenient in validation by using a "lenient" verification
|
|
274
|
+
* function, if available. The behavior of the lenient verifier depends on the
|
|
271
275
|
* specific format, but generally it may allow for a wider range of valid
|
|
272
276
|
* inputs, including values that are not compliant with the AT Protocol
|
|
273
277
|
* specification.
|
|
@@ -321,8 +325,8 @@ export function isStringFormat<I extends string, F extends StringFormat>(
|
|
|
321
325
|
if (!formatVerifier) throw new TypeError(`Unknown string format: ${format}`)
|
|
322
326
|
|
|
323
327
|
const check: CheckFn<StringFormats[F]> =
|
|
324
|
-
options?.strict === false
|
|
325
|
-
? formatVerifier[1]
|
|
328
|
+
options?.strict === false && formatVerifier.length > 1
|
|
329
|
+
? formatVerifier[1]!
|
|
326
330
|
: formatVerifier[0]
|
|
327
331
|
|
|
328
332
|
return check(input)
|