@atproto/lex-data 0.0.14 → 0.1.0-next.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/CHANGELOG.md +28 -0
- package/dist/blob.d.ts +118 -39
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js +68 -22
- package/dist/blob.js.map +1 -1
- package/dist/cid.d.ts.map +1 -1
- package/dist/cid.js +75 -79
- package/dist/cid.js.map +1 -1
- package/dist/index.js +8 -11
- package/dist/index.js.map +1 -1
- package/dist/lex-equals.js +9 -12
- package/dist/lex-equals.js.map +1 -1
- package/dist/lex-error.js +2 -7
- package/dist/lex-error.js.map +1 -1
- package/dist/lex.js +10 -17
- package/dist/lex.js.map +1 -1
- package/dist/lib/nodejs-buffer.d.ts +4 -0
- package/dist/lib/nodejs-buffer.d.ts.map +1 -1
- package/dist/lib/nodejs-buffer.js +1 -4
- package/dist/lib/nodejs-buffer.js.map +1 -1
- package/dist/lib/util.js +2 -6
- package/dist/lib/util.js.map +1 -1
- package/dist/object.js +3 -8
- package/dist/object.js.map +1 -1
- package/dist/uint8array-base64.js +1 -2
- package/dist/uint8array-concat.d.ts +2 -2
- package/dist/uint8array-concat.d.ts.map +1 -1
- package/dist/uint8array-concat.js +4 -8
- package/dist/uint8array-concat.js.map +1 -1
- package/dist/uint8array-from-base64.js +7 -11
- package/dist/uint8array-from-base64.js.map +1 -1
- package/dist/uint8array-to-base64.js +7 -11
- package/dist/uint8array-to-base64.js.map +1 -1
- package/dist/uint8array.d.ts +1 -1
- package/dist/uint8array.d.ts.map +1 -1
- package/dist/uint8array.js +17 -23
- package/dist/uint8array.js.map +1 -1
- package/dist/utf8-from-base64.js +6 -10
- package/dist/utf8-from-base64.js.map +1 -1
- package/dist/utf8-from-bytes.d.ts +3 -0
- package/dist/utf8-from-bytes.d.ts.map +1 -0
- package/dist/utf8-from-bytes.js +15 -0
- package/dist/utf8-from-bytes.js.map +1 -0
- package/dist/utf8-grapheme-len.js +4 -8
- package/dist/utf8-grapheme-len.js.map +1 -1
- package/dist/utf8-len.js +4 -8
- package/dist/utf8-len.js.map +1 -1
- package/dist/utf8-to-base64.js +8 -12
- package/dist/utf8-to-base64.js.map +1 -1
- package/dist/utf8.d.ts +18 -0
- package/dist/utf8.d.ts.map +1 -1
- package/dist/utf8.js +32 -16
- package/dist/utf8.js.map +1 -1
- package/package.json +7 -8
- package/src/blob.test.ts +38 -25
- package/src/blob.ts +190 -52
- package/src/cid-implementation.test.ts +3 -3
- package/src/cid.ts +1 -0
- package/src/core-js.d.ts +2 -0
- package/src/lib/nodejs-buffer.ts +10 -0
- package/src/uint8array-concat.ts +7 -3
- package/src/uint8array-from-base64.test.ts +2 -2
- package/src/uint8array-to-base64.test.ts +2 -2
- package/src/uint8array.test.ts +2 -2
- package/src/utf8-from-bytes.test.ts +43 -0
- package/src/utf8-from-bytes.ts +21 -0
- package/src/utf8.ts +20 -0
- package/tsconfig.tests.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @atproto/lex-data
|
|
2
2
|
|
|
3
|
+
## 0.1.0-next.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4929](https://github.com/bluesky-social/atproto/pull/4929) [`bb7491c`](https://github.com/bluesky-social/atproto/commit/bb7491c29e06181e1d2f8cf6eb454f9bb8ab961b) Thanks [@devinivy](https://github.com/devinivy)! - **BREAKING:** Drop support for Node.js 18 and 20. Node.js 22 is now the minimum supported version. Docker images now use Node.js 24.
|
|
8
|
+
|
|
9
|
+
- [#4943](https://github.com/bluesky-social/atproto/pull/4943) [`07ae5d4`](https://github.com/bluesky-social/atproto/commit/07ae5d4452df51e045e0239da7a04cf0bc154028) Thanks [@devinivy](https://github.com/devinivy)! - **BREAKING:** Convert to pure ESM. All packages now ship `"type": "module"` with ES module output and Node16 module resolution.
|
|
10
|
+
|
|
11
|
+
Node.js 22's `require()` compatibility layer can still load these packages in CommonJS code.
|
|
12
|
+
|
|
13
|
+
- [#4930](https://github.com/bluesky-social/atproto/pull/4930) [`042df15`](https://github.com/bluesky-social/atproto/commit/042df15087c0e62cd1e715fcbf58852fab875af9) Thanks [@devinivy](https://github.com/devinivy)! - Build with TypeScript 6.0. Emitted `.d.ts` files now use TypeScript 6's stricter `Uint8Array<ArrayBuffer>` typing in places where Web/Node APIs require buffer-backed (not shared-memory) byte arrays. Consumers compiling against these types on older TypeScript should see no runtime impact, but may need to widen or cast in spots that previously relied on `Uint8Array` defaulting to `<ArrayBufferLike>`.
|
|
14
|
+
|
|
15
|
+
Internal: tsconfig `moduleResolution: "node"` is silenced via `ignoreDeprecations: "6.0"` for now; the proper migration to `node16`/`bundler` resolution is deferred.
|
|
16
|
+
|
|
17
|
+
## 0.0.15
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#4828](https://github.com/bluesky-social/atproto/pull/4828) [`c62651d`](https://github.com/bluesky-social/atproto/commit/c62651dd69f1e18bd854b66e499b91fee9eaa856) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Export new utility functions for working with `BlobRef`: `getBlobCid`, `getBlobCidString`, `getBlobMime`, and `getBlobSize`.
|
|
22
|
+
|
|
23
|
+
- [#4835](https://github.com/bluesky-social/atproto/pull/4835) [`f6f100c`](https://github.com/bluesky-social/atproto/commit/f6f100c33700a7ff58a1458109cc7420131feed0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add `utf8FromBytes` that decodes a byte array containing a utf-8 string
|
|
24
|
+
|
|
25
|
+
- [#4828](https://github.com/bluesky-social/atproto/pull/4828) [`c62651d`](https://github.com/bluesky-social/atproto/commit/c62651dd69f1e18bd854b66e499b91fee9eaa856) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Defines `BlobRef` as a union of `TypedBlobRef` and `LegacyBlobRef` to allow for seamless handling of both types of blob references.
|
|
26
|
+
|
|
27
|
+
- [#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.
|
|
28
|
+
|
|
29
|
+
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.
|
|
30
|
+
|
|
3
31
|
## 0.0.14
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/blob.d.ts
CHANGED
|
@@ -1,19 +1,114 @@
|
|
|
1
1
|
import { Cid, RawCid } from './cid.js';
|
|
2
2
|
import { LexValue } from './lex.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reference to binary data (like images, videos, etc.) in the AT Protocol data
|
|
5
|
+
* model.
|
|
6
|
+
*
|
|
7
|
+
* This type represents a reference to a blob of binary data, identified by its
|
|
8
|
+
* content hash (CID) and accompanied by metadata such as MIME type and size.
|
|
9
|
+
*
|
|
10
|
+
* The {@link BlobRef} type is a union of the current {@link TypedBlobRef}
|
|
11
|
+
* format and the legacy {@link LegacyBlobRef} format.
|
|
12
|
+
*/
|
|
13
|
+
export type BlobRef<Ref extends Cid = Cid> = TypedBlobRef<Ref> | LegacyBlobRef;
|
|
14
|
+
/**
|
|
15
|
+
* Options for validating a {@link BlobRef}.
|
|
16
|
+
*/
|
|
17
|
+
export type BlobRefCheckOptions = {
|
|
18
|
+
/**
|
|
19
|
+
* If `false`, skips strict CID validation of {@link BlobRef.ref}, allowing
|
|
20
|
+
* any valid CID. Otherwise, validates that the CID is v1, uses the raw
|
|
21
|
+
* multicodec, and has a sha256 multihash.
|
|
22
|
+
*
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
strict?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Type guard to check if a value is a valid {@link BlobRef}, which can be
|
|
29
|
+
* either a {@link TypedBlobRef} or a {@link LegacyBlobRef}. By default, strict
|
|
30
|
+
* CID validation is applied to ensure that the CID in the blob reference is in
|
|
31
|
+
* the expected format for the AT Protocol, but this can be relaxed with the
|
|
32
|
+
* `strict: false` option.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isBlobRef(input: unknown): input is BlobRef<RawCid>;
|
|
35
|
+
export declare function isBlobRef<TOptions extends BlobRefCheckOptions>(input: unknown, options: TOptions): input is LegacyBlobRef | InferTypedBlobRef<TOptions>;
|
|
36
|
+
export declare function isBlobRef(input: unknown, options?: BlobRefCheckOptions): input is BlobRef<RawCid>;
|
|
37
|
+
/**
|
|
38
|
+
* Extracts the MIME type from a {@link BlobRef}.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const mimeType = getBlobMime(blobRef)
|
|
43
|
+
* console.log(mimeType) // e.g., 'image/jpeg'
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function getBlobMime(blob: BlobRef): string;
|
|
47
|
+
export declare function getBlobMime(blob?: BlobRef): string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Extracts the size (in bytes) from a {@link TypedBlobRef}. For
|
|
50
|
+
* {@link LegacyBlobRef}, size information is not available, so this function
|
|
51
|
+
* returns `undefined` for legacy refs.
|
|
52
|
+
*
|
|
53
|
+
* @note The size property, in blob refs, cannot be 100% trusted since the PDS
|
|
54
|
+
* might not have a local copy of the blob (to check the size against) and might
|
|
55
|
+
* just be passing through the blob ref from the client without validating it.
|
|
56
|
+
* So, while this function can be useful for getting size information when
|
|
57
|
+
* available, it should not be solely relied upon for critical functionality
|
|
58
|
+
* without additional validation.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* const size = getBlobSize(blobRef)
|
|
63
|
+
* if (size !== undefined) {
|
|
64
|
+
* console.log(`Blob size: ${size} bytes`)
|
|
65
|
+
* } else {
|
|
66
|
+
* console.log('Size information not available for legacy blob ref')
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function getBlobSize(blob: BlobRef): number | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Extracts the {@link Cid} from a {@link BlobRef}.
|
|
73
|
+
*
|
|
74
|
+
* @throws If the input input is a {@link LegacyBlobRef} with an invalid CID string
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const cid = getBlobCid(blobRef)
|
|
78
|
+
* console.log(cid.bytes)
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function getBlobCid(blob: BlobRef): Cid;
|
|
82
|
+
export declare function getBlobCid(blob?: BlobRef): Cid | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Extracts the CID string from a {@link BlobRef}.
|
|
85
|
+
*
|
|
86
|
+
* This is similar to `getBlobCid(blob).toString()` but is more optimized since
|
|
87
|
+
* the CID string is already available in the legacy format and we can avoid
|
|
88
|
+
* parsing it into a CID object just to convert it back to a string.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const cidString = getBlobCidString(blobRef)
|
|
93
|
+
* console.log(cidString)
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function getBlobCidString(blob: BlobRef): string;
|
|
97
|
+
export declare function getBlobCidString(blob?: BlobRef): string | undefined;
|
|
3
98
|
/**
|
|
4
99
|
* Reference to binary data (like images, videos, etc.) in the AT Protocol data model.
|
|
5
100
|
*
|
|
6
|
-
* A
|
|
7
|
-
* content by its content hash (CID), along with metadata
|
|
8
|
-
* and size.
|
|
101
|
+
* A {@link TypedBlobRef} is a {@link LexMap} with a specific structure that
|
|
102
|
+
* identifies binary content by its content hash (CID), along with metadata
|
|
103
|
+
* about the content type and size.
|
|
9
104
|
*
|
|
10
105
|
* @typeParam Ref - The type of CID reference, defaults to any {@link Cid}
|
|
11
106
|
*
|
|
12
107
|
* @example
|
|
13
108
|
* ```typescript
|
|
14
|
-
* import type {
|
|
109
|
+
* import type { TypedBlobRef } from '@atproto/lex-data'
|
|
15
110
|
*
|
|
16
|
-
* const imageRef:
|
|
111
|
+
* const imageRef: TypedBlobRef = {
|
|
17
112
|
* $type: 'blob',
|
|
18
113
|
* mimeType: 'image/jpeg',
|
|
19
114
|
* ref: cid, // CID of the blob content
|
|
@@ -21,38 +116,25 @@ import { LexValue } from './lex.js';
|
|
|
21
116
|
* }
|
|
22
117
|
* ```
|
|
23
118
|
*
|
|
24
|
-
* @see {@link
|
|
119
|
+
* @see {@link isTypedBlobRef} to check if a value is a valid {@link TypedBlobRef}
|
|
25
120
|
* @see {@link LegacyBlobRef} for the older blob reference format
|
|
26
121
|
*/
|
|
27
|
-
export type
|
|
122
|
+
export type TypedBlobRef<Ref extends Cid = Cid> = {
|
|
28
123
|
$type: 'blob';
|
|
29
124
|
mimeType: string;
|
|
30
125
|
ref: Ref;
|
|
31
126
|
size: number;
|
|
32
127
|
};
|
|
33
|
-
/**
|
|
34
|
-
* Options for validating a {@link BlobRef}.
|
|
35
|
-
*/
|
|
36
|
-
export type BlobRefCheckOptions = {
|
|
37
|
-
/**
|
|
38
|
-
* If `false`, skips strict CID validation of {@link BlobRef.ref}, allowing
|
|
39
|
-
* any valid CID. Otherwise, validates that the CID is v1, uses the raw
|
|
40
|
-
* multicodec, and has a sha256 multihash.
|
|
41
|
-
*
|
|
42
|
-
* @default true
|
|
43
|
-
*/
|
|
44
|
-
strict?: boolean;
|
|
45
|
-
};
|
|
46
128
|
/**
|
|
47
129
|
* Infers the BlobRef type based on the check options.
|
|
48
130
|
*
|
|
49
131
|
* @typeParam TOptions - The options used for checking
|
|
50
132
|
*/
|
|
51
|
-
export type
|
|
133
|
+
export type InferTypedBlobRef<TOptions extends BlobRefCheckOptions> = TOptions extends {
|
|
52
134
|
strict: false;
|
|
53
|
-
} ?
|
|
135
|
+
} ? TypedBlobRef : {
|
|
54
136
|
strict: boolean;
|
|
55
|
-
} extends TOptions ?
|
|
137
|
+
} extends TOptions ? TypedBlobRef : TypedBlobRef<RawCid>;
|
|
56
138
|
/**
|
|
57
139
|
* Type guard to check if a value is a valid {@link BlobRef}.
|
|
58
140
|
*
|
|
@@ -68,22 +150,22 @@ export type InferCheckedBlobRef<TOptions extends BlobRefCheckOptions> = TOptions
|
|
|
68
150
|
*
|
|
69
151
|
* @example
|
|
70
152
|
* ```typescript
|
|
71
|
-
* import {
|
|
153
|
+
* import { isTypedBlobRef } from '@atproto/lex-data'
|
|
72
154
|
*
|
|
73
|
-
* if (
|
|
155
|
+
* if (isTypedBlobRef(data)) {
|
|
74
156
|
* console.log(data.mimeType) // e.g., 'image/jpeg'
|
|
75
157
|
* console.log(data.size) // e.g., 12345
|
|
76
158
|
* }
|
|
77
159
|
*
|
|
78
160
|
* // Allow any valid CID (not just raw CIDs)
|
|
79
|
-
* if (
|
|
161
|
+
* if (isTypedBlobRef(data, { strict: false })) {
|
|
80
162
|
* // ...
|
|
81
163
|
* }
|
|
82
164
|
* ```
|
|
83
165
|
*/
|
|
84
|
-
export declare function
|
|
85
|
-
export declare function
|
|
86
|
-
export declare function
|
|
166
|
+
export declare function isTypedBlobRef(input: unknown): input is TypedBlobRef<RawCid>;
|
|
167
|
+
export declare function isTypedBlobRef<TOptions extends BlobRefCheckOptions>(input: unknown, options: TOptions): input is InferTypedBlobRef<TOptions>;
|
|
168
|
+
export declare function isTypedBlobRef(input: unknown, options?: BlobRefCheckOptions): input is TypedBlobRef<RawCid>;
|
|
87
169
|
/**
|
|
88
170
|
* Legacy format for blob references used in older AT Protocol data.
|
|
89
171
|
*
|
|
@@ -116,9 +198,6 @@ export type LegacyBlobRef = {
|
|
|
116
198
|
* - `mimeType` must be a non-empty string
|
|
117
199
|
* - No additional properties allowed
|
|
118
200
|
*
|
|
119
|
-
* @param input - The value to check
|
|
120
|
-
* @returns `true` if the input is a valid LegacyBlobRef
|
|
121
|
-
*
|
|
122
201
|
* @example
|
|
123
202
|
* ```typescript
|
|
124
203
|
* import { isLegacyBlobRef } from '@atproto/lex-data'
|
|
@@ -129,9 +208,9 @@ export type LegacyBlobRef = {
|
|
|
129
208
|
* }
|
|
130
209
|
* ```
|
|
131
210
|
*
|
|
132
|
-
* @see {@link
|
|
211
|
+
* @see {@link isTypedBlobRef} for checking the current blob reference format
|
|
133
212
|
*/
|
|
134
|
-
export declare function isLegacyBlobRef(input: unknown): input is LegacyBlobRef;
|
|
213
|
+
export declare function isLegacyBlobRef(input: unknown, options?: BlobRefCheckOptions): input is LegacyBlobRef;
|
|
135
214
|
/**
|
|
136
215
|
* Options for enumerating blob references within a {@link LexValue}.
|
|
137
216
|
*/
|
|
@@ -151,9 +230,9 @@ export type EnumBlobRefsOptions = BlobRefCheckOptions & {
|
|
|
151
230
|
*/
|
|
152
231
|
export type InferEnumBlobRefs<TOptions extends EnumBlobRefsOptions> = TOptions extends {
|
|
153
232
|
allowLegacy: true;
|
|
154
|
-
} ?
|
|
233
|
+
} ? InferTypedBlobRef<TOptions> | LegacyBlobRef : {
|
|
155
234
|
allowLegacy: boolean;
|
|
156
|
-
} extends TOptions ?
|
|
235
|
+
} extends TOptions ? InferTypedBlobRef<TOptions> | LegacyBlobRef : InferTypedBlobRef<TOptions>;
|
|
157
236
|
/**
|
|
158
237
|
* Generator that enumerates all {@link BlobRef}s (and, optionally,
|
|
159
238
|
* {@link LegacyBlobRef}s) found within a {@link LexValue}.
|
|
@@ -182,12 +261,12 @@ export type InferEnumBlobRefs<TOptions extends EnumBlobRefsOptions> = TOptions e
|
|
|
182
261
|
* }
|
|
183
262
|
*
|
|
184
263
|
* // Include legacy blob references
|
|
185
|
-
* for (const ref of enumBlobRefs(record, { allowLegacy: true })) {
|
|
186
|
-
* // ref may be BlobRef or LegacyBlobRef
|
|
264
|
+
* for (const ref of enumBlobRefs(record, { allowLegacy: true, strict: false })) {
|
|
265
|
+
* // ref may be BlobRef or LegacyBlobRef, with relaxed CID validation
|
|
187
266
|
* }
|
|
188
267
|
* ```
|
|
189
268
|
*/
|
|
190
269
|
export declare function enumBlobRefs(input: LexValue): Generator<BlobRef<RawCid>, void, unknown>;
|
|
191
270
|
export declare function enumBlobRefs<TOptions extends EnumBlobRefsOptions>(input: LexValue, options: TOptions): Generator<InferEnumBlobRefs<TOptions>, void, unknown>;
|
|
192
|
-
export declare function enumBlobRefs(input: LexValue, options?: EnumBlobRefsOptions): Generator<BlobRef
|
|
271
|
+
export declare function enumBlobRefs(input: LexValue, options?: EnumBlobRefsOptions): Generator<BlobRef, void, unknown>;
|
|
193
272
|
//# sourceMappingURL=blob.d.ts.map
|
package/dist/blob.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"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"}
|
package/dist/blob.js
CHANGED
|
@@ -1,15 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { ifCid, parseCid, validateCidString, } from './cid.js';
|
|
2
|
+
import { isPlainObject, isPlainProto } from './object.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options to use with {@link ifCid}, {@link validateCidString}, and related CID
|
|
5
|
+
* validation functions when validating CIDs in BlobRefs, in strict mode. This
|
|
6
|
+
* ensures that the CID is a {@link RawCid} (CID v1, raw multicodec, sha256
|
|
7
|
+
* multihash), which is the expected format for blob references in the AT
|
|
8
|
+
* Protocol data model.
|
|
9
|
+
*/
|
|
10
|
+
const STRICT_CID_CHECK_OPTIONS = { flavor: 'raw' };
|
|
8
11
|
// Number.isSafeInteger is actually safe to use with non-number values, so we
|
|
9
12
|
// can use it as a type guard.
|
|
10
13
|
const isSafeInteger = Number.isSafeInteger;
|
|
11
|
-
function isBlobRef(input, options) {
|
|
12
|
-
|
|
14
|
+
export function isBlobRef(input, options) {
|
|
15
|
+
return input?.$type === 'blob'
|
|
16
|
+
? isTypedBlobRef(input, options)
|
|
17
|
+
: isLegacyBlobRef(input, options);
|
|
18
|
+
}
|
|
19
|
+
export function getBlobMime(blob) {
|
|
20
|
+
return blob?.mimeType;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extracts the size (in bytes) from a {@link TypedBlobRef}. For
|
|
24
|
+
* {@link LegacyBlobRef}, size information is not available, so this function
|
|
25
|
+
* returns `undefined` for legacy refs.
|
|
26
|
+
*
|
|
27
|
+
* @note The size property, in blob refs, cannot be 100% trusted since the PDS
|
|
28
|
+
* might not have a local copy of the blob (to check the size against) and might
|
|
29
|
+
* just be passing through the blob ref from the client without validating it.
|
|
30
|
+
* So, while this function can be useful for getting size information when
|
|
31
|
+
* available, it should not be solely relied upon for critical functionality
|
|
32
|
+
* without additional validation.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const size = getBlobSize(blobRef)
|
|
37
|
+
* if (size !== undefined) {
|
|
38
|
+
* console.log(`Blob size: ${size} bytes`)
|
|
39
|
+
* } else {
|
|
40
|
+
* console.log('Size information not available for legacy blob ref')
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function getBlobSize(blob) {
|
|
45
|
+
if ('$type' in blob && blob.size >= 0)
|
|
46
|
+
return blob.size;
|
|
47
|
+
// LegacyBlobRef doesn't have size information
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
export function getBlobCid(blob) {
|
|
51
|
+
if (!blob)
|
|
52
|
+
return undefined;
|
|
53
|
+
return '$type' in blob ? blob.ref : parseCid(blob.cid);
|
|
54
|
+
}
|
|
55
|
+
export function getBlobCidString(blob) {
|
|
56
|
+
if (!blob)
|
|
57
|
+
return undefined;
|
|
58
|
+
return '$type' in blob ? blob.ref.toString() : blob.cid;
|
|
59
|
+
}
|
|
60
|
+
export function isTypedBlobRef(input, options) {
|
|
61
|
+
if (!isPlainObject(input)) {
|
|
13
62
|
return false;
|
|
14
63
|
}
|
|
15
64
|
if (input?.$type !== 'blob') {
|
|
@@ -38,9 +87,9 @@ function isBlobRef(input, options) {
|
|
|
38
87
|
return false;
|
|
39
88
|
}
|
|
40
89
|
}
|
|
41
|
-
const cid =
|
|
90
|
+
const cid = ifCid(ref,
|
|
42
91
|
// Strict unless explicitly disabled
|
|
43
|
-
options?.strict === false ? undefined :
|
|
92
|
+
options?.strict === false ? undefined : STRICT_CID_CHECK_OPTIONS);
|
|
44
93
|
if (!cid) {
|
|
45
94
|
return false;
|
|
46
95
|
}
|
|
@@ -54,9 +103,6 @@ function isBlobRef(input, options) {
|
|
|
54
103
|
* - `mimeType` must be a non-empty string
|
|
55
104
|
* - No additional properties allowed
|
|
56
105
|
*
|
|
57
|
-
* @param input - The value to check
|
|
58
|
-
* @returns `true` if the input is a valid LegacyBlobRef
|
|
59
|
-
*
|
|
60
106
|
* @example
|
|
61
107
|
* ```typescript
|
|
62
108
|
* import { isLegacyBlobRef } from '@atproto/lex-data'
|
|
@@ -67,10 +113,10 @@ function isBlobRef(input, options) {
|
|
|
67
113
|
* }
|
|
68
114
|
* ```
|
|
69
115
|
*
|
|
70
|
-
* @see {@link
|
|
116
|
+
* @see {@link isTypedBlobRef} for checking the current blob reference format
|
|
71
117
|
*/
|
|
72
|
-
function isLegacyBlobRef(input) {
|
|
73
|
-
if (!
|
|
118
|
+
export function isLegacyBlobRef(input, options) {
|
|
119
|
+
if (!isPlainObject(input)) {
|
|
74
120
|
return false;
|
|
75
121
|
}
|
|
76
122
|
const { cid, mimeType } = input;
|
|
@@ -85,12 +131,12 @@ function isLegacyBlobRef(input) {
|
|
|
85
131
|
return false;
|
|
86
132
|
}
|
|
87
133
|
}
|
|
88
|
-
if (!(
|
|
134
|
+
if (!validateCidString(cid, options?.strict === false ? undefined : STRICT_CID_CHECK_OPTIONS)) {
|
|
89
135
|
return false;
|
|
90
136
|
}
|
|
91
137
|
return true;
|
|
92
138
|
}
|
|
93
|
-
function* enumBlobRefs(input, options) {
|
|
139
|
+
export function* enumBlobRefs(input, options) {
|
|
94
140
|
// LegacyBlobRef not included by default
|
|
95
141
|
const includeLegacy = options?.allowLegacy === true;
|
|
96
142
|
// Using a stack to avoid recursion depth issues.
|
|
@@ -108,14 +154,14 @@ function* enumBlobRefs(input, options) {
|
|
|
108
154
|
visited.add(value);
|
|
109
155
|
stack.push(...value);
|
|
110
156
|
}
|
|
111
|
-
else if (
|
|
157
|
+
else if (isPlainProto(value)) {
|
|
112
158
|
if (visited.has(value))
|
|
113
159
|
continue;
|
|
114
160
|
visited.add(value);
|
|
115
|
-
if (
|
|
161
|
+
if (isTypedBlobRef(value, options)) {
|
|
116
162
|
yield value;
|
|
117
163
|
}
|
|
118
|
-
else if (includeLegacy && isLegacyBlobRef(value)) {
|
|
164
|
+
else if (includeLegacy && isLegacyBlobRef(value, options)) {
|
|
119
165
|
yield value;
|
|
120
166
|
}
|
|
121
167
|
else {
|
package/dist/blob.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob.js","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"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","sourcesContent":["import { Cid, RawCid, ifCid, validateCidString } from './cid.js'\nimport { LexValue } from './lex.js'\nimport { isPlainObject, isPlainProto } from './object.js'\n\n// Number.isSafeInteger is actually safe to use with non-number values, so we\n// can use it as a type guard.\nconst isSafeInteger = Number.isSafeInteger as (v: unknown) => v is number\n\n/**\n * Reference to binary data (like images, videos, etc.) in the AT Protocol data model.\n *\n * A BlobRef is a {@link LexMap} with a specific structure that identifies binary\n * content by its content hash (CID), along with metadata about the content type\n * and size.\n *\n * @typeParam Ref - The type of CID reference, defaults to any {@link Cid}\n *\n * @example\n * ```typescript\n * import type { BlobRef } from '@atproto/lex-data'\n *\n * const imageRef: BlobRef = {\n * $type: 'blob',\n * mimeType: 'image/jpeg',\n * ref: cid, // CID of the blob content\n * size: 12345\n * }\n * ```\n *\n * @see {@link isBlobRef} to check if a value is a valid BlobRef\n * @see {@link LegacyBlobRef} for the older blob reference format\n */\nexport type BlobRef<Ref extends Cid = Cid> = {\n $type: 'blob'\n mimeType: string\n ref: Ref\n size: number\n}\n\n/**\n * Options for validating a {@link BlobRef}.\n */\nexport type BlobRefCheckOptions = {\n /**\n * If `false`, skips strict CID validation of {@link BlobRef.ref}, allowing\n * any valid CID. Otherwise, validates that the CID is v1, uses the raw\n * multicodec, and has a sha256 multihash.\n *\n * @default true\n */\n strict?: boolean\n}\n\n/**\n * Infers the BlobRef type based on the check options.\n *\n * @typeParam TOptions - The options used for checking\n */\nexport type InferCheckedBlobRef<TOptions extends BlobRefCheckOptions> =\n TOptions extends { strict: false }\n ? BlobRef\n : { strict: boolean } extends TOptions\n ? BlobRef\n : BlobRef<RawCid>\n\n/**\n * Type guard to check if a value is a valid {@link BlobRef}.\n *\n * Validates the structure of the input including:\n * - `$type` must be `'blob'`\n * - `mimeType` must be a valid MIME type string (containing '/')\n * - `size` must be a non-negative safe integer\n * - `ref` must be a valid CID (strict validation by default)\n *\n * @param input - The value to check\n * @param options - Optional validation options\n * @returns `true` if the input is a valid BlobRef\n *\n * @example\n * ```typescript\n * import { isBlobRef } from '@atproto/lex-data'\n *\n * if (isBlobRef(data)) {\n * console.log(data.mimeType) // e.g., 'image/jpeg'\n * console.log(data.size) // e.g., 12345\n * }\n *\n * // Allow any valid CID (not just raw CIDs)\n * if (isBlobRef(data, { strict: false })) {\n * // ...\n * }\n * ```\n */\nexport function isBlobRef(input: unknown): input is BlobRef<RawCid>\nexport function isBlobRef<TOptions extends BlobRefCheckOptions>(\n input: unknown,\n options: TOptions,\n): input is InferCheckedBlobRef<TOptions>\nexport function isBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is BlobRef\nexport function isBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is BlobRef {\n if (!isPlainObject(input)) {\n return false\n }\n\n if (input?.$type !== 'blob') {\n return false\n }\n\n const { mimeType, size, ref } = input\n // @NOTE Very basic mime validation\n if (typeof mimeType !== 'string' || !mimeType.includes('/')) {\n return false\n }\n\n if (size === -1 && options?.strict === false) {\n // In non-strict mode, allow size to be -1 to accommodate legacy blob refs\n // that don't include size information.\n } else if (!isSafeInteger(size) || size < 0) {\n return false\n }\n\n if (typeof ref !== 'object' || ref === null) {\n return false\n }\n\n for (const key in input) {\n if (\n key !== '$type' &&\n key !== 'mimeType' &&\n key !== 'ref' &&\n key !== 'size'\n ) {\n return false\n }\n }\n\n const cid = ifCid(\n ref,\n // Strict unless explicitly disabled\n options?.strict === false ? undefined : { flavor: 'raw' },\n )\n if (!cid) {\n return false\n }\n\n return true\n}\n\n/**\n * Legacy format for blob references used in older AT Protocol data.\n *\n * This is the older format that stores the CID as a string rather than\n * as a structured CID object. New code should use {@link BlobRef} instead.\n *\n * @example\n * ```typescript\n * import type { LegacyBlobRef } from '@atproto/lex-data'\n *\n * const legacyRef: LegacyBlobRef = {\n * cid: 'bafyreib...',\n * mimeType: 'image/jpeg'\n * }\n * ```\n *\n * @see {@link isLegacyBlobRef} to check if a value is a LegacyBlobRef\n * @see {@link BlobRef} for the current blob reference format\n * @deprecated Use {@link BlobRef} for new code\n */\nexport type LegacyBlobRef = {\n cid: string\n mimeType: string\n}\n\n/**\n * Type guard to check if a value is a valid {@link LegacyBlobRef}.\n *\n * Validates the structure of the input:\n * - `cid` must be a valid CID string\n * - `mimeType` must be a non-empty string\n * - No additional properties allowed\n *\n * @param input - The value to check\n * @returns `true` if the input is a valid LegacyBlobRef\n *\n * @example\n * ```typescript\n * import { isLegacyBlobRef } from '@atproto/lex-data'\n *\n * if (isLegacyBlobRef(data)) {\n * console.log(data.cid) // CID as string\n * console.log(data.mimeType) // e.g., 'image/jpeg'\n * }\n * ```\n *\n * @see {@link isBlobRef} for checking the current blob reference format\n */\nexport function isLegacyBlobRef(input: unknown): input is LegacyBlobRef {\n if (!isPlainObject(input)) {\n return false\n }\n\n const { cid, mimeType } = input\n if (typeof cid !== 'string') {\n return false\n }\n\n if (typeof mimeType !== 'string' || mimeType.length === 0) {\n return false\n }\n\n for (const key in input) {\n if (key !== 'cid' && key !== 'mimeType') {\n return false\n }\n }\n\n if (!validateCidString(cid)) {\n return false\n }\n\n return true\n}\n\n/**\n * Options for enumerating blob references within a {@link LexValue}.\n */\nexport type EnumBlobRefsOptions = BlobRefCheckOptions & {\n /**\n * If `true`, also yields {@link LegacyBlobRef} objects in addition to\n * {@link BlobRef} objects.\n *\n * @default false\n */\n allowLegacy?: boolean\n}\n\n/**\n * Infers the yielded type of {@link enumBlobRefs} based on options.\n *\n * @typeParam TOptions - The options used for enumeration\n */\nexport type InferEnumBlobRefs<TOptions extends EnumBlobRefsOptions> =\n TOptions extends { allowLegacy: true }\n ? InferCheckedBlobRef<TOptions> | LegacyBlobRef\n : { allowLegacy: boolean } extends TOptions\n ? InferCheckedBlobRef<TOptions> | LegacyBlobRef\n : InferCheckedBlobRef<TOptions>\n\n/**\n * Generator that enumerates all {@link BlobRef}s (and, optionally,\n * {@link LegacyBlobRef}s) found within a {@link LexValue}.\n *\n * Performs a deep traversal of the input value, yielding any blob references\n * found. This is useful for extracting all media references from a record.\n *\n * @param input - The LexValue to search for blob references\n * @param options - Optional configuration for the enumeration\n * @yields Each blob reference found in the input\n *\n * @example\n * ```typescript\n * import { enumBlobRefs } from '@atproto/lex-data'\n *\n * const record = {\n * text: 'Hello',\n * images: [\n * { $type: 'blob', mimeType: 'image/jpeg', ref: cid1, size: 1000 },\n * { $type: 'blob', mimeType: 'image/png', ref: cid2, size: 2000 }\n * ]\n * }\n *\n * for (const blobRef of enumBlobRefs(record)) {\n * console.log(blobRef.mimeType, blobRef.size)\n * }\n *\n * // Include legacy blob references\n * for (const ref of enumBlobRefs(record, { allowLegacy: true })) {\n * // ref may be BlobRef or LegacyBlobRef\n * }\n * ```\n */\nexport function enumBlobRefs(\n input: LexValue,\n): Generator<BlobRef<RawCid>, void, unknown>\nexport function enumBlobRefs<TOptions extends EnumBlobRefsOptions>(\n input: LexValue,\n options: TOptions,\n): Generator<InferEnumBlobRefs<TOptions>, void, unknown>\nexport function enumBlobRefs(\n input: LexValue,\n options?: EnumBlobRefsOptions,\n): Generator<BlobRef | LegacyBlobRef, void, unknown>\nexport function* enumBlobRefs(\n input: LexValue,\n options?: EnumBlobRefsOptions,\n): Generator<BlobRef | LegacyBlobRef, void, unknown> {\n // LegacyBlobRef not included by default\n const includeLegacy = options?.allowLegacy === true\n\n // Using a stack to avoid recursion depth issues.\n const stack: LexValue[] = [input]\n\n // Since we are using a stack, we could end-up in an infinite loop with cyclic\n // structures. Cyclic structures are not valid LexValues and should, thus,\n // never occur, but let's be safe.\n const visited = new Set<object>()\n\n do {\n const value = stack.pop()!\n\n if (value != null && typeof value === 'object') {\n if (Array.isArray(value)) {\n if (visited.has(value)) continue\n visited.add(value)\n stack.push(...value)\n } else if (isPlainProto(value)) {\n if (visited.has(value)) continue\n visited.add(value)\n if (isBlobRef(value, options)) {\n yield value\n } else if (includeLegacy && isLegacyBlobRef(value)) {\n yield value\n } else {\n for (const v of Object.values(value)) {\n if (v != null) stack.push(v)\n }\n }\n }\n }\n } while (stack.length > 0)\n\n // Optimization: ease GC's work\n visited.clear()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"blob.js","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CheckCidOptions,\n Cid,\n RawCid,\n ifCid,\n parseCid,\n validateCidString,\n} from './cid.js'\nimport { LexValue } from './lex.js'\nimport { isPlainObject, isPlainProto } from './object.js'\n\n/**\n * Options to use with {@link ifCid}, {@link validateCidString}, and related CID\n * validation functions when validating CIDs in BlobRefs, in strict mode. This\n * ensures that the CID is a {@link RawCid} (CID v1, raw multicodec, sha256\n * multihash), which is the expected format for blob references in the AT\n * Protocol data model.\n */\nconst STRICT_CID_CHECK_OPTIONS: CheckCidOptions = { flavor: 'raw' }\n\n// Number.isSafeInteger is actually safe to use with non-number values, so we\n// can use it as a type guard.\nconst isSafeInteger = Number.isSafeInteger as (v: unknown) => v is number\n\n/**\n * Reference to binary data (like images, videos, etc.) in the AT Protocol data\n * model.\n *\n * This type represents a reference to a blob of binary data, identified by its\n * content hash (CID) and accompanied by metadata such as MIME type and size.\n *\n * The {@link BlobRef} type is a union of the current {@link TypedBlobRef}\n * format and the legacy {@link LegacyBlobRef} format.\n */\nexport type BlobRef<Ref extends Cid = Cid> = TypedBlobRef<Ref> | LegacyBlobRef\n\n/**\n * Options for validating a {@link BlobRef}.\n */\nexport type BlobRefCheckOptions = {\n /**\n * If `false`, skips strict CID validation of {@link BlobRef.ref}, allowing\n * any valid CID. Otherwise, validates that the CID is v1, uses the raw\n * multicodec, and has a sha256 multihash.\n *\n * @default true\n */\n strict?: boolean\n}\n\n/**\n * Type guard to check if a value is a valid {@link BlobRef}, which can be\n * either a {@link TypedBlobRef} or a {@link LegacyBlobRef}. By default, strict\n * CID validation is applied to ensure that the CID in the blob reference is in\n * the expected format for the AT Protocol, but this can be relaxed with the\n * `strict: false` option.\n */\nexport function isBlobRef(input: unknown): input is BlobRef<RawCid>\nexport function isBlobRef<TOptions extends BlobRefCheckOptions>(\n input: unknown,\n options: TOptions,\n): input is LegacyBlobRef | InferTypedBlobRef<TOptions>\nexport function isBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is BlobRef<RawCid>\nexport function isBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is BlobRef {\n return (input as any)?.$type === 'blob'\n ? isTypedBlobRef(input, options)\n : isLegacyBlobRef(input, options)\n}\n\n/**\n * Extracts the MIME type from a {@link BlobRef}.\n *\n * @example\n * ```ts\n * const mimeType = getBlobMime(blobRef)\n * console.log(mimeType) // e.g., 'image/jpeg'\n * ```\n */\nexport function getBlobMime(blob: BlobRef): string\nexport function getBlobMime(blob?: BlobRef): string | undefined\nexport function getBlobMime(blob?: BlobRef): string | undefined {\n return blob?.mimeType\n}\n\n/**\n * Extracts the size (in bytes) from a {@link TypedBlobRef}. For\n * {@link LegacyBlobRef}, size information is not available, so this function\n * returns `undefined` for legacy refs.\n *\n * @note The size property, in blob refs, cannot be 100% trusted since the PDS\n * might not have a local copy of the blob (to check the size against) and might\n * just be passing through the blob ref from the client without validating it.\n * So, while this function can be useful for getting size information when\n * available, it should not be solely relied upon for critical functionality\n * without additional validation.\n *\n * @example\n * ```ts\n * const size = getBlobSize(blobRef)\n * if (size !== undefined) {\n * console.log(`Blob size: ${size} bytes`)\n * } else {\n * console.log('Size information not available for legacy blob ref')\n * }\n * ```\n */\nexport function getBlobSize(blob: BlobRef): number | undefined {\n if ('$type' in blob && blob.size >= 0) return blob.size\n // LegacyBlobRef doesn't have size information\n return undefined\n}\n\n/**\n * Extracts the {@link Cid} from a {@link BlobRef}.\n *\n * @throws If the input input is a {@link LegacyBlobRef} with an invalid CID string\n * @example\n * ```ts\n * const cid = getBlobCid(blobRef)\n * console.log(cid.bytes)\n * ```\n */\nexport function getBlobCid(blob: BlobRef): Cid\nexport function getBlobCid(blob?: BlobRef): Cid | undefined\nexport function getBlobCid(blob?: BlobRef): Cid | undefined {\n if (!blob) return undefined\n return '$type' in blob ? blob.ref : parseCid(blob.cid)\n}\n\n/**\n * Extracts the CID string from a {@link BlobRef}.\n *\n * This is similar to `getBlobCid(blob).toString()` but is more optimized since\n * the CID string is already available in the legacy format and we can avoid\n * parsing it into a CID object just to convert it back to a string.\n *\n * @example\n * ```ts\n * const cidString = getBlobCidString(blobRef)\n * console.log(cidString)\n * ```\n */\nexport function getBlobCidString(blob: BlobRef): string\nexport function getBlobCidString(blob?: BlobRef): string | undefined\nexport function getBlobCidString(blob?: BlobRef): string | undefined {\n if (!blob) return undefined\n return '$type' in blob ? blob.ref.toString() : blob.cid\n}\n\n/**\n * Reference to binary data (like images, videos, etc.) in the AT Protocol data model.\n *\n * A {@link TypedBlobRef} is a {@link LexMap} with a specific structure that\n * identifies binary content by its content hash (CID), along with metadata\n * about the content type and size.\n *\n * @typeParam Ref - The type of CID reference, defaults to any {@link Cid}\n *\n * @example\n * ```typescript\n * import type { TypedBlobRef } from '@atproto/lex-data'\n *\n * const imageRef: TypedBlobRef = {\n * $type: 'blob',\n * mimeType: 'image/jpeg',\n * ref: cid, // CID of the blob content\n * size: 12345\n * }\n * ```\n *\n * @see {@link isTypedBlobRef} to check if a value is a valid {@link TypedBlobRef}\n * @see {@link LegacyBlobRef} for the older blob reference format\n */\nexport type TypedBlobRef<Ref extends Cid = Cid> = {\n $type: 'blob'\n mimeType: string\n ref: Ref\n size: number\n}\n\n/**\n * Infers the BlobRef type based on the check options.\n *\n * @typeParam TOptions - The options used for checking\n */\nexport type InferTypedBlobRef<TOptions extends BlobRefCheckOptions> =\n TOptions extends { strict: false }\n ? TypedBlobRef\n : { strict: boolean } extends TOptions\n ? TypedBlobRef\n : TypedBlobRef<RawCid>\n\n/**\n * Type guard to check if a value is a valid {@link BlobRef}.\n *\n * Validates the structure of the input including:\n * - `$type` must be `'blob'`\n * - `mimeType` must be a valid MIME type string (containing '/')\n * - `size` must be a non-negative safe integer\n * - `ref` must be a valid CID (strict validation by default)\n *\n * @param input - The value to check\n * @param options - Optional validation options\n * @returns `true` if the input is a valid BlobRef\n *\n * @example\n * ```typescript\n * import { isTypedBlobRef } from '@atproto/lex-data'\n *\n * if (isTypedBlobRef(data)) {\n * console.log(data.mimeType) // e.g., 'image/jpeg'\n * console.log(data.size) // e.g., 12345\n * }\n *\n * // Allow any valid CID (not just raw CIDs)\n * if (isTypedBlobRef(data, { strict: false })) {\n * // ...\n * }\n * ```\n */\nexport function isTypedBlobRef(input: unknown): input is TypedBlobRef<RawCid>\nexport function isTypedBlobRef<TOptions extends BlobRefCheckOptions>(\n input: unknown,\n options: TOptions,\n): input is InferTypedBlobRef<TOptions>\nexport function isTypedBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is TypedBlobRef<RawCid>\nexport function isTypedBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is TypedBlobRef {\n if (!isPlainObject(input)) {\n return false\n }\n\n if (input?.$type !== 'blob') {\n return false\n }\n\n const { mimeType, size, ref } = input\n // @NOTE Very basic mime validation\n if (typeof mimeType !== 'string' || !mimeType.includes('/')) {\n return false\n }\n\n if (size === -1 && options?.strict === false) {\n // In non-strict mode, allow size to be -1 to accommodate legacy blob refs\n // that don't include size information.\n } else if (!isSafeInteger(size) || size < 0) {\n return false\n }\n\n if (typeof ref !== 'object' || ref === null) {\n return false\n }\n\n for (const key in input) {\n if (\n key !== '$type' &&\n key !== 'mimeType' &&\n key !== 'ref' &&\n key !== 'size'\n ) {\n return false\n }\n }\n\n const cid = ifCid(\n ref,\n // Strict unless explicitly disabled\n options?.strict === false ? undefined : STRICT_CID_CHECK_OPTIONS,\n )\n if (!cid) {\n return false\n }\n\n return true\n}\n\n/**\n * Legacy format for blob references used in older AT Protocol data.\n *\n * This is the older format that stores the CID as a string rather than\n * as a structured CID object. New code should use {@link BlobRef} instead.\n *\n * @example\n * ```typescript\n * import type { LegacyBlobRef } from '@atproto/lex-data'\n *\n * const legacyRef: LegacyBlobRef = {\n * cid: 'bafyreib...',\n * mimeType: 'image/jpeg'\n * }\n * ```\n *\n * @see {@link isLegacyBlobRef} to check if a value is a LegacyBlobRef\n * @see {@link BlobRef} for the current blob reference format\n * @deprecated Use {@link BlobRef} for new code\n */\nexport type LegacyBlobRef = {\n cid: string\n mimeType: string\n}\n\n/**\n * Type guard to check if a value is a valid {@link LegacyBlobRef}.\n *\n * Validates the structure of the input:\n * - `cid` must be a valid CID string\n * - `mimeType` must be a non-empty string\n * - No additional properties allowed\n *\n * @example\n * ```typescript\n * import { isLegacyBlobRef } from '@atproto/lex-data'\n *\n * if (isLegacyBlobRef(data)) {\n * console.log(data.cid) // CID as string\n * console.log(data.mimeType) // e.g., 'image/jpeg'\n * }\n * ```\n *\n * @see {@link isTypedBlobRef} for checking the current blob reference format\n */\nexport function isLegacyBlobRef(\n input: unknown,\n options?: BlobRefCheckOptions,\n): input is LegacyBlobRef {\n if (!isPlainObject(input)) {\n return false\n }\n\n const { cid, mimeType } = input\n if (typeof cid !== 'string') {\n return false\n }\n\n if (typeof mimeType !== 'string' || mimeType.length === 0) {\n return false\n }\n\n for (const key in input) {\n if (key !== 'cid' && key !== 'mimeType') {\n return false\n }\n }\n\n if (\n !validateCidString(\n cid,\n options?.strict === false ? undefined : STRICT_CID_CHECK_OPTIONS,\n )\n ) {\n return false\n }\n\n return true\n}\n\n/**\n * Options for enumerating blob references within a {@link LexValue}.\n */\nexport type EnumBlobRefsOptions = BlobRefCheckOptions & {\n /**\n * If `true`, also yields {@link LegacyBlobRef} objects in addition to\n * {@link BlobRef} objects.\n *\n * @default false\n */\n allowLegacy?: boolean\n}\n\n/**\n * Infers the yielded type of {@link enumBlobRefs} based on options.\n *\n * @typeParam TOptions - The options used for enumeration\n */\nexport type InferEnumBlobRefs<TOptions extends EnumBlobRefsOptions> =\n TOptions extends { allowLegacy: true }\n ? InferTypedBlobRef<TOptions> | LegacyBlobRef\n : { allowLegacy: boolean } extends TOptions\n ? InferTypedBlobRef<TOptions> | LegacyBlobRef\n : InferTypedBlobRef<TOptions>\n\n/**\n * Generator that enumerates all {@link BlobRef}s (and, optionally,\n * {@link LegacyBlobRef}s) found within a {@link LexValue}.\n *\n * Performs a deep traversal of the input value, yielding any blob references\n * found. This is useful for extracting all media references from a record.\n *\n * @param input - The LexValue to search for blob references\n * @param options - Optional configuration for the enumeration\n * @yields Each blob reference found in the input\n *\n * @example\n * ```typescript\n * import { enumBlobRefs } from '@atproto/lex-data'\n *\n * const record = {\n * text: 'Hello',\n * images: [\n * { $type: 'blob', mimeType: 'image/jpeg', ref: cid1, size: 1000 },\n * { $type: 'blob', mimeType: 'image/png', ref: cid2, size: 2000 }\n * ]\n * }\n *\n * for (const blobRef of enumBlobRefs(record)) {\n * console.log(blobRef.mimeType, blobRef.size)\n * }\n *\n * // Include legacy blob references\n * for (const ref of enumBlobRefs(record, { allowLegacy: true, strict: false })) {\n * // ref may be BlobRef or LegacyBlobRef, with relaxed CID validation\n * }\n * ```\n */\nexport function enumBlobRefs(\n input: LexValue,\n): Generator<BlobRef<RawCid>, void, unknown>\nexport function enumBlobRefs<TOptions extends EnumBlobRefsOptions>(\n input: LexValue,\n options: TOptions,\n): Generator<InferEnumBlobRefs<TOptions>, void, unknown>\nexport function enumBlobRefs(\n input: LexValue,\n options?: EnumBlobRefsOptions,\n): Generator<BlobRef, void, unknown>\nexport function* enumBlobRefs(\n input: LexValue,\n options?: EnumBlobRefsOptions,\n): Generator<BlobRef, void, unknown> {\n // LegacyBlobRef not included by default\n const includeLegacy = options?.allowLegacy === true\n\n // Using a stack to avoid recursion depth issues.\n const stack: LexValue[] = [input]\n\n // Since we are using a stack, we could end-up in an infinite loop with cyclic\n // structures. Cyclic structures are not valid LexValues and should, thus,\n // never occur, but let's be safe.\n const visited = new Set<object>()\n\n do {\n const value = stack.pop()!\n\n if (value != null && typeof value === 'object') {\n if (Array.isArray(value)) {\n if (visited.has(value)) continue\n visited.add(value)\n stack.push(...value)\n } else if (isPlainProto(value)) {\n if (visited.has(value)) continue\n visited.add(value)\n if (isTypedBlobRef(value, options)) {\n yield value\n } else if (includeLegacy && isLegacyBlobRef(value, options)) {\n yield value\n } else {\n for (const v of Object.values(value)) {\n if (v != null) stack.push(v)\n }\n }\n }\n }\n } while (stack.length > 0)\n\n // Optimization: ease GC's work\n visited.clear()\n}\n"]}
|
package/dist/cid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cid.d.ts","sourceRoot":"","sources":["../src/cid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAOtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,MAAO,CAAA;AACnC,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAA;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,KAAO,CAAA;AAClC,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAA;AAElD;;GAEG;AACH,eAAO,MAAM,gBAAgB,IAAc,CAAA;AAC3C,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA;AAEtD;;GAEG;AACH,eAAO,MAAM,gBAAgB,IAAc,CAAA;AAC3C,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,SAAS,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM;IAC1D;;OAEG;IACH,IAAI,EAAE,SAAS,CAAA;IAEf;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAGnE;AAED,OAAO,QAAQ,kBAAkB,CAAC;IAChC;;;;;;;;;;;;;;;;;;OAkBG;
|
|
1
|
+
{"version":3,"file":"cid.d.ts","sourceRoot":"","sources":["../src/cid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAOtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,MAAO,CAAA;AACnC,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAA;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,KAAO,CAAA;AAClC,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAA;AAElD;;GAEG;AACH,eAAO,MAAM,gBAAgB,IAAc,CAAA;AAC3C,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA;AAEtD;;GAEG;AACH,eAAO,MAAM,gBAAgB,IAAc,CAAA;AAC3C,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,SAAS,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM;IAC1D;;OAEG;IACH,IAAI,EAAE,SAAS,CAAA;IAEf;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAGnE;AAED,OAAO,QAAQ,kBAAkB,CAAC;IAChC;;;;;;;;;;;;;;;;;;OAkBG;IAEH,UAAU,GAAG;KAAG;CACjB;AAqBD,OAAO,EAAE,kBAAkB,CAAC,GAAG,EAAE,CAAA;AAEjC;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAC9B,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,SAAS,SAAS,MAAM,GAAG,MAAM,EACjC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,GAeX,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CACnE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,GAAG,CAClB,QAAQ,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAC9B,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,SAAS,SAAS,MAAM,GAAG,MAAM;IAKjC,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IAExC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAE1B;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAA;IAE3B;;OAEG;IACH,QAAQ,IAAI,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAEhD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,eAAe,EAAE,gBAAgB,CAAC,CAAA;AAEhF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,OAAO,CAOlD;AAED;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAA;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,OAAO,CAElD;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;CACjC,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,QAAQ,SAAS,eAAe,IAC1D,QAAQ,SAAS;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GAC9B,MAAM,GACN,QAAQ,SAAS;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC,OAAO,GACP,GAAG,CAAA;AAEX;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,SAAS,eAAe,EACvD,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,QAAQ,GAChB,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAA;AACnC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAA;AAgBtE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,QAAQ,SAAS,eAAe,EACpD,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,QAAQ,GAChB,KAAK,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAA;AACrC,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,KAAK,IAAI,GAAG,CAAA;AAK9E;;GAEG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,QAAQ,SAAS,eAAe,EAC5D,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,QAAQ,GAChB,CAAC,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAA;AAC9C,wBAAgB,KAAK,CAAC,MAAM,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,GACxB,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAA;AAMxB;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,QAAQ,SAAS,eAAe,EAC5D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,GAChB,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAA;AACrC,wBAAgB,KAAK,CAAC,MAAM,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,GACxB,MAAM,GAAG,GAAG,CAAA;AAQf;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,SAAS,eAAe,EACxD,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,QAAQ,GAChB,eAAe,CAAC,QAAQ,CAAC,CAAA;AAC5B,wBAAgB,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,GAAG,CAAA;AAS/E;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,SAAS,eAAe,EACvD,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,GAChB,eAAe,CAAC,QAAQ,CAAC,CAAA;AAC5B,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,GAAG,CAAA;AAMvE;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAET;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,SAAS,eAAe,EAC3D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,GAChB,eAAe,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAA;AACnC,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,GACxB,GAAG,GAAG,IAAI,CAAA;AAYb;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,GACxB,IAAI,CAIN;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,OAAO,CAAC,CAelB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,EACvE,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,SAAS,EACxB,MAAM,EAAE,UAAU,GAGJ,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CACxC;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAGpE;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAQxD"}
|