@atproto/lex-data 0.0.10 → 0.0.12

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/dist/cid.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CID = exports.SHA512_MULTIHASH = exports.SHA256_MULTIHASH = exports.RAW_MULTICODEC = exports.DAG_CBOR_MULTICODEC = void 0;
3
+ exports.CID = exports.SHA512_HASH_CODE = exports.SHA256_HASH_CODE = exports.RAW_DATA_CODEC = exports.CBOR_DATA_CODEC = void 0;
4
4
  exports.multihashEquals = multihashEquals;
5
5
  exports.asMultiformatsCID = asMultiformatsCID;
6
6
  exports.isRawCid = isRawCid;
@@ -26,11 +26,40 @@ const digest_1 = require("multiformats/hashes/digest");
26
26
  const sha2_1 = require("multiformats/hashes/sha2");
27
27
  const object_js_1 = require("./object.js");
28
28
  const uint8array_js_1 = require("./uint8array.js");
29
- exports.DAG_CBOR_MULTICODEC = 0x71; // DRISL conformant DAG-CBOR
30
- exports.RAW_MULTICODEC = 0x55; // raw binary codec used in DASL CIDs
31
- exports.SHA256_MULTIHASH = sha2_1.sha256.code;
32
- exports.SHA512_MULTIHASH = sha2_1.sha512.code;
29
+ /**
30
+ * Codec code that indicates the CID references a CBOR-encoded data structure.
31
+ *
32
+ * Used when encoding structured data in AT Protocol repositories.
33
+ *
34
+ * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}
35
+ */
36
+ exports.CBOR_DATA_CODEC = 0x71;
37
+ /**
38
+ * Codec code that indicates the CID references raw binary data (like media blobs).
39
+ *
40
+ * Used in DASL CIDs for binary blobs like images and media.
41
+ *
42
+ * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}
43
+ */
44
+ exports.RAW_DATA_CODEC = 0x55;
45
+ /**
46
+ * Hash code that indicates that a CID uses SHA-256.
47
+ */
48
+ exports.SHA256_HASH_CODE = sha2_1.sha256.code;
49
+ /**
50
+ * Hash code that indicates that a CID uses SHA-512.
51
+ */
52
+ exports.SHA512_HASH_CODE = sha2_1.sha512.code;
53
+ /**
54
+ * Compares two {@link Multihash} for equality.
55
+ *
56
+ * @param a - First {@link Multihash}
57
+ * @param b - Second {@link Multihash}
58
+ * @returns `true` if both multihashes have the same code and digest
59
+ */
33
60
  function multihashEquals(a, b) {
61
+ if (a === b)
62
+ return true;
34
63
  return a.code === b.code && (0, uint8array_js_1.ui8Equals)(a.digest, b.digest);
35
64
  }
36
65
  /**
@@ -53,18 +82,36 @@ function asMultiformatsCID(input) {
53
82
  // needed.
54
83
  return cid;
55
84
  }
85
+ /**
86
+ * Type guard to check if a CID is a raw binary CID.
87
+ *
88
+ * @param cid - The CID to check
89
+ * @returns `true` if the CID is a version 1 CID with raw multicodec
90
+ */
56
91
  function isRawCid(cid) {
57
- return cid.version === 1 && cid.code === exports.RAW_MULTICODEC;
92
+ return cid.version === 1 && cid.code === exports.RAW_DATA_CODEC;
58
93
  }
94
+ /**
95
+ * Type guard to check if a CID is DASL compliant.
96
+ *
97
+ * @param cid - The CID to check
98
+ * @returns `true` if the CID is DASL compliant (v1, raw/dag-cbor, sha256)
99
+ */
59
100
  function isDaslCid(cid) {
60
101
  return (cid.version === 1 &&
61
- (cid.code === exports.RAW_MULTICODEC || cid.code === exports.DAG_CBOR_MULTICODEC) &&
62
- cid.multihash.code === exports.SHA256_MULTIHASH &&
63
- cid.multihash.digest.byteLength === 32 // Should always be 32 bytes (256 bits) for SHA-256, but double-checking anyways
102
+ (cid.code === exports.RAW_DATA_CODEC || cid.code === exports.CBOR_DATA_CODEC) &&
103
+ cid.multihash.code === exports.SHA256_HASH_CODE &&
104
+ cid.multihash.digest.byteLength === 0x20 // Should always be 32 bytes (256 bits) for SHA-256, but double-checking anyways
64
105
  );
65
106
  }
107
+ /**
108
+ * Type guard to check if a CID is a DAG-CBOR CID.
109
+ *
110
+ * @param cid - The CID to check
111
+ * @returns `true` if the CID is a DAG-CBOR CID (v1, dag-cbor, sha256)
112
+ */
66
113
  function isCborCid(cid) {
67
- return cid.code === exports.DAG_CBOR_MULTICODEC && isDaslCid(cid);
114
+ return cid.code === exports.CBOR_DATA_CODEC && isDaslCid(cid);
68
115
  }
69
116
  function checkCid(cid, options) {
70
117
  switch (options?.flavor) {
@@ -101,6 +148,16 @@ function parseCid(input, options) {
101
148
  const cid = cid_1.CID.parse(input);
102
149
  return asCid(cid, options);
103
150
  }
151
+ /**
152
+ * Validates that a string is a valid CID representation.
153
+ *
154
+ * Unlike {@link parseCid}, this function returns a boolean instead of throwing.
155
+ * It also verifies that the string is the canonical representation of the CID.
156
+ *
157
+ * @param input - The string to validate
158
+ * @param options - Optional flavor constraints
159
+ * @returns `true` if the string is a valid CID
160
+ */
104
161
  function validateCidString(input, options) {
105
162
  return parseCidSafe(input, options)?.toString() === input;
106
163
  }
@@ -112,6 +169,13 @@ function parseCidSafe(input, options) {
112
169
  return null;
113
170
  }
114
171
  }
172
+ /**
173
+ * Ensures that a string is a valid CID representation.
174
+ *
175
+ * @param input - The string to validate
176
+ * @param options - Optional flavor constraints
177
+ * @throws If the string is not a valid CID
178
+ */
115
179
  function ensureValidCidString(input, options) {
116
180
  if (!validateCidString(input, options)) {
117
181
  throw new Error(`Invalid CID string`);
@@ -135,28 +199,63 @@ async function isCidForBytes(cid, bytes) {
135
199
  // Don't know how to verify other multihash codes
136
200
  throw new Error('Unsupported CID multihash');
137
201
  }
202
+ /**
203
+ * Creates a CID from a multicodec, multihash code, and digest.
204
+ *
205
+ * @param code - The multicodec content type code
206
+ * @param multihashCode - The multihash algorithm code
207
+ * @param digest - The raw hash digest bytes
208
+ * @returns A new CIDv1 instance
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * import { createCid, RAW_DATA_CODEC, SHA256_HASH_CODE } from '@atproto/lex-data'
213
+ *
214
+ * const cid = createCid(RAW_DATA_CODEC, SHA256_HASH_CODE, hashDigest)
215
+ * ```
216
+ */
138
217
  function createCid(code, multihashCode, digest) {
139
218
  const cid = cid_1.CID.createV1(code, (0, digest_1.create)(multihashCode, digest));
140
219
  return cid;
141
220
  }
221
+ /**
222
+ * Creates a DAG-CBOR CID for the given CBOR bytes.
223
+ *
224
+ * Computes the SHA-256 hash of the bytes and creates a CIDv1 with DAG-CBOR multicodec.
225
+ *
226
+ * @param bytes - The CBOR-encoded bytes to hash
227
+ * @returns A promise that resolves to the CborCid
228
+ */
142
229
  async function cidForCbor(bytes) {
143
230
  const multihash = await sha2_1.sha256.digest(bytes);
144
- return cid_1.CID.createV1(exports.DAG_CBOR_MULTICODEC, multihash);
231
+ return cid_1.CID.createV1(exports.CBOR_DATA_CODEC, multihash);
145
232
  }
233
+ /**
234
+ * Creates a raw CID for the given binary bytes.
235
+ *
236
+ * Computes the SHA-256 hash of the bytes and creates a CIDv1 with raw multicodec.
237
+ *
238
+ * @param bytes - The raw binary bytes to hash
239
+ * @returns A promise that resolves to the RawCid
240
+ */
146
241
  async function cidForRawBytes(bytes) {
147
242
  const multihash = await sha2_1.sha256.digest(bytes);
148
- return cid_1.CID.createV1(exports.RAW_MULTICODEC, multihash);
243
+ return cid_1.CID.createV1(exports.RAW_DATA_CODEC, multihash);
149
244
  }
245
+ /**
246
+ * Creates a raw CID from an existing SHA-256 hash digest.
247
+ *
248
+ * @param digest - The SHA-256 hash digest (must be 32 bytes)
249
+ * @returns A RawCid with the given digest
250
+ * @throws If the digest length is not 32 bytes
251
+ */
150
252
  function cidForRawHash(digest) {
151
253
  // Fool-proofing
152
254
  if (digest.length !== 32) {
153
255
  throw new Error(`Invalid SHA-256 hash length: ${digest.length}`);
154
256
  }
155
- return createCid(exports.RAW_MULTICODEC, sha2_1.sha256.code, digest);
257
+ return createCid(exports.RAW_DATA_CODEC, sha2_1.sha256.code, digest);
156
258
  }
157
- /**
158
- * @internal
159
- */
160
259
  function isCidImplementation(value) {
161
260
  if (cid_1.CID.asCID(value)) {
162
261
  // CIDs created using older multiformats versions did not have a "bytes"
@@ -206,9 +305,6 @@ function isCidImplementation(value) {
206
305
  }
207
306
  }
208
307
  }
209
- /**
210
- * @internal
211
- */
212
308
  function isUint8(val) {
213
309
  return Number.isInteger(val) && val >= 0 && val < 256;
214
310
  }
package/dist/cid.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cid.js","sourceRoot":"","sources":["../src/cid.ts"],"names":[],"mappings":"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","sourcesContent":["import { CID } from 'multiformats/cid'\nimport { create as createDigest } from 'multiformats/hashes/digest'\nimport { sha256, sha512 } from 'multiformats/hashes/sha2'\nimport { isObject } from './object.js'\nimport { ui8Equals } from './uint8array.js'\n\nexport const DAG_CBOR_MULTICODEC = 0x71 // DRISL conformant DAG-CBOR\nexport type DAG_CBOR_MULTICODEC = typeof DAG_CBOR_MULTICODEC\n\nexport const RAW_MULTICODEC = 0x55 // raw binary codec used in DASL CIDs\nexport type RAW_MULTICODEC = typeof RAW_MULTICODEC\n\nexport const SHA256_MULTIHASH = sha256.code\nexport type SHA256_MULTIHASH = typeof SHA256_MULTIHASH\n\nexport const SHA512_MULTIHASH = sha512.code\nexport type SHA512_MULTIHASH = typeof SHA512_MULTIHASH\n\nexport interface Multihash<TCode extends number = number> {\n /**\n * Code of the multihash\n */\n code: TCode\n\n /**\n * Raw digest\n */\n digest: Uint8Array\n}\n\nexport function multihashEquals(a: Multihash, b: Multihash): boolean {\n return a.code === b.code && ui8Equals(a.digest, b.digest)\n}\n\ndeclare module 'multiformats/cid' {\n /**\n * @deprecated use the {@link Cid} interface from `@atproto/lex-data`, and\n * related helpers ({@link isCid}, {@link ifCid}, {@link asCid},\n * {@link parseCid}, {@link decodeCid}), instead.\n *\n * This is marked as deprecated because we want to discourage direct usage of\n * `multiformats/cid` in dependent packages, and instead have them rely on the\n * {@link Cid} interface from `@atproto/lex-data`. The {@link CID} class from\n * `multiformats` version <10 has compatibility issues with certain TypeScript\n * configuration, which can lead to type errors in dependent packages.\n *\n * We are stuck with version 9 because `@atproto` packages did not drop\n * CommonJS support yet, and multiformats version 10 only supports ES modules.\n *\n * In order to avoid compatibility issues, while preparing for future breaking\n * changes (CID in multiformats v10+ has a slightly different interface), as\n * we update or swap out `multiformats`, `@atproto/lex-data` provides its own\n * stable {@link Cid} interface.\n */\n interface CID {}\n}\n\n// multiformats' CID class is not very portable because:\n//\n// - In dependent packages that use \"moduleResolution\" set to \"node16\",\n// \"nodenext\" or \"bundler\", TypeScript fails to properly resolve the\n// multiformats package when importing CID from @atproto/lex-data. This causes\n// type errors in those packages. This is caused by the fact that the\n// multiformats version <10 (which is the last version that supports CommonJS)\n// uses \"exports\" field in package.json, which do not contain \"types\"\n// entrypoints.\n// https://www.npmjs.com/package/multiformats/v/9.9.0?activeTab=code\n// - By defining our own interface and helper functions, we can have more\n// control over the public API exposed by this package.\n// - It allow us to have a stable interface in case we need to swap out, or\n// eventually update multiformats (should we choose to drop CommonJS support)\n// in the future.\n\n// @NOTE Even though it is not portable, we still re-export CID here so that\n// dependent packages where it can be used, have access to it (instead of\n// importing directly from \"multiformats\" or \"multiformats/cid\").\nexport { /** @deprecated */ CID }\n\n/**\n * Converts a {@link Cid} to a multiformats {@link CID} instance.\n *\n * @deprecated Packages depending on `@atproto/lex-data` should use the\n * {@link Cid} interface instead of relying on `multiformats`'s {@link CID}\n * implementation directly. This is to avoid compatibility issues, and in order\n * to allow better portability, compatibility and future updates.\n */\nexport function asMultiformatsCID<\n TVersion extends 0 | 1 = 0 | 1,\n TCode extends number = number,\n TMultihashCode extends number = number,\n>(input: Cid<TVersion, TCode, TMultihashCode>) {\n const cid =\n // Already a multiformats CID instance\n CID.asCID(input) ??\n // Create a new multiformats CID instance\n CID.create(\n input.version,\n input.code,\n createDigest(input.multihash.code, input.multihash.digest),\n )\n\n // @NOTE: the \"satisfies\" operator is used here to ensure that the Cid\n // interface is indeed compatible with multiformats' CID implementation, which\n // allows us to safely rely on multiformats' CID implementation where Cid are\n // needed.\n return cid satisfies Cid as CID & Cid<TVersion, TCode, TMultihashCode>\n}\n\n/**\n * Interface for working with CIDs\n */\nexport interface Cid<\n TVersion extends 0 | 1 = 0 | 1,\n TCode extends number = number,\n TMultihashCode extends number = number,\n> {\n // @NOTE This interface is compatible with multiformats' CID implementation\n // which we are using under the hood.\n\n readonly version: TVersion\n readonly code: TCode\n readonly multihash: Multihash<TMultihashCode>\n\n /**\n * Binary representation of the whole CID.\n */\n readonly bytes: Uint8Array\n\n equals(other: Cid): boolean\n toString(): string\n}\n\n/**\n * Represents the cid of raw binary data (like media blobs).\n *\n * The use of {@link SHA256_MULTIHASH} is recommended but not required for raw CIDs.\n *\n * @see {@link https://atproto.com/specs/data-model#link-and-cid-formats ATproto Data Model - Link and CID Formats}\n */\nexport type RawCid = Cid<1, RAW_MULTICODEC>\n\nexport function isRawCid(cid: Cid): cid is RawCid {\n return cid.version === 1 && cid.code === RAW_MULTICODEC\n}\n\n/**\n * Represents a DASL compliant CID.\n * @see {@link https://dasl.ing/cid.html DASL-CIDs}\n */\nexport type DaslCid = Cid<\n 1,\n RAW_MULTICODEC | DAG_CBOR_MULTICODEC,\n SHA256_MULTIHASH\n>\n\nexport function isDaslCid(cid: Cid): cid is DaslCid {\n return (\n cid.version === 1 &&\n (cid.code === RAW_MULTICODEC || cid.code === DAG_CBOR_MULTICODEC) &&\n cid.multihash.code === SHA256_MULTIHASH &&\n cid.multihash.digest.byteLength === 32 // Should always be 32 bytes (256 bits) for SHA-256, but double-checking anyways\n )\n}\n\n/**\n * Represents the cid of ATProto DAG-CBOR data (like repository MST nodes).\n * @see {@link https://atproto.com/specs/data-model#link-and-cid-formats ATproto Data Model - Link and CID Formats}\n */\nexport type CborCid = Cid<1, DAG_CBOR_MULTICODEC, SHA256_MULTIHASH>\n\nexport function isCborCid(cid: Cid): cid is CborCid {\n return cid.code === DAG_CBOR_MULTICODEC && isDaslCid(cid)\n}\n\nexport type CheckCidOptions = {\n flavor?: 'raw' | 'cbor' | 'dasl'\n}\n\nexport type InferCheckedCid<TOptions> = TOptions extends { flavor: 'raw' }\n ? RawCid\n : TOptions extends { flavor: 'cbor' }\n ? CborCid\n : Cid\n\n/**\n * Type guard to check whether a {@link Cid} instance meets specific flavor\n * constraints.\n */\nexport function checkCid<TOptions extends CheckCidOptions>(\n cid: Cid,\n options: TOptions,\n): cid is InferCheckedCid<TOptions>\nexport function checkCid(cid: Cid, options?: CheckCidOptions): boolean\nexport function checkCid(cid: Cid, options?: CheckCidOptions): boolean {\n switch (options?.flavor) {\n case undefined:\n return true\n case 'cbor':\n return isCborCid(cid)\n case 'dasl':\n return isDaslCid(cid)\n case 'raw':\n return isRawCid(cid)\n default:\n throw new TypeError(`Unknown CID flavor: ${options?.flavor}`)\n }\n}\n\n/**\n * Type guard to check whether a value is a valid {@link Cid} instance,\n * optionally checking for specific flavor constraints.\n */\nexport function isCid<TOptions extends CheckCidOptions>(\n value: unknown,\n options: TOptions,\n): value is InferCheckedCid<TOptions>\nexport function isCid(value: unknown, options?: CheckCidOptions): value is Cid\nexport function isCid(value: unknown, options?: CheckCidOptions): value is Cid {\n return isCidImplementation(value) && checkCid(value, options)\n}\n\n/**\n * Returns the input value as a {@link Cid} if it is valid, or `null` otherwise.\n */\nexport function ifCid<TValue, TOptions extends CheckCidOptions>(\n value: unknown,\n options: TOptions,\n): (TValue & InferCheckedCid<TOptions>) | null\nexport function ifCid<TValue>(\n value: TValue,\n options?: CheckCidOptions,\n): (TValue & Cid) | null\nexport function ifCid(value: unknown, options?: CheckCidOptions): Cid | null {\n if (isCidImplementation(value) && checkCid(value, options)) return value\n return null\n}\n\n/**\n * Returns the input value as a {@link Cid} if it is valid.\n *\n * @throws if the input is not a valid {@link Cid}.\n */\nexport function asCid<TValue, TOptions extends CheckCidOptions>(\n value: TValue,\n options: TOptions,\n): TValue & InferCheckedCid<TOptions>\nexport function asCid<TValue>(\n value: TValue,\n options?: CheckCidOptions,\n): Cid & TValue\nexport function asCid(value: unknown, options?: CheckCidOptions): Cid {\n if (isCidImplementation(value) && checkCid(value, options)) return value\n throw new Error('Not a valid CID')\n}\n\n/**\n * Decodes a CID from its binary representation.\n *\n * @see {@link https://dasl.ing/cid.html DASL-CIDs}\n * @throws if the input do not represent a valid DASL {@link Cid}\n */\nexport function decodeCid<TOptions extends CheckCidOptions>(\n cidBytes: Uint8Array,\n options: TOptions,\n): InferCheckedCid<TOptions>\nexport function decodeCid(cidBytes: Uint8Array, options?: CheckCidOptions): Cid\nexport function decodeCid(\n cidBytes: Uint8Array,\n options?: CheckCidOptions,\n): Cid {\n const cid = CID.decode(cidBytes)\n return asCid(cid, options)\n}\n\n/**\n * Parses a CID string into a Cid object.\n *\n * @throws if the input is not a valid CID string.\n */\nexport function parseCid<TOptions extends CheckCidOptions>(\n input: string,\n options: TOptions,\n): InferCheckedCid<TOptions>\nexport function parseCid(input: string, options?: CheckCidOptions): Cid\nexport function parseCid(input: string, options?: CheckCidOptions): Cid {\n const cid = CID.parse(input)\n return asCid(cid, options)\n}\n\nexport function validateCidString(\n input: string,\n options?: CheckCidOptions,\n): boolean {\n return parseCidSafe(input, options)?.toString() === input\n}\n\nexport function parseCidSafe<TOptions extends CheckCidOptions>(\n input: string,\n options: TOptions,\n): InferCheckedCid<TOptions> | null\nexport function parseCidSafe(\n input: string,\n options?: CheckCidOptions,\n): Cid | null\nexport function parseCidSafe(\n input: string,\n options?: CheckCidOptions,\n): Cid | null {\n try {\n return parseCid(input, options)\n } catch {\n return null\n }\n}\n\nexport function ensureValidCidString(\n input: string,\n options?: CheckCidOptions,\n): void {\n if (!validateCidString(input, options)) {\n throw new Error(`Invalid CID string`)\n }\n}\n\n/**\n * Verifies whether the multihash of a given {@link cid} matches the hash of the provided {@link bytes}.\n * @params cid The CID to match against the bytes.\n * @params bytes The bytes to verify.\n * @returns true if the CID matches the bytes, false otherwise.\n */\nexport async function isCidForBytes(\n cid: Cid,\n bytes: Uint8Array,\n): Promise<boolean> {\n if (cid.multihash.code === sha256.code) {\n const multihash = await sha256.digest(bytes)\n return multihashEquals(multihash, cid.multihash)\n }\n\n if (cid.multihash.code === sha512.code) {\n const multihash = await sha512.digest(bytes)\n return multihashEquals(multihash, cid.multihash)\n }\n\n // Don't know how to verify other multihash codes\n throw new Error('Unsupported CID multihash')\n}\n\nexport function createCid<TCode extends number, TMultihashCode extends number>(\n code: TCode,\n multihashCode: TMultihashCode,\n digest: Uint8Array,\n) {\n const cid: Cid = CID.createV1(code, createDigest(multihashCode, digest))\n return cid as Cid<1, TCode, TMultihashCode>\n}\n\nexport async function cidForCbor(bytes: Uint8Array): Promise<CborCid> {\n const multihash = await sha256.digest(bytes)\n return CID.createV1(DAG_CBOR_MULTICODEC, multihash) as CborCid\n}\n\nexport async function cidForRawBytes(bytes: Uint8Array): Promise<RawCid> {\n const multihash = await sha256.digest(bytes)\n return CID.createV1(RAW_MULTICODEC, multihash) as RawCid\n}\n\nexport function cidForRawHash(digest: Uint8Array): RawCid {\n // Fool-proofing\n if (digest.length !== 32) {\n throw new Error(`Invalid SHA-256 hash length: ${digest.length}`)\n }\n return createCid(RAW_MULTICODEC, sha256.code, digest)\n}\n\n/**\n * @internal\n */\nfunction isCidImplementation(value: unknown): value is Cid {\n if (CID.asCID(value)) {\n // CIDs created using older multiformats versions did not have a \"bytes\"\n // property.\n return (value as { bytes?: Uint8Array }).bytes != null\n } else {\n // Unknown implementation, do a structural check\n try {\n if (!isObject(value)) return false\n\n const val = value as Record<string, unknown>\n if (val.version !== 0 && val.version !== 1) return false\n if (!isUint8(val.code)) return false\n\n if (!isObject(val.multihash)) return false\n const mh = val.multihash as Record<string, unknown>\n if (!isUint8(mh.code)) return false\n if (!(mh.digest instanceof Uint8Array)) return false\n\n // Ensure that the bytes array is consistent with other properties\n if (!(val.bytes instanceof Uint8Array)) return false\n if (val.bytes[0] !== val.version) return false\n if (val.bytes[1] !== val.code) return false\n if (val.bytes[2] !== mh.code) return false\n if (val.bytes[3] !== mh.digest.length) return false\n if (val.bytes.length !== 4 + mh.digest.length) return false\n if (!ui8Equals(val.bytes.subarray(4), mh.digest)) return false\n\n if (typeof val.equals !== 'function') return false\n if (val.equals(val) !== true) return false\n\n return true\n } catch {\n return false\n }\n }\n}\n\n/**\n * @internal\n */\nfunction isUint8(val: unknown): val is number {\n return Number.isInteger(val) && (val as number) >= 0 && (val as number) < 256\n}\n"]}
1
+ {"version":3,"file":"cid.js","sourceRoot":"","sources":["../src/cid.ts"],"names":[],"mappings":";;;AA+DA,0CAGC;AAsDD,8CAoBC;AAkFD,4BAEC;AAkBD,8BAOC;AAiBD,8BAEC;AAmCD,4BAaC;AAWD,sBAEC;AAaD,sBAGC;AAeD,sBAGC;AAaD,8BAMC;AAYD,4BAGC;AAYD,8CAKC;AA2BD,oCASC;AASD,oDAOC;AAQD,sCAgBC;AAiBD,8BAOC;AAUD,gCAGC;AAUD,wCAGC;AASD,sCAMC;AA3iBD,0CAAsC;AA8GV,oFA9GnB,SAAG,OA8GmB;AA7G/B,uDAAmE;AACnE,mDAAyD;AACzD,2CAAsC;AACtC,mDAA2C;AAE3C;;;;;;GAMG;AACU,QAAA,eAAe,GAAG,IAAI,CAAA;AAGnC;;;;;;GAMG;AACU,QAAA,cAAc,GAAG,IAAI,CAAA;AAGlC;;GAEG;AACU,QAAA,gBAAgB,GAAG,aAAM,CAAC,IAAI,CAAA;AAG3C;;GAEG;AACU,QAAA,gBAAgB,GAAG,aAAM,CAAC,IAAI,CAAA;AAqB3C;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,CAAY,EAAE,CAAY;IACxD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACxB,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,IAAA,yBAAS,EAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;AAC3D,CAAC;AA8CD;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAI/B,KAAuC;IACvC,MAAM,GAAG;IACP,sCAAsC;IACtC,SAAG,CAAC,KAAK,CAAC,KAAK,CAAC;QAChB,yCAAyC;QACzC,SAAG,CAAC,MAAM,CACR,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,IAAI,EACV,IAAA,eAAY,EAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAC3D,CAAA;IAEH,sEAAsE;IACtE,8EAA8E;IAC9E,6EAA6E;IAC7E,UAAU;IACV,OAAO,GAA2D,CAAA;AACpE,CAAC;AA4ED;;;;;GAKG;AACH,SAAgB,QAAQ,CAAC,GAAQ;IAC/B,OAAO,GAAG,CAAC,OAAO,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,sBAAc,CAAA;AACzD,CAAC;AAYD;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,GAAQ;IAChC,OAAO,CACL,GAAG,CAAC,OAAO,KAAK,CAAC;QACjB,CAAC,GAAG,CAAC,IAAI,KAAK,sBAAc,IAAI,GAAG,CAAC,IAAI,KAAK,uBAAe,CAAC;QAC7D,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,wBAAgB;QACvC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,gFAAgF;KAC1H,CAAA;AACH,CAAC;AAWD;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,GAAQ;IAChC,OAAO,GAAG,CAAC,IAAI,KAAK,uBAAe,IAAI,SAAS,CAAC,GAAG,CAAC,CAAA;AACvD,CAAC;AAmCD,SAAgB,QAAQ,CAAC,GAAQ,EAAE,OAAyB;IAC1D,QAAQ,OAAO,EAAE,MAAM,EAAE,CAAC;QACxB,KAAK,SAAS;YACZ,OAAO,IAAI,CAAA;QACb,KAAK,MAAM;YACT,OAAO,SAAS,CAAC,GAAG,CAAC,CAAA;QACvB,KAAK,MAAM;YACT,OAAO,SAAS,CAAC,GAAG,CAAC,CAAA;QACvB,KAAK,KAAK;YACR,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA;QACtB;YACE,MAAM,IAAI,SAAS,CAAC,uBAAuB,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;IACjE,CAAC;AACH,CAAC;AAWD,SAAgB,KAAK,CAAC,KAAc,EAAE,OAAyB;IAC7D,OAAO,mBAAmB,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAC/D,CAAC;AAaD,SAAgB,KAAK,CAAC,KAAc,EAAE,OAAyB;IAC7D,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACxE,OAAO,IAAI,CAAA;AACb,CAAC;AAeD,SAAgB,KAAK,CAAC,KAAc,EAAE,OAAyB;IAC7D,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACxE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;AACpC,CAAC;AAaD,SAAgB,SAAS,CACvB,QAAoB,EACpB,OAAyB;IAEzB,MAAM,GAAG,GAAG,SAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAChC,OAAO,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AAC5B,CAAC;AAYD,SAAgB,QAAQ,CAAC,KAAa,EAAE,OAAyB;IAC/D,MAAM,GAAG,GAAG,SAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5B,OAAO,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AAC5B,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,iBAAiB,CAC/B,KAAa,EACb,OAAyB;IAEzB,OAAO,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,KAAK,CAAA;AAC3D,CAAC;AA2BD,SAAgB,YAAY,CAC1B,KAAa,EACb,OAAyB;IAEzB,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAClC,KAAa,EACb,OAAyB;IAEzB,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;IACvC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,aAAa,CACjC,GAAQ,EACR,KAAiB;IAEjB,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,aAAM,CAAC,IAAI,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC5C,OAAO,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,aAAM,CAAC,IAAI,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC5C,OAAO,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;IAClD,CAAC;IAED,iDAAiD;IACjD,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,SAAS,CACvB,IAAY,EACZ,aAAwB,EACxB,MAAkB;IAElB,MAAM,GAAG,GAAQ,SAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAA,eAAY,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAA;IACxE,OAAO,GAAgC,CAAA;AACzC,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,UAAU,CAAC,KAAiB;IAChD,MAAM,SAAS,GAAG,MAAM,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,OAAO,SAAG,CAAC,QAAQ,CAAC,uBAAe,EAAE,SAAS,CAAY,CAAA;AAC5D,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,cAAc,CAAC,KAAiB;IACpD,MAAM,SAAS,GAAG,MAAM,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,OAAO,SAAG,CAAC,QAAQ,CAAC,sBAAc,EAAE,SAAS,CAAW,CAAA;AAC1D,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,aAAa,CAAC,MAAkB;IAC9C,gBAAgB;IAChB,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,SAAS,CAAC,sBAAc,EAAE,aAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACvD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,SAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,wEAAwE;QACxE,YAAY;QACZ,OAAQ,KAAgC,CAAC,KAAK,IAAI,IAAI,CAAA;IACxD,CAAC;SAAM,CAAC;QACN,gDAAgD;QAChD,IAAI,CAAC;YACH,IAAI,CAAC,IAAA,oBAAQ,EAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YAElC,MAAM,GAAG,GAAG,KAAgC,CAAA;YAC5C,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAA;YAEpC,IAAI,CAAC,IAAA,oBAAQ,EAAC,GAAG,CAAC,SAAS,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC1C,MAAM,EAAE,GAAG,GAAG,CAAC,SAAoC,CAAA;YACnD,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAA;YACnC,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,YAAY,UAAU,CAAC;gBAAE,OAAO,KAAK,CAAA;YAEpD,kEAAkE;YAClE,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,YAAY,UAAU,CAAC;gBAAE,OAAO,KAAK,CAAA;YACpD,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAA;YAC9C,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI;gBAAE,OAAO,KAAK,CAAA;YAC3C,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI;gBAAE,OAAO,KAAK,CAAA;YAC1C,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAA;YACnD,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAA;YAC3D,IAAI,CAAC,IAAA,yBAAS,EAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC;gBAAE,OAAO,KAAK,CAAA;YAE9D,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAA;YAClD,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAA;YAE1C,OAAO,IAAI,CAAA;QACb,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,GAAY;IAC3B,OAAO,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAK,GAAc,IAAI,CAAC,IAAK,GAAc,GAAG,GAAG,CAAA;AAC/E,CAAC","sourcesContent":["import { CID } from 'multiformats/cid'\nimport { create as createDigest } from 'multiformats/hashes/digest'\nimport { sha256, sha512 } from 'multiformats/hashes/sha2'\nimport { isObject } from './object.js'\nimport { ui8Equals } from './uint8array.js'\n\n/**\n * Codec code that indicates the CID references a CBOR-encoded data structure.\n *\n * Used when encoding structured data in AT Protocol repositories.\n *\n * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}\n */\nexport const CBOR_DATA_CODEC = 0x71\nexport type CBOR_DATA_CODEC = typeof CBOR_DATA_CODEC\n\n/**\n * Codec code that indicates the CID references raw binary data (like media blobs).\n *\n * Used in DASL CIDs for binary blobs like images and media.\n *\n * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}\n */\nexport const RAW_DATA_CODEC = 0x55\nexport type RAW_DATA_CODEC = typeof RAW_DATA_CODEC\n\n/**\n * Hash code that indicates that a CID uses SHA-256.\n */\nexport const SHA256_HASH_CODE = sha256.code\nexport type SHA256_HASH_CODE = typeof SHA256_HASH_CODE\n\n/**\n * Hash code that indicates that a CID uses SHA-512.\n */\nexport const SHA512_HASH_CODE = sha512.code\nexport type SHA512_HASH_CODE = typeof SHA512_HASH_CODE\n\n/**\n * Represent the hash part of a CID, which includes the hash algorithm code and\n * the raw digest bytes.\n *\n * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}\n */\nexport interface Multihash<THashCode extends number = number> {\n /**\n * Code of the hash algorithm (e.g., SHA256_HASH_CODE).\n */\n code: THashCode\n\n /**\n * Raw digest bytes.\n */\n digest: Uint8Array\n}\n\n/**\n * Compares two {@link Multihash} for equality.\n *\n * @param a - First {@link Multihash}\n * @param b - Second {@link Multihash}\n * @returns `true` if both multihashes have the same code and digest\n */\nexport function multihashEquals(a: Multihash, b: Multihash): boolean {\n if (a === b) return true\n return a.code === b.code && ui8Equals(a.digest, b.digest)\n}\n\ndeclare module 'multiformats/cid' {\n /**\n * @deprecated use the {@link Cid} interface from `@atproto/lex-data`, and\n * related helpers ({@link isCid}, {@link ifCid}, {@link asCid},\n * {@link parseCid}, {@link decodeCid}), instead.\n *\n * This is marked as deprecated because we want to discourage direct usage of\n * `multiformats/cid` in dependent packages, and instead have them rely on the\n * {@link Cid} interface from `@atproto/lex-data`. The {@link CID} class from\n * `multiformats` version <10 has compatibility issues with certain TypeScript\n * configuration, which can lead to type errors in dependent packages.\n *\n * We are stuck with version 9 because `@atproto` packages did not drop\n * CommonJS support yet, and multiformats version 10 only supports ES modules.\n *\n * In order to avoid compatibility issues, while preparing for future breaking\n * changes (CID in multiformats v10+ has a slightly different interface), as\n * we update or swap out `multiformats`, `@atproto/lex-data` provides its own\n * stable {@link Cid} interface.\n */\n interface CID {}\n}\n\n// multiformats' CID class is not very portable because:\n//\n// - In dependent packages that use \"moduleResolution\" set to \"node16\",\n// \"nodenext\" or \"bundler\", TypeScript fails to properly resolve the\n// multiformats package when importing CID from @atproto/lex-data. This causes\n// type errors in those packages. This is caused by the fact that the\n// multiformats version <10 (which is the last version that supports CommonJS)\n// uses \"exports\" field in package.json, which do not contain \"types\"\n// entrypoints.\n// https://www.npmjs.com/package/multiformats/v/9.9.0?activeTab=code\n// - By defining our own interface and helper functions, we can have more\n// control over the public API exposed by this package.\n// - It allow us to have a stable interface in case we need to swap out, or\n// eventually update multiformats (should we choose to drop CommonJS support)\n// in the future.\n\n// @NOTE Even though it is not portable, we still re-export CID here so that\n// dependent packages where it can be used, have access to it (instead of\n// importing directly from \"multiformats\" or \"multiformats/cid\").\nexport { /** @deprecated */ CID }\n\n/**\n * Converts a {@link Cid} to a multiformats {@link CID} instance.\n *\n * @deprecated Packages depending on `@atproto/lex-data` should use the\n * {@link Cid} interface instead of relying on `multiformats`'s {@link CID}\n * implementation directly. This is to avoid compatibility issues, and in order\n * to allow better portability, compatibility and future updates.\n */\nexport function asMultiformatsCID<\n TVersion extends 0 | 1 = 0 | 1,\n TCodec extends number = number,\n THashCode extends number = number,\n>(input: Cid<TVersion, TCodec, THashCode>) {\n const cid =\n // Already a multiformats CID instance\n CID.asCID(input) ??\n // Create a new multiformats CID instance\n CID.create(\n input.version,\n input.code,\n createDigest(input.multihash.code, input.multihash.digest),\n )\n\n // @NOTE: the \"satisfies\" operator is used here to ensure that the Cid\n // interface is indeed compatible with multiformats' CID implementation, which\n // allows us to safely rely on multiformats' CID implementation where Cid are\n // needed.\n return cid satisfies Cid as CID & Cid<TVersion, TCodec, THashCode>\n}\n\n/**\n * Content Identifier (CID) for addressing content by its hash.\n *\n * CIDs are self-describing content addresses used throughout AT Protocol for\n * linking to data by its cryptographic hash. This interface provides a\n * stable API that is compatible with the `multiformats` library but avoids\n * direct dependency issues.\n *\n * @typeParam TVersion - CID version (0 or 1)\n * @typeParam TCodec - Multicodec content type code\n * @typeParam THashCode - Multihash algorithm code\n *\n * @example\n * ```typescript\n * import type { Cid } from '@atproto/lex-data'\n * import { parseCid, isCid } from '@atproto/lex-data'\n *\n * // Parse a CID from a string\n * const cid: Cid = parseCid('bafyreib...')\n *\n * // Check if a value is a CID\n * if (isCid(value)) {\n * console.log(cid.toString())\n * }\n * ```\n *\n * @see {@link isCid} to check if a value is a valid CID\n * @see {@link parseCid} to parse a CID from a string\n * @see {@link decodeCid} to decode a CID from bytes\n * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}\n */\nexport interface Cid<\n TVersion extends 0 | 1 = 0 | 1,\n TCodec extends number = number,\n THashCode extends number = number,\n> {\n // @NOTE This interface is compatible with multiformats' CID implementation\n // which we are using under the hood.\n\n /** CID version (0 or 1). AT Protocol uses CIDv1. */\n readonly version: TVersion\n /** Coded (e.g., {@link CBOR_DATA_CODEC}, {@link RAW_DATA_CODEC}). */\n readonly code: TCodec\n /** The multihash containing the hash algorithm and digest. */\n readonly multihash: Multihash<THashCode>\n\n /**\n * Binary representation of the whole CID.\n */\n readonly bytes: Uint8Array\n\n /**\n * Compares this CID with another for equality.\n *\n * @param other - The CID to compare with\n * @returns `true` if the CIDs are equal\n */\n equals(other: Cid): boolean\n\n /**\n * Returns the string representation of this CID (base32 for v1, base58btc for v0).\n */\n toString(): string\n}\n\n/**\n * Represents the CID of raw binary data (like media blobs).\n *\n * The use of {@link SHA256_HASH_CODE} is recommended but not required for raw CIDs.\n *\n * @see {@link https://atproto.com/specs/data-model#link-and-cid-formats AT Protocol Data Model - Link and CID Formats}\n */\nexport type RawCid = Cid<1, RAW_DATA_CODEC>\n\n/**\n * Type guard to check if a CID is a raw binary CID.\n *\n * @param cid - The CID to check\n * @returns `true` if the CID is a version 1 CID with raw multicodec\n */\nexport function isRawCid(cid: Cid): cid is RawCid {\n return cid.version === 1 && cid.code === RAW_DATA_CODEC\n}\n\n/**\n * Represents a DASL compliant CID.\n *\n * DASL CIDs are version 1 CIDs using either raw or DAG-CBOR multicodec\n * with SHA-256 multihash.\n *\n * @see {@link https://dasl.ing/cid.html Content IDs (DASL)}\n */\nexport type DaslCid = Cid<1, RAW_DATA_CODEC | CBOR_DATA_CODEC, SHA256_HASH_CODE>\n\n/**\n * Type guard to check if a CID is DASL compliant.\n *\n * @param cid - The CID to check\n * @returns `true` if the CID is DASL compliant (v1, raw/dag-cbor, sha256)\n */\nexport function isDaslCid(cid: Cid): cid is DaslCid {\n return (\n cid.version === 1 &&\n (cid.code === RAW_DATA_CODEC || cid.code === CBOR_DATA_CODEC) &&\n cid.multihash.code === SHA256_HASH_CODE &&\n cid.multihash.digest.byteLength === 0x20 // Should always be 32 bytes (256 bits) for SHA-256, but double-checking anyways\n )\n}\n\n/**\n * Represents the CID of AT Protocol DAG-CBOR data (like repository MST nodes).\n *\n * CBOR CIDs are version 1 CIDs using DAG-CBOR multicodec with SHA-256 multihash.\n *\n * @see {@link https://atproto.com/specs/data-model#link-and-cid-formats AT Protocol Data Model - Link and CID Formats}\n */\nexport type CborCid = Cid<1, CBOR_DATA_CODEC, SHA256_HASH_CODE>\n\n/**\n * Type guard to check if a CID is a DAG-CBOR CID.\n *\n * @param cid - The CID to check\n * @returns `true` if the CID is a DAG-CBOR CID (v1, dag-cbor, sha256)\n */\nexport function isCborCid(cid: Cid): cid is CborCid {\n return cid.code === CBOR_DATA_CODEC && isDaslCid(cid)\n}\n\n/**\n * Options for checking CID flavor constraints.\n */\nexport type CheckCidOptions = {\n /**\n * The CID flavor to check for.\n * - `'raw'` - Raw binary CID ({@link RawCid})\n * - `'cbor'` - DAG-CBOR CID ({@link CborCid})\n * - `'dasl'` - DASL compliant CID ({@link DaslCid})\n */\n flavor?: 'raw' | 'cbor' | 'dasl'\n}\n\n/**\n * Infers the CID type based on check options.\n *\n * @typeParam TOptions - The options used for checking\n */\nexport type InferCheckedCid<TOptions> = TOptions extends { flavor: 'raw' }\n ? RawCid\n : TOptions extends { flavor: 'cbor' }\n ? CborCid\n : Cid\n\n/**\n * Type guard to check whether a {@link Cid} instance meets specific flavor\n * constraints.\n */\nexport function checkCid<TOptions extends CheckCidOptions>(\n cid: Cid,\n options: TOptions,\n): cid is InferCheckedCid<TOptions>\nexport function checkCid(cid: Cid, options?: CheckCidOptions): boolean\nexport function checkCid(cid: Cid, options?: CheckCidOptions): boolean {\n switch (options?.flavor) {\n case undefined:\n return true\n case 'cbor':\n return isCborCid(cid)\n case 'dasl':\n return isDaslCid(cid)\n case 'raw':\n return isRawCid(cid)\n default:\n throw new TypeError(`Unknown CID flavor: ${options?.flavor}`)\n }\n}\n\n/**\n * Type guard to check whether a value is a valid {@link Cid} instance,\n * optionally checking for specific flavor constraints.\n */\nexport function isCid<TOptions extends CheckCidOptions>(\n value: unknown,\n options: TOptions,\n): value is InferCheckedCid<TOptions>\nexport function isCid(value: unknown, options?: CheckCidOptions): value is Cid\nexport function isCid(value: unknown, options?: CheckCidOptions): value is Cid {\n return isCidImplementation(value) && checkCid(value, options)\n}\n\n/**\n * Returns the input value as a {@link Cid} if it is valid, or `null` otherwise.\n */\nexport function ifCid<TValue, TOptions extends CheckCidOptions>(\n value: unknown,\n options: TOptions,\n): (TValue & InferCheckedCid<TOptions>) | null\nexport function ifCid<TValue>(\n value: TValue,\n options?: CheckCidOptions,\n): (TValue & Cid) | null\nexport function ifCid(value: unknown, options?: CheckCidOptions): Cid | null {\n if (isCidImplementation(value) && checkCid(value, options)) return value\n return null\n}\n\n/**\n * Returns the input value as a {@link Cid} if it is valid.\n *\n * @throws if the input is not a valid {@link Cid}.\n */\nexport function asCid<TValue, TOptions extends CheckCidOptions>(\n value: TValue,\n options: TOptions,\n): TValue & InferCheckedCid<TOptions>\nexport function asCid<TValue>(\n value: TValue,\n options?: CheckCidOptions,\n): Cid & TValue\nexport function asCid(value: unknown, options?: CheckCidOptions): Cid {\n if (isCidImplementation(value) && checkCid(value, options)) return value\n throw new Error('Not a valid CID')\n}\n\n/**\n * Decodes a CID from its binary representation.\n *\n * @see {@link https://dasl.ing/cid.html DASL-CIDs}\n * @throws if the input do not represent a valid DASL {@link Cid}\n */\nexport function decodeCid<TOptions extends CheckCidOptions>(\n cidBytes: Uint8Array,\n options: TOptions,\n): InferCheckedCid<TOptions>\nexport function decodeCid(cidBytes: Uint8Array, options?: CheckCidOptions): Cid\nexport function decodeCid(\n cidBytes: Uint8Array,\n options?: CheckCidOptions,\n): Cid {\n const cid = CID.decode(cidBytes)\n return asCid(cid, options)\n}\n\n/**\n * Parses a CID string into a Cid object.\n *\n * @throws if the input is not a valid CID string.\n */\nexport function parseCid<TOptions extends CheckCidOptions>(\n input: string,\n options: TOptions,\n): InferCheckedCid<TOptions>\nexport function parseCid(input: string, options?: CheckCidOptions): Cid\nexport function parseCid(input: string, options?: CheckCidOptions): Cid {\n const cid = CID.parse(input)\n return asCid(cid, options)\n}\n\n/**\n * Validates that a string is a valid CID representation.\n *\n * Unlike {@link parseCid}, this function returns a boolean instead of throwing.\n * It also verifies that the string is the canonical representation of the CID.\n *\n * @param input - The string to validate\n * @param options - Optional flavor constraints\n * @returns `true` if the string is a valid CID\n */\nexport function validateCidString(\n input: string,\n options?: CheckCidOptions,\n): boolean {\n return parseCidSafe(input, options)?.toString() === input\n}\n\n/**\n * Safely parses a CID string, returning `null` on failure instead of throwing.\n *\n * @param input - The string to parse\n * @param options - Optional flavor constraints\n * @returns The parsed CID, or `null` if parsing fails\n *\n * @example\n * ```typescript\n * import { parseCidSafe } from '@atproto/lex-data'\n *\n * const cid = parseCidSafe('bafyreib...')\n * if (cid) {\n * console.log(cid.toString())\n * }\n * ```\n */\nexport function parseCidSafe<TOptions extends CheckCidOptions>(\n input: string,\n options: TOptions,\n): InferCheckedCid<TOptions> | null\nexport function parseCidSafe(\n input: string,\n options?: CheckCidOptions,\n): Cid | null\nexport function parseCidSafe(\n input: string,\n options?: CheckCidOptions,\n): Cid | null {\n try {\n return parseCid(input, options)\n } catch {\n return null\n }\n}\n\n/**\n * Ensures that a string is a valid CID representation.\n *\n * @param input - The string to validate\n * @param options - Optional flavor constraints\n * @throws If the string is not a valid CID\n */\nexport function ensureValidCidString(\n input: string,\n options?: CheckCidOptions,\n): void {\n if (!validateCidString(input, options)) {\n throw new Error(`Invalid CID string`)\n }\n}\n\n/**\n * Verifies whether the multihash of a given {@link cid} matches the hash of the provided {@link bytes}.\n * @params cid The CID to match against the bytes.\n * @params bytes The bytes to verify.\n * @returns true if the CID matches the bytes, false otherwise.\n */\nexport async function isCidForBytes(\n cid: Cid,\n bytes: Uint8Array,\n): Promise<boolean> {\n if (cid.multihash.code === sha256.code) {\n const multihash = await sha256.digest(bytes)\n return multihashEquals(multihash, cid.multihash)\n }\n\n if (cid.multihash.code === sha512.code) {\n const multihash = await sha512.digest(bytes)\n return multihashEquals(multihash, cid.multihash)\n }\n\n // Don't know how to verify other multihash codes\n throw new Error('Unsupported CID multihash')\n}\n\n/**\n * Creates a CID from a multicodec, multihash code, and digest.\n *\n * @param code - The multicodec content type code\n * @param multihashCode - The multihash algorithm code\n * @param digest - The raw hash digest bytes\n * @returns A new CIDv1 instance\n *\n * @example\n * ```typescript\n * import { createCid, RAW_DATA_CODEC, SHA256_HASH_CODE } from '@atproto/lex-data'\n *\n * const cid = createCid(RAW_DATA_CODEC, SHA256_HASH_CODE, hashDigest)\n * ```\n */\nexport function createCid<TCodec extends number, THashCode extends number>(\n code: TCodec,\n multihashCode: THashCode,\n digest: Uint8Array,\n) {\n const cid: Cid = CID.createV1(code, createDigest(multihashCode, digest))\n return cid as Cid<1, TCodec, THashCode>\n}\n\n/**\n * Creates a DAG-CBOR CID for the given CBOR bytes.\n *\n * Computes the SHA-256 hash of the bytes and creates a CIDv1 with DAG-CBOR multicodec.\n *\n * @param bytes - The CBOR-encoded bytes to hash\n * @returns A promise that resolves to the CborCid\n */\nexport async function cidForCbor(bytes: Uint8Array): Promise<CborCid> {\n const multihash = await sha256.digest(bytes)\n return CID.createV1(CBOR_DATA_CODEC, multihash) as CborCid\n}\n\n/**\n * Creates a raw CID for the given binary bytes.\n *\n * Computes the SHA-256 hash of the bytes and creates a CIDv1 with raw multicodec.\n *\n * @param bytes - The raw binary bytes to hash\n * @returns A promise that resolves to the RawCid\n */\nexport async function cidForRawBytes(bytes: Uint8Array): Promise<RawCid> {\n const multihash = await sha256.digest(bytes)\n return CID.createV1(RAW_DATA_CODEC, multihash) as RawCid\n}\n\n/**\n * Creates a raw CID from an existing SHA-256 hash digest.\n *\n * @param digest - The SHA-256 hash digest (must be 32 bytes)\n * @returns A RawCid with the given digest\n * @throws If the digest length is not 32 bytes\n */\nexport function cidForRawHash(digest: Uint8Array): RawCid {\n // Fool-proofing\n if (digest.length !== 32) {\n throw new Error(`Invalid SHA-256 hash length: ${digest.length}`)\n }\n return createCid(RAW_DATA_CODEC, sha256.code, digest)\n}\n\nfunction isCidImplementation(value: unknown): value is Cid {\n if (CID.asCID(value)) {\n // CIDs created using older multiformats versions did not have a \"bytes\"\n // property.\n return (value as { bytes?: Uint8Array }).bytes != null\n } else {\n // Unknown implementation, do a structural check\n try {\n if (!isObject(value)) return false\n\n const val = value as Record<string, unknown>\n if (val.version !== 0 && val.version !== 1) return false\n if (!isUint8(val.code)) return false\n\n if (!isObject(val.multihash)) return false\n const mh = val.multihash as Record<string, unknown>\n if (!isUint8(mh.code)) return false\n if (!(mh.digest instanceof Uint8Array)) return false\n\n // Ensure that the bytes array is consistent with other properties\n if (!(val.bytes instanceof Uint8Array)) return false\n if (val.bytes[0] !== val.version) return false\n if (val.bytes[1] !== val.code) return false\n if (val.bytes[2] !== mh.code) return false\n if (val.bytes[3] !== mh.digest.length) return false\n if (val.bytes.length !== 4 + mh.digest.length) return false\n if (!ui8Equals(val.bytes.subarray(4), mh.digest)) return false\n\n if (typeof val.equals !== 'function') return false\n if (val.equals(val) !== true) return false\n\n return true\n } catch {\n return false\n }\n }\n}\n\nfunction isUint8(val: unknown): val is number {\n return Number.isInteger(val) && (val as number) >= 0 && (val as number) < 256\n}\n"]}
@@ -1,3 +1,41 @@
1
1
  import { LexValue } from './lex.js';
2
+ /**
3
+ * Performs deep equality comparison between two {@link LexValue}s.
4
+ *
5
+ * This function correctly handles all Lexicon data types including:
6
+ * - Primitives (string, number, boolean, null)
7
+ * - Arrays (recursive element comparison)
8
+ * - Objects/LexMaps (recursive key-value comparison)
9
+ * - Uint8Arrays (byte-by-byte comparison)
10
+ * - CIDs (using CID equality)
11
+ *
12
+ * @param a - First LexValue to compare
13
+ * @param b - Second LexValue to compare
14
+ * @returns `true` if the values are deeply equal
15
+ * @throws {TypeError} If either value is not a valid LexValue (e.g., contains unsupported types)
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { lexEquals } from '@atproto/lex-data'
20
+ *
21
+ * // Primitives
22
+ * lexEquals('hello', 'hello') // true
23
+ * lexEquals(42, 42) // true
24
+ *
25
+ * // Arrays
26
+ * lexEquals([1, 2, 3], [1, 2, 3]) // true
27
+ * lexEquals([1, 2], [1, 2, 3]) // false
28
+ *
29
+ * // Objects
30
+ * lexEquals({ a: 1, b: 2 }, { a: 1, b: 2 }) // true
31
+ * lexEquals({ a: 1 }, { a: 1, b: 2 }) // false
32
+ *
33
+ * // CIDs
34
+ * lexEquals(cid1, cid2) // true if CIDs are equal
35
+ *
36
+ * // Uint8Arrays
37
+ * lexEquals(new Uint8Array([1, 2]), new Uint8Array([1, 2])) // true
38
+ * ```
39
+ */
2
40
  export declare function lexEquals(a: LexValue, b: LexValue): boolean;
3
41
  //# sourceMappingURL=lex-equals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lex-equals.d.ts","sourceRoot":"","sources":["../src/lex-equals.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAInC,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CA+E3D"}
1
+ {"version":3,"file":"lex-equals.d.ts","sourceRoot":"","sources":["../src/lex-equals.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAInC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CA+E3D"}
@@ -4,6 +4,44 @@ exports.lexEquals = lexEquals;
4
4
  const cid_js_1 = require("./cid.js");
5
5
  const object_js_1 = require("./object.js");
6
6
  const uint8array_js_1 = require("./uint8array.js");
7
+ /**
8
+ * Performs deep equality comparison between two {@link LexValue}s.
9
+ *
10
+ * This function correctly handles all Lexicon data types including:
11
+ * - Primitives (string, number, boolean, null)
12
+ * - Arrays (recursive element comparison)
13
+ * - Objects/LexMaps (recursive key-value comparison)
14
+ * - Uint8Arrays (byte-by-byte comparison)
15
+ * - CIDs (using CID equality)
16
+ *
17
+ * @param a - First LexValue to compare
18
+ * @param b - Second LexValue to compare
19
+ * @returns `true` if the values are deeply equal
20
+ * @throws {TypeError} If either value is not a valid LexValue (e.g., contains unsupported types)
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import { lexEquals } from '@atproto/lex-data'
25
+ *
26
+ * // Primitives
27
+ * lexEquals('hello', 'hello') // true
28
+ * lexEquals(42, 42) // true
29
+ *
30
+ * // Arrays
31
+ * lexEquals([1, 2, 3], [1, 2, 3]) // true
32
+ * lexEquals([1, 2], [1, 2, 3]) // false
33
+ *
34
+ * // Objects
35
+ * lexEquals({ a: 1, b: 2 }, { a: 1, b: 2 }) // true
36
+ * lexEquals({ a: 1 }, { a: 1, b: 2 }) // false
37
+ *
38
+ * // CIDs
39
+ * lexEquals(cid1, cid2) // true if CIDs are equal
40
+ *
41
+ * // Uint8Arrays
42
+ * lexEquals(new Uint8Array([1, 2]), new Uint8Array([1, 2])) // true
43
+ * ```
44
+ */
7
45
  function lexEquals(a, b) {
8
46
  if (Object.is(a, b)) {
9
47
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"lex-equals.js","sourceRoot":"","sources":["../src/lex-equals.ts"],"names":[],"mappings":"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","sourcesContent":["import { ifCid, isCid } from './cid.js'\nimport { LexValue } from './lex.js'\nimport { isPlainObject } from './object.js'\nimport { ui8Equals } from './uint8array.js'\n\nexport function lexEquals(a: LexValue, b: LexValue): boolean {\n if (Object.is(a, b)) {\n return true\n }\n\n if (\n a == null ||\n b == null ||\n typeof a !== 'object' ||\n typeof b !== 'object'\n ) {\n return false\n }\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b)) {\n return false\n }\n if (a.length !== b.length) {\n return false\n }\n for (let i = 0; i < a.length; i++) {\n if (!lexEquals(a[i], b[i])) {\n return false\n }\n }\n return true\n } else if (Array.isArray(b)) {\n return false\n }\n\n if (ArrayBuffer.isView(a)) {\n if (!ArrayBuffer.isView(b)) return false\n return ui8Equals(a, b)\n } else if (ArrayBuffer.isView(b)) {\n return false\n }\n\n if (isCid(a)) {\n // @NOTE CID.equals returns its argument when it is falsy (e.g. null or\n // undefined) so we need to explicitly check that the output is \"true\".\n return ifCid(b)?.equals(a) === true\n } else if (isCid(b)) {\n return false\n }\n\n if (!isPlainObject(a) || !isPlainObject(b)) {\n // Foolproof (should never happen)\n throw new TypeError(\n 'Invalid LexValue (expected CID, Uint8Array, or LexMap)',\n )\n }\n\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n\n if (aKeys.length !== bKeys.length) {\n return false\n }\n\n for (const key of aKeys) {\n const aVal = a[key]\n const bVal = b[key]\n\n // Needed because of the optional index signature in the Lex object type\n // though, in practice, aVal should never be undefined here.\n if (aVal === undefined) {\n if (bVal === undefined && bKeys.includes(key)) continue\n return false\n } else if (bVal === undefined) {\n return false\n }\n\n if (!lexEquals(aVal, bVal)) {\n return false\n }\n }\n\n return true\n}\n"]}
1
+ {"version":3,"file":"lex-equals.js","sourceRoot":"","sources":["../src/lex-equals.ts"],"names":[],"mappings":";;AA2CA,8BA+EC;AA1HD,qCAAuC;AAEvC,2CAA2C;AAC3C,mDAA2C;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,SAAgB,SAAS,CAAC,CAAW,EAAE,CAAW;IAChD,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IACE,CAAC,IAAI,IAAI;QACT,CAAC,IAAI,IAAI;QACT,OAAO,CAAC,KAAK,QAAQ;QACrB,OAAO,CAAC,KAAK,QAAQ,EACrB,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACtB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAA;QACd,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3B,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QACxC,OAAO,IAAA,yBAAS,EAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACxB,CAAC;SAAM,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,IAAA,cAAK,EAAC,CAAC,CAAC,EAAE,CAAC;QACb,uEAAuE;QACvE,uEAAuE;QACvE,OAAO,IAAA,cAAK,EAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACrC,CAAC;SAAM,IAAI,IAAA,cAAK,EAAC,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,CAAC,IAAA,yBAAa,EAAC,CAAC,CAAC,IAAI,CAAC,IAAA,yBAAa,EAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,kCAAkC;QAClC,MAAM,IAAI,SAAS,CACjB,wDAAwD,CACzD,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QAClC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QACnB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QAEnB,wEAAwE;QACxE,4DAA4D;QAC5D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,SAAQ;YACvD,OAAO,KAAK,CAAA;QACd,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["import { ifCid, isCid } from './cid.js'\nimport { LexValue } from './lex.js'\nimport { isPlainObject } from './object.js'\nimport { ui8Equals } from './uint8array.js'\n\n/**\n * Performs deep equality comparison between two {@link LexValue}s.\n *\n * This function correctly handles all Lexicon data types including:\n * - Primitives (string, number, boolean, null)\n * - Arrays (recursive element comparison)\n * - Objects/LexMaps (recursive key-value comparison)\n * - Uint8Arrays (byte-by-byte comparison)\n * - CIDs (using CID equality)\n *\n * @param a - First LexValue to compare\n * @param b - Second LexValue to compare\n * @returns `true` if the values are deeply equal\n * @throws {TypeError} If either value is not a valid LexValue (e.g., contains unsupported types)\n *\n * @example\n * ```typescript\n * import { lexEquals } from '@atproto/lex-data'\n *\n * // Primitives\n * lexEquals('hello', 'hello') // true\n * lexEquals(42, 42) // true\n *\n * // Arrays\n * lexEquals([1, 2, 3], [1, 2, 3]) // true\n * lexEquals([1, 2], [1, 2, 3]) // false\n *\n * // Objects\n * lexEquals({ a: 1, b: 2 }, { a: 1, b: 2 }) // true\n * lexEquals({ a: 1 }, { a: 1, b: 2 }) // false\n *\n * // CIDs\n * lexEquals(cid1, cid2) // true if CIDs are equal\n *\n * // Uint8Arrays\n * lexEquals(new Uint8Array([1, 2]), new Uint8Array([1, 2])) // true\n * ```\n */\nexport function lexEquals(a: LexValue, b: LexValue): boolean {\n if (Object.is(a, b)) {\n return true\n }\n\n if (\n a == null ||\n b == null ||\n typeof a !== 'object' ||\n typeof b !== 'object'\n ) {\n return false\n }\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b)) {\n return false\n }\n if (a.length !== b.length) {\n return false\n }\n for (let i = 0; i < a.length; i++) {\n if (!lexEquals(a[i], b[i])) {\n return false\n }\n }\n return true\n } else if (Array.isArray(b)) {\n return false\n }\n\n if (ArrayBuffer.isView(a)) {\n if (!ArrayBuffer.isView(b)) return false\n return ui8Equals(a, b)\n } else if (ArrayBuffer.isView(b)) {\n return false\n }\n\n if (isCid(a)) {\n // @NOTE CID.equals returns its argument when it is falsy (e.g. null or\n // undefined) so we need to explicitly check that the output is \"true\".\n return ifCid(b)?.equals(a) === true\n } else if (isCid(b)) {\n return false\n }\n\n if (!isPlainObject(a) || !isPlainObject(b)) {\n // Foolproof (should never happen)\n throw new TypeError(\n 'Invalid LexValue (expected CID, Uint8Array, or LexMap)',\n )\n }\n\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n\n if (aKeys.length !== bKeys.length) {\n return false\n }\n\n for (const key of aKeys) {\n const aVal = a[key]\n const bVal = b[key]\n\n // Needed because of the optional index signature in the Lex object type\n // though, in practice, aVal should never be undefined here.\n if (aVal === undefined) {\n if (bVal === undefined && bKeys.includes(key)) continue\n return false\n } else if (bVal === undefined) {\n return false\n }\n\n if (!lexEquals(aVal, bVal)) {\n return false\n }\n }\n\n return true\n}\n"]}
@@ -1,17 +1,96 @@
1
+ /**
2
+ * Error code type for Lexicon errors.
3
+ *
4
+ * Error codes identify the type of error that occurred (e.g., 'InvalidRequest').
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import type { LexErrorCode } from '@atproto/lex-data'
9
+ *
10
+ * const errorCode: LexErrorCode = 'InvalidRequest'
11
+ * ```
12
+ */
1
13
  export type LexErrorCode = string & NonNullable<unknown>;
14
+ /**
15
+ * JSON-serializable error data structure.
16
+ *
17
+ * This is the standard format for error responses in the AT Protocol XRPC protocol.
18
+ *
19
+ * @typeParam N - The specific error code type
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import type { LexErrorData } from '@atproto/lex-data'
24
+ *
25
+ * const errorData: LexErrorData = {
26
+ * error: 'InvalidRequest',
27
+ * message: 'Missing required field: handle'
28
+ * }
29
+ * ```
30
+ */
2
31
  export type LexErrorData<N extends LexErrorCode = LexErrorCode> = {
32
+ /** The error code identifying the type of error. */
3
33
  error: N;
34
+ /** Optional human-readable error message. */
4
35
  message?: string;
5
36
  };
37
+ /**
38
+ * Error class for Lexicon-related errors.
39
+ *
40
+ * LexError extends the standard JavaScript {@link Error} with AT Protocol-specific
41
+ * functionality including:
42
+ * - An error code for programmatic error handling
43
+ * - JSON serialization for API responses
44
+ * - HTTP Response generation
45
+ *
46
+ * @typeParam N - The specific error code type
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * import { LexError } from '@atproto/lex-data'
51
+ *
52
+ * // Throw a Lexicon error
53
+ * throw new LexError('InvalidRequest', 'Missing required field')
54
+ *
55
+ * // Create and serialize
56
+ * const error = new LexError('NotFound', 'Record not found')
57
+ * console.log(error.toJSON())
58
+ * // { error: 'NotFound', message: 'Record not found' }
59
+ *
60
+ * // Return as HTTP response
61
+ * return error.toResponse() // 400 Bad Request with JSON body
62
+ * ```
63
+ */
6
64
  export declare class LexError<N extends LexErrorCode = LexErrorCode> extends Error {
7
65
  readonly error: N;
8
66
  name: string;
67
+ /**
68
+ * Creates a new LexError.
69
+ *
70
+ * @param error - The error code identifying the type of error
71
+ * @param message - Optional human-readable error message
72
+ * @param options - Standard Error options (e.g., cause)
73
+ */
9
74
  constructor(error: N, message?: string, // Defaults to empty string in Error constructor
10
75
  options?: ErrorOptions);
76
+ /**
77
+ * Returns a string representation of this error.
78
+ *
79
+ * @returns A formatted string: "LexError: [ERROR_CODE] message"
80
+ */
11
81
  toString(): string;
82
+ /**
83
+ * Converts this error to a JSON-serializable object.
84
+ *
85
+ * @returns The error data suitable for JSON serialization
86
+ */
12
87
  toJSON(): LexErrorData<N>;
13
88
  /**
14
- * Translate into an HTTP response for downstream clients.
89
+ * Converts this error to an HTTP Response for downstream clients.
90
+ *
91
+ * Returns a 400 Bad Request response with the JSON-serialized error body.
92
+ *
93
+ * @returns A Response object with status 400 and JSON body
15
94
  */
16
95
  toResponse(): Response;
17
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"lex-error.d.ts","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;AAExD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI;IAChE,KAAK,EAAE,CAAC,CAAA;IACR,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,qBAAa,QAAQ,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,CAAE,SAAQ,KAAK;IAItE,QAAQ,CAAC,KAAK,EAAE,CAAC;IAHnB,IAAI,SAAa;gBAGN,KAAK,EAAE,CAAC,EACjB,OAAO,CAAC,EAAE,MAAM,EAAE,gDAAgD;IAClE,OAAO,CAAC,EAAE,YAAY;IAKxB,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC;IAKzB;;OAEG;IACH,UAAU,IAAI,QAAQ;CAGvB"}
1
+ {"version":3,"file":"lex-error.d.ts","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;AAExD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI;IAChE,oDAAoD;IACpD,KAAK,EAAE,CAAC,CAAA;IACR,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,QAAQ,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,CAAE,SAAQ,KAAK;IAWtE,QAAQ,CAAC,KAAK,EAAE,CAAC;IAVnB,IAAI,SAAa;IAEjB;;;;;;OAMG;gBAEQ,KAAK,EAAE,CAAC,EACjB,OAAO,CAAC,EAAE,MAAM,EAAE,gDAAgD;IAClE,OAAO,CAAC,EAAE,YAAY;IAKxB;;;;OAIG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;OAIG;IACH,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC;IAKzB;;;;;;OAMG;IACH,UAAU,IAAI,QAAQ;CAGvB"}
package/dist/lex-error.js CHANGED
@@ -1,23 +1,71 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LexError = void 0;
4
+ /**
5
+ * Error class for Lexicon-related errors.
6
+ *
7
+ * LexError extends the standard JavaScript {@link Error} with AT Protocol-specific
8
+ * functionality including:
9
+ * - An error code for programmatic error handling
10
+ * - JSON serialization for API responses
11
+ * - HTTP Response generation
12
+ *
13
+ * @typeParam N - The specific error code type
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { LexError } from '@atproto/lex-data'
18
+ *
19
+ * // Throw a Lexicon error
20
+ * throw new LexError('InvalidRequest', 'Missing required field')
21
+ *
22
+ * // Create and serialize
23
+ * const error = new LexError('NotFound', 'Record not found')
24
+ * console.log(error.toJSON())
25
+ * // { error: 'NotFound', message: 'Record not found' }
26
+ *
27
+ * // Return as HTTP response
28
+ * return error.toResponse() // 400 Bad Request with JSON body
29
+ * ```
30
+ */
4
31
  class LexError extends Error {
5
32
  error;
6
33
  name = 'LexError';
34
+ /**
35
+ * Creates a new LexError.
36
+ *
37
+ * @param error - The error code identifying the type of error
38
+ * @param message - Optional human-readable error message
39
+ * @param options - Standard Error options (e.g., cause)
40
+ */
7
41
  constructor(error, message, // Defaults to empty string in Error constructor
8
42
  options) {
9
43
  super(message, options);
10
44
  this.error = error;
11
45
  }
46
+ /**
47
+ * Returns a string representation of this error.
48
+ *
49
+ * @returns A formatted string: "LexError: [ERROR_CODE] message"
50
+ */
12
51
  toString() {
13
52
  return `${this.name}: [${this.error}] ${this.message}`;
14
53
  }
54
+ /**
55
+ * Converts this error to a JSON-serializable object.
56
+ *
57
+ * @returns The error data suitable for JSON serialization
58
+ */
15
59
  toJSON() {
16
60
  const { error, message } = this;
17
61
  return { error, message: message || undefined };
18
62
  }
19
63
  /**
20
- * Translate into an HTTP response for downstream clients.
64
+ * Converts this error to an HTTP Response for downstream clients.
65
+ *
66
+ * Returns a 400 Bad Request response with the JSON-serialized error body.
67
+ *
68
+ * @returns A Response object with status 400 and JSON body
21
69
  */
22
70
  toResponse() {
23
71
  return Response.json(this.toJSON(), { status: 400 });
@@ -1 +1 @@
1
- {"version":3,"file":"lex-error.js","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":";;;AAOA,MAAa,QAAgD,SAAQ,KAAK;IAI7D;IAHX,IAAI,GAAG,UAAU,CAAA;IAEjB,YACW,KAAQ,EACjB,OAAgB,EAAE,gDAAgD;IAClE,OAAsB;QAEtB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAJd,UAAK,GAAL,KAAK,CAAG;IAKnB,CAAC;IAED,QAAQ;QACN,OAAO,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,CAAA;IACxD,CAAC;IAED,MAAM;QACJ,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;QAC/B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,CAAA;IACjD,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACtD,CAAC;CACF;AA1BD,4BA0BC","sourcesContent":["export type LexErrorCode = string & NonNullable<unknown>\n\nexport type LexErrorData<N extends LexErrorCode = LexErrorCode> = {\n error: N\n message?: string\n}\n\nexport class LexError<N extends LexErrorCode = LexErrorCode> extends Error {\n name = 'LexError'\n\n constructor(\n readonly error: N,\n message?: string, // Defaults to empty string in Error constructor\n options?: ErrorOptions,\n ) {\n super(message, options)\n }\n\n toString(): string {\n return `${this.name}: [${this.error}] ${this.message}`\n }\n\n toJSON(): LexErrorData<N> {\n const { error, message } = this\n return { error, message: message || undefined }\n }\n\n /**\n * Translate into an HTTP response for downstream clients.\n */\n toResponse(): Response {\n return Response.json(this.toJSON(), { status: 400 })\n }\n}\n"]}
1
+ {"version":3,"file":"lex-error.js","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":";;;AAsCA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAa,QAAgD,SAAQ,KAAK;IAW7D;IAVX,IAAI,GAAG,UAAU,CAAA;IAEjB;;;;;;OAMG;IACH,YACW,KAAQ,EACjB,OAAgB,EAAE,gDAAgD;IAClE,OAAsB;QAEtB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAJd,UAAK,GAAL,KAAK,CAAG;IAKnB,CAAC;IAED;;;;OAIG;IACH,QAAQ;QACN,OAAO,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,CAAA;IACxD,CAAC;IAED;;;;OAIG;IACH,MAAM;QACJ,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;QAC/B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,CAAA;IACjD,CAAC;IAED;;;;;;OAMG;IACH,UAAU;QACR,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACtD,CAAC;CACF;AA/CD,4BA+CC","sourcesContent":["/**\n * Error code type for Lexicon errors.\n *\n * Error codes identify the type of error that occurred (e.g., 'InvalidRequest').\n *\n * @example\n * ```typescript\n * import type { LexErrorCode } from '@atproto/lex-data'\n *\n * const errorCode: LexErrorCode = 'InvalidRequest'\n * ```\n */\nexport type LexErrorCode = string & NonNullable<unknown>\n\n/**\n * JSON-serializable error data structure.\n *\n * This is the standard format for error responses in the AT Protocol XRPC protocol.\n *\n * @typeParam N - The specific error code type\n *\n * @example\n * ```typescript\n * import type { LexErrorData } from '@atproto/lex-data'\n *\n * const errorData: LexErrorData = {\n * error: 'InvalidRequest',\n * message: 'Missing required field: handle'\n * }\n * ```\n */\nexport type LexErrorData<N extends LexErrorCode = LexErrorCode> = {\n /** The error code identifying the type of error. */\n error: N\n /** Optional human-readable error message. */\n message?: string\n}\n\n/**\n * Error class for Lexicon-related errors.\n *\n * LexError extends the standard JavaScript {@link Error} with AT Protocol-specific\n * functionality including:\n * - An error code for programmatic error handling\n * - JSON serialization for API responses\n * - HTTP Response generation\n *\n * @typeParam N - The specific error code type\n *\n * @example\n * ```typescript\n * import { LexError } from '@atproto/lex-data'\n *\n * // Throw a Lexicon error\n * throw new LexError('InvalidRequest', 'Missing required field')\n *\n * // Create and serialize\n * const error = new LexError('NotFound', 'Record not found')\n * console.log(error.toJSON())\n * // { error: 'NotFound', message: 'Record not found' }\n *\n * // Return as HTTP response\n * return error.toResponse() // 400 Bad Request with JSON body\n * ```\n */\nexport class LexError<N extends LexErrorCode = LexErrorCode> extends Error {\n name = 'LexError'\n\n /**\n * Creates a new LexError.\n *\n * @param error - The error code identifying the type of error\n * @param message - Optional human-readable error message\n * @param options - Standard Error options (e.g., cause)\n */\n constructor(\n readonly error: N,\n message?: string, // Defaults to empty string in Error constructor\n options?: ErrorOptions,\n ) {\n super(message, options)\n }\n\n /**\n * Returns a string representation of this error.\n *\n * @returns A formatted string: \"LexError: [ERROR_CODE] message\"\n */\n toString(): string {\n return `${this.name}: [${this.error}] ${this.message}`\n }\n\n /**\n * Converts this error to a JSON-serializable object.\n *\n * @returns The error data suitable for JSON serialization\n */\n toJSON(): LexErrorData<N> {\n const { error, message } = this\n return { error, message: message || undefined }\n }\n\n /**\n * Converts this error to an HTTP Response for downstream clients.\n *\n * Returns a 400 Bad Request response with the JSON-serialized error body.\n *\n * @returns A Response object with status 400 and JSON body\n */\n toResponse(): Response {\n return Response.json(this.toJSON(), { status: 400 })\n }\n}\n"]}