@atproto/lex-data 0.0.9 → 0.0.11

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.
@@ -14,18 +14,45 @@ const uint8array_to_base64_js_1 = require("./uint8array-to-base64.js");
14
14
  /**
15
15
  * Encodes a Uint8Array into a base64 string.
16
16
  *
17
+ * Uses native Uint8Array.prototype.toBase64 when available (Node.js 24+, modern browsers),
18
+ * falling back to Node.js Buffer or a ponyfill implementation.
19
+ *
20
+ * @param bytes - The binary data to encode
21
+ * @param alphabet - The base64 alphabet to use ('base64' or 'base64url'), defaults to 'base64'
17
22
  * @returns The base64 encoded string
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * import { toBase64 } from '@atproto/lex-data'
27
+ *
28
+ * const bytes = new Uint8Array([72, 101, 108, 108, 111])
29
+ * toBase64(bytes) // 'SGVsbG8='
30
+ * toBase64(bytes, 'base64url') // 'SGVsbG8' (URL-safe, no padding)
31
+ * ```
18
32
  */
19
33
  exports.toBase64 =
20
34
  /* v8 ignore next -- @preserve */ uint8array_to_base64_js_1.toBase64Native ??
21
35
  uint8array_to_base64_js_1.toBase64Node ??
22
36
  uint8array_to_base64_js_1.toBase64Ponyfill;
23
37
  /**
24
- * Decodes a base64 string into a Uint8Array. This function supports both padded
25
- * and unpadded base64 strings.
38
+ * Decodes a base64 string into a Uint8Array.
39
+ *
40
+ * Supports both padded and unpadded base64 strings. Uses native
41
+ * Uint8Array.fromBase64 when available, falling back to Node.js Buffer
42
+ * or a ponyfill implementation.
26
43
  *
27
- * @returns The decoded {@link Uint8Array}
44
+ * @param b64 - The base64 string to decode
45
+ * @param alphabet - The base64 alphabet to use ('base64' or 'base64url'), defaults to 'base64'
46
+ * @returns The decoded binary data
28
47
  * @throws If the input is not a valid base64 string
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { fromBase64 } from '@atproto/lex-data'
52
+ *
53
+ * fromBase64('SGVsbG8=') // Uint8Array([72, 101, 108, 108, 111])
54
+ * fromBase64('SGVsbG8', 'base64url') // Same, URL-safe alphabet
55
+ * ```
29
56
  */
30
57
  exports.fromBase64 =
31
58
  /* v8 ignore next -- @preserve */ uint8array_from_base64_js_1.fromBase64Native ??
@@ -36,6 +63,21 @@ if (exports.toBase64 === uint8array_to_base64_js_1.toBase64Ponyfill || exports.f
36
63
  /*#__PURE__*/
37
64
  console.warn('[@atproto/lex-data]: Uint8Array.fromBase64 / Uint8Array.prototype.toBase64 not available in this environment. Falling back to ponyfill implementation.');
38
65
  }
66
+ /**
67
+ * Returns the input if it is a Uint8Array, otherwise returns undefined.
68
+ *
69
+ * @param input - The value to check
70
+ * @returns The input if it's a Uint8Array, otherwise undefined
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * import { ifUint8Array } from '@atproto/lex-data'
75
+ *
76
+ * ifUint8Array(new Uint8Array([1, 2])) // Uint8Array([1, 2])
77
+ * ifUint8Array('not binary') // undefined
78
+ * ifUint8Array(new ArrayBuffer(4)) // undefined
79
+ * ```
80
+ */
39
81
  function ifUint8Array(input) {
40
82
  if (input instanceof Uint8Array) {
41
83
  return input;
@@ -45,7 +87,23 @@ function ifUint8Array(input) {
45
87
  /**
46
88
  * Coerces various binary data representations into a Uint8Array.
47
89
  *
48
- * @return `undefined` if the input could not be coerced into a {@link Uint8Array}.
90
+ * Handles the following input types:
91
+ * - `Uint8Array` - Returned as-is
92
+ * - `ArrayBufferView` (e.g., DataView, other TypedArrays) - Converted to Uint8Array
93
+ * - `ArrayBuffer` - Wrapped in a Uint8Array
94
+ *
95
+ * @param input - The value to convert
96
+ * @returns A Uint8Array, or `undefined` if the input could not be converted
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * import { asUint8Array } from '@atproto/lex-data'
101
+ *
102
+ * asUint8Array(new Uint8Array([1, 2])) // Uint8Array([1, 2])
103
+ * asUint8Array(new ArrayBuffer(4)) // Uint8Array of length 4
104
+ * asUint8Array(new Int16Array([1, 2])) // Uint8Array view of the buffer
105
+ * asUint8Array('string') // undefined
106
+ * ```
49
107
  */
50
108
  function asUint8Array(input) {
51
109
  if (input instanceof Uint8Array) {
@@ -59,6 +117,22 @@ function asUint8Array(input) {
59
117
  }
60
118
  return undefined;
61
119
  }
120
+ /**
121
+ * Compares two Uint8Arrays for byte-by-byte equality.
122
+ *
123
+ * @param a - First Uint8Array to compare
124
+ * @param b - Second Uint8Array to compare
125
+ * @returns `true` if both arrays have the same length and identical bytes
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * import { ui8Equals } from '@atproto/lex-data'
130
+ *
131
+ * ui8Equals(new Uint8Array([1, 2]), new Uint8Array([1, 2])) // true
132
+ * ui8Equals(new Uint8Array([1, 2]), new Uint8Array([1, 3])) // false
133
+ * ui8Equals(new Uint8Array([1]), new Uint8Array([1, 2])) // false
134
+ * ```
135
+ */
62
136
  function ui8Equals(a, b) {
63
137
  if (a.byteLength !== b.byteLength) {
64
138
  return false;
@@ -70,6 +144,24 @@ function ui8Equals(a, b) {
70
144
  }
71
145
  return true;
72
146
  }
147
+ /**
148
+ * Concatenates multiple Uint8Arrays into a single Uint8Array.
149
+ *
150
+ * Uses Node.js Buffer.concat when available for performance,
151
+ * falling back to a ponyfill implementation.
152
+ *
153
+ * @param arrays - The Uint8Arrays to concatenate
154
+ * @returns A new Uint8Array containing all input bytes in order
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * import { ui8Concat } from '@atproto/lex-data'
159
+ *
160
+ * const a = new Uint8Array([1, 2])
161
+ * const b = new Uint8Array([3, 4])
162
+ * ui8Concat([a, b]) // Uint8Array([1, 2, 3, 4])
163
+ * ```
164
+ */
73
165
  exports.ui8Concat =
74
166
  /* v8 ignore next -- @preserve */ uint8array_concat_js_1.ui8ConcatNode ?? uint8array_concat_js_1.ui8ConcatPonyfill;
75
167
  //# sourceMappingURL=uint8array.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"uint8array.js","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":";;;AAwDA,oCAMC;AAOD,oCAkBC;AAED,8BAYC;AApGD,iEAAyE;AACzE,2EAIoC;AACpC,uEAIkC;AAIlC,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,0CAA0C;AAE1C;;;;GAIG;AACU,QAAA,QAAQ;AAInB,iCAAiC,CAAC,wCAAc;IAChD,sCAAY;IACZ,0CAAgB,CAAA;AAElB;;;;;;GAMG;AACU,QAAA,UAAU;AAIrB,iCAAiC,CAAC,4CAAgB;IAClD,0CAAc;IACd,8CAAkB,CAAA;AAEpB,iCAAiC;AACjC,IAAI,gBAAQ,KAAK,0CAAgB,IAAI,kBAAU,KAAK,8CAAkB,EAAE,CAAC;IACvE,aAAa;IACb,OAAO,CAAC,IAAI,CACV,wJAAwJ,CACzJ,CAAA;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,UAAU,CACnB,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAChD,CAAA;IACH,CAAC;IAED,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAgB,SAAS,CAAC,CAAa,EAAE,CAAa;IACpD,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAEY,QAAA,SAAS;AACpB,iCAAiC,CAAC,oCAAa,IAAI,wCAAiB,CAAA","sourcesContent":["import { Base64Alphabet } from './uint8array-base64.js'\nimport { ui8ConcatNode, ui8ConcatPonyfill } from './uint8array-concat.js'\nimport {\n fromBase64Native,\n fromBase64Node,\n fromBase64Ponyfill,\n} from './uint8array-from-base64.js'\nimport {\n toBase64Native,\n toBase64Node,\n toBase64Ponyfill,\n} from './uint8array-to-base64.js'\n\nexport type { Base64Alphabet }\n\n// @TODO drop dependency on uint8arrays package once Uint8Array.fromBase64 /\n// Uint8Array.prototype.toBase64 is widely supported, and mark fromBase64 /\n// toBase64 as deprecated. We can also drop NodeJS specific implementations\n// once NodeJS <24 is no longer supported.\n\n/**\n * Encodes a Uint8Array into a base64 string.\n *\n * @returns The base64 encoded string\n */\nexport const toBase64: (\n bytes: Uint8Array,\n alphabet?: Base64Alphabet,\n) => string =\n /* v8 ignore next -- @preserve */ toBase64Native ??\n toBase64Node ??\n toBase64Ponyfill\n\n/**\n * Decodes a base64 string into a Uint8Array. This function supports both padded\n * and unpadded base64 strings.\n *\n * @returns The decoded {@link Uint8Array}\n * @throws If the input is not a valid base64 string\n */\nexport const fromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => Uint8Array =\n /* v8 ignore next -- @preserve */ fromBase64Native ??\n fromBase64Node ??\n fromBase64Ponyfill\n\n/* v8 ignore next -- @preserve */\nif (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Uint8Array.fromBase64 / Uint8Array.prototype.toBase64 not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\nexport function ifUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n return undefined\n}\n\n/**\n * Coerces various binary data representations into a Uint8Array.\n *\n * @return `undefined` if the input could not be coerced into a {@link Uint8Array}.\n */\nexport function asUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n if (ArrayBuffer.isView(input)) {\n return new Uint8Array(\n input.buffer,\n input.byteOffset,\n input.byteLength / Uint8Array.BYTES_PER_ELEMENT,\n )\n }\n\n if (input instanceof ArrayBuffer) {\n return new Uint8Array(input)\n }\n\n return undefined\n}\n\nexport function ui8Equals(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) {\n return false\n }\n\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] !== b[i]) {\n return false\n }\n }\n\n return true\n}\n\nexport const ui8Concat =\n /* v8 ignore next -- @preserve */ ui8ConcatNode ?? ui8ConcatPonyfill\n"]}
1
+ {"version":3,"file":"uint8array.js","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":";;;AAkGA,oCAMC;AAuBD,oCAkBC;AAkBD,8BAYC;AA9KD,iEAAyE;AACzE,2EAIoC;AACpC,uEAIkC;AAIlC,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,0CAA0C;AAE1C;;;;;;;;;;;;;;;;;;GAkBG;AACU,QAAA,QAAQ;AAInB,iCAAiC,CAAC,wCAAc;IAChD,sCAAY;IACZ,0CAAgB,CAAA;AAElB;;;;;;;;;;;;;;;;;;;GAmBG;AACU,QAAA,UAAU;AAIrB,iCAAiC,CAAC,4CAAgB;IAClD,0CAAc;IACd,8CAAkB,CAAA;AAEpB,iCAAiC;AACjC,IAAI,gBAAQ,KAAK,0CAAgB,IAAI,kBAAU,KAAK,8CAAkB,EAAE,CAAC;IACvE,aAAa;IACb,OAAO,CAAC,IAAI,CACV,wJAAwJ,CACzJ,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,UAAU,CACnB,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAChD,CAAA;IACH,CAAC;IAED,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,SAAS,CAAC,CAAa,EAAE,CAAa;IACpD,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACU,QAAA,SAAS;AACpB,iCAAiC,CAAC,oCAAa,IAAI,wCAAiB,CAAA","sourcesContent":["import { Base64Alphabet } from './uint8array-base64.js'\nimport { ui8ConcatNode, ui8ConcatPonyfill } from './uint8array-concat.js'\nimport {\n fromBase64Native,\n fromBase64Node,\n fromBase64Ponyfill,\n} from './uint8array-from-base64.js'\nimport {\n toBase64Native,\n toBase64Node,\n toBase64Ponyfill,\n} from './uint8array-to-base64.js'\n\nexport type { Base64Alphabet }\n\n// @TODO drop dependency on uint8arrays package once Uint8Array.fromBase64 /\n// Uint8Array.prototype.toBase64 is widely supported, and mark fromBase64 /\n// toBase64 as deprecated. We can also drop NodeJS specific implementations\n// once NodeJS <24 is no longer supported.\n\n/**\n * Encodes a Uint8Array into a base64 string.\n *\n * Uses native Uint8Array.prototype.toBase64 when available (Node.js 24+, modern browsers),\n * falling back to Node.js Buffer or a ponyfill implementation.\n *\n * @param bytes - The binary data to encode\n * @param alphabet - The base64 alphabet to use ('base64' or 'base64url'), defaults to 'base64'\n * @returns The base64 encoded string\n *\n * @example\n * ```typescript\n * import { toBase64 } from '@atproto/lex-data'\n *\n * const bytes = new Uint8Array([72, 101, 108, 108, 111])\n * toBase64(bytes) // 'SGVsbG8='\n * toBase64(bytes, 'base64url') // 'SGVsbG8' (URL-safe, no padding)\n * ```\n */\nexport const toBase64: (\n bytes: Uint8Array,\n alphabet?: Base64Alphabet,\n) => string =\n /* v8 ignore next -- @preserve */ toBase64Native ??\n toBase64Node ??\n toBase64Ponyfill\n\n/**\n * Decodes a base64 string into a Uint8Array.\n *\n * Supports both padded and unpadded base64 strings. Uses native\n * Uint8Array.fromBase64 when available, falling back to Node.js Buffer\n * or a ponyfill implementation.\n *\n * @param b64 - The base64 string to decode\n * @param alphabet - The base64 alphabet to use ('base64' or 'base64url'), defaults to 'base64'\n * @returns The decoded binary data\n * @throws If the input is not a valid base64 string\n *\n * @example\n * ```typescript\n * import { fromBase64 } from '@atproto/lex-data'\n *\n * fromBase64('SGVsbG8=') // Uint8Array([72, 101, 108, 108, 111])\n * fromBase64('SGVsbG8', 'base64url') // Same, URL-safe alphabet\n * ```\n */\nexport const fromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => Uint8Array =\n /* v8 ignore next -- @preserve */ fromBase64Native ??\n fromBase64Node ??\n fromBase64Ponyfill\n\n/* v8 ignore next -- @preserve */\nif (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Uint8Array.fromBase64 / Uint8Array.prototype.toBase64 not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\n/**\n * Returns the input if it is a Uint8Array, otherwise returns undefined.\n *\n * @param input - The value to check\n * @returns The input if it's a Uint8Array, otherwise undefined\n *\n * @example\n * ```typescript\n * import { ifUint8Array } from '@atproto/lex-data'\n *\n * ifUint8Array(new Uint8Array([1, 2])) // Uint8Array([1, 2])\n * ifUint8Array('not binary') // undefined\n * ifUint8Array(new ArrayBuffer(4)) // undefined\n * ```\n */\nexport function ifUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n return undefined\n}\n\n/**\n * Coerces various binary data representations into a Uint8Array.\n *\n * Handles the following input types:\n * - `Uint8Array` - Returned as-is\n * - `ArrayBufferView` (e.g., DataView, other TypedArrays) - Converted to Uint8Array\n * - `ArrayBuffer` - Wrapped in a Uint8Array\n *\n * @param input - The value to convert\n * @returns A Uint8Array, or `undefined` if the input could not be converted\n *\n * @example\n * ```typescript\n * import { asUint8Array } from '@atproto/lex-data'\n *\n * asUint8Array(new Uint8Array([1, 2])) // Uint8Array([1, 2])\n * asUint8Array(new ArrayBuffer(4)) // Uint8Array of length 4\n * asUint8Array(new Int16Array([1, 2])) // Uint8Array view of the buffer\n * asUint8Array('string') // undefined\n * ```\n */\nexport function asUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n if (ArrayBuffer.isView(input)) {\n return new Uint8Array(\n input.buffer,\n input.byteOffset,\n input.byteLength / Uint8Array.BYTES_PER_ELEMENT,\n )\n }\n\n if (input instanceof ArrayBuffer) {\n return new Uint8Array(input)\n }\n\n return undefined\n}\n\n/**\n * Compares two Uint8Arrays for byte-by-byte equality.\n *\n * @param a - First Uint8Array to compare\n * @param b - Second Uint8Array to compare\n * @returns `true` if both arrays have the same length and identical bytes\n *\n * @example\n * ```typescript\n * import { ui8Equals } from '@atproto/lex-data'\n *\n * ui8Equals(new Uint8Array([1, 2]), new Uint8Array([1, 2])) // true\n * ui8Equals(new Uint8Array([1, 2]), new Uint8Array([1, 3])) // false\n * ui8Equals(new Uint8Array([1]), new Uint8Array([1, 2])) // false\n * ```\n */\nexport function ui8Equals(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) {\n return false\n }\n\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] !== b[i]) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Concatenates multiple Uint8Arrays into a single Uint8Array.\n *\n * Uses Node.js Buffer.concat when available for performance,\n * falling back to a ponyfill implementation.\n *\n * @param arrays - The Uint8Arrays to concatenate\n * @returns A new Uint8Array containing all input bytes in order\n *\n * @example\n * ```typescript\n * import { ui8Concat } from '@atproto/lex-data'\n *\n * const a = new Uint8Array([1, 2])\n * const b = new Uint8Array([3, 4])\n * ui8Concat([a, b]) // Uint8Array([1, 2, 3, 4])\n * ```\n */\nexport const ui8Concat =\n /* v8 ignore next -- @preserve */ ui8ConcatNode ?? ui8ConcatPonyfill\n"]}
package/dist/utf8.d.ts CHANGED
@@ -1,6 +1,83 @@
1
1
  import { Base64Alphabet } from './uint8array.js';
2
+ /**
3
+ * Counts the number of grapheme clusters (user-perceived characters) in a string.
4
+ *
5
+ * Grapheme clusters represent what users typically think of as "characters",
6
+ * handling complex cases like:
7
+ * - Emoji with skin tones and ZWJ sequences (e.g., family emoji)
8
+ * - Combined characters (e.g., 'e' + combining accent)
9
+ * - Regional indicator pairs (flag emoji)
10
+ *
11
+ * Uses native {@link Intl.Segmenter} when available, falling back to a ponyfill.
12
+ *
13
+ * @param str - The string to measure
14
+ * @returns The number of grapheme clusters
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { graphemeLen } from '@atproto/lex-data'
19
+ *
20
+ * graphemeLen('hello') // 5
21
+ * graphemeLen('cafe\u0301') // 4 (cafe with combining accent)
22
+ * graphemeLen('\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}') // 1 (family emoji)
23
+ * ```
24
+ */
2
25
  export declare const graphemeLen: (str: string) => number;
26
+ /**
27
+ * Calculates the UTF-8 byte length of a string.
28
+ *
29
+ * Returns the number of bytes the string would occupy when encoded as UTF-8.
30
+ * This is important for Lexicon validation where schemas specify byte limits.
31
+ *
32
+ * Uses Node.js Buffer.byteLength when available for performance,
33
+ * falling back to a computed implementation.
34
+ *
35
+ * @param str - The string to measure
36
+ * @returns The UTF-8 byte length
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import { utf8Len } from '@atproto/lex-data'
41
+ *
42
+ * utf8Len('hello') // 5 (ASCII: 1 byte per char)
43
+ * utf8Len('\u00e9') // 2 (e with accent: 2 bytes)
44
+ * utf8Len('\u{1F600}') // 4 (emoji: 4 bytes)
45
+ * utf8Len('\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}') // 25 (family emoji)
46
+ * ```
47
+ */
3
48
  export declare const utf8Len: (string: string) => number;
49
+ /**
50
+ * Encodes a UTF-8 string to base64.
51
+ *
52
+ * First encodes the string as UTF-8 bytes, then encodes those bytes as base64.
53
+ *
54
+ * @param str - The string to encode
55
+ * @param alphabet - The base64 alphabet to use ('base64' or 'base64url')
56
+ * @returns The base64-encoded string
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * import { utf8ToBase64 } from '@atproto/lex-data'
61
+ *
62
+ * utf8ToBase64('Hello') // 'SGVsbG8='
63
+ * ```
64
+ */
4
65
  export declare const utf8ToBase64: (str: string, alphabet?: Base64Alphabet) => string;
66
+ /**
67
+ * Decodes a base64 string to UTF-8.
68
+ *
69
+ * Decodes the base64 to bytes, then interprets those bytes as UTF-8 text.
70
+ *
71
+ * @param b64 - The base64 string to decode
72
+ * @param alphabet - The base64 alphabet to use ('base64' or 'base64url')
73
+ * @returns The decoded UTF-8 string
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { utf8FromBase64 } from '@atproto/lex-data'
78
+ *
79
+ * utf8FromBase64('SGVsbG8=') // 'Hello'
80
+ * ```
81
+ */
5
82
  export declare const utf8FromBase64: (b64: string, alphabet?: Base64Alphabet) => string;
6
83
  //# sourceMappingURL=utf8.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utf8.d.ts","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAShD,eAAO,MAAM,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MACiC,CAAA;AAU5E,eAAO,MAAM,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MACuB,CAAA;AAEjE,eAAO,MAAM,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MACK,CAAA;AAE5E,eAAO,MAAM,cAAc,EAAE,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,cAAc,KACtB,MAC2E,CAAA"}
1
+ {"version":3,"file":"utf8.d.ts","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAShD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MACiC,CAAA;AAU5E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MACuB,CAAA;AAEjE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MACK,CAAA;AAE5E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,EAAE,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,cAAc,KACtB,MAC2E,CAAA"}
package/dist/utf8.js CHANGED
@@ -5,6 +5,29 @@ const utf8_from_base64_js_1 = require("./utf8-from-base64.js");
5
5
  const utf8_grapheme_len_js_1 = require("./utf8-grapheme-len.js");
6
6
  const utf8_len_js_1 = require("./utf8-len.js");
7
7
  const utf8_to_base64_js_1 = require("./utf8-to-base64.js");
8
+ /**
9
+ * Counts the number of grapheme clusters (user-perceived characters) in a string.
10
+ *
11
+ * Grapheme clusters represent what users typically think of as "characters",
12
+ * handling complex cases like:
13
+ * - Emoji with skin tones and ZWJ sequences (e.g., family emoji)
14
+ * - Combined characters (e.g., 'e' + combining accent)
15
+ * - Regional indicator pairs (flag emoji)
16
+ *
17
+ * Uses native {@link Intl.Segmenter} when available, falling back to a ponyfill.
18
+ *
19
+ * @param str - The string to measure
20
+ * @returns The number of grapheme clusters
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import { graphemeLen } from '@atproto/lex-data'
25
+ *
26
+ * graphemeLen('hello') // 5
27
+ * graphemeLen('cafe\u0301') // 4 (cafe with combining accent)
28
+ * graphemeLen('\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}') // 1 (family emoji)
29
+ * ```
30
+ */
8
31
  exports.graphemeLen =
9
32
  /* v8 ignore next -- @preserve */ utf8_grapheme_len_js_1.graphemeLenNative ?? utf8_grapheme_len_js_1.graphemeLenPonyfill;
10
33
  /* v8 ignore next -- @preserve */
@@ -12,10 +35,64 @@ if (exports.graphemeLen === utf8_grapheme_len_js_1.graphemeLenPonyfill) {
12
35
  /*#__PURE__*/
13
36
  console.warn('[@atproto/lex-data]: Intl.Segmenter is not available in this environment. Falling back to ponyfill implementation.');
14
37
  }
38
+ /**
39
+ * Calculates the UTF-8 byte length of a string.
40
+ *
41
+ * Returns the number of bytes the string would occupy when encoded as UTF-8.
42
+ * This is important for Lexicon validation where schemas specify byte limits.
43
+ *
44
+ * Uses Node.js Buffer.byteLength when available for performance,
45
+ * falling back to a computed implementation.
46
+ *
47
+ * @param str - The string to measure
48
+ * @returns The UTF-8 byte length
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { utf8Len } from '@atproto/lex-data'
53
+ *
54
+ * utf8Len('hello') // 5 (ASCII: 1 byte per char)
55
+ * utf8Len('\u00e9') // 2 (e with accent: 2 bytes)
56
+ * utf8Len('\u{1F600}') // 4 (emoji: 4 bytes)
57
+ * utf8Len('\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}') // 25 (family emoji)
58
+ * ```
59
+ */
15
60
  exports.utf8Len =
16
61
  /* v8 ignore next -- @preserve */ utf8_len_js_1.utf8LenNode ?? utf8_len_js_1.utf8LenCompute;
62
+ /**
63
+ * Encodes a UTF-8 string to base64.
64
+ *
65
+ * First encodes the string as UTF-8 bytes, then encodes those bytes as base64.
66
+ *
67
+ * @param str - The string to encode
68
+ * @param alphabet - The base64 alphabet to use ('base64' or 'base64url')
69
+ * @returns The base64-encoded string
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { utf8ToBase64 } from '@atproto/lex-data'
74
+ *
75
+ * utf8ToBase64('Hello') // 'SGVsbG8='
76
+ * ```
77
+ */
17
78
  exports.utf8ToBase64 =
18
79
  /* v8 ignore next -- @preserve */ utf8_to_base64_js_1.utf8ToBase64Node ?? utf8_to_base64_js_1.utf8ToBase64Ponyfill;
80
+ /**
81
+ * Decodes a base64 string to UTF-8.
82
+ *
83
+ * Decodes the base64 to bytes, then interprets those bytes as UTF-8 text.
84
+ *
85
+ * @param b64 - The base64 string to decode
86
+ * @param alphabet - The base64 alphabet to use ('base64' or 'base64url')
87
+ * @returns The decoded UTF-8 string
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * import { utf8FromBase64 } from '@atproto/lex-data'
92
+ *
93
+ * utf8FromBase64('SGVsbG8=') // 'Hello'
94
+ * ```
95
+ */
19
96
  exports.utf8FromBase64 =
20
97
  /* v8 ignore next -- @preserve */ utf8_from_base64_js_1.utf8FromBase64Node ?? utf8_from_base64_js_1.utf8FromBase64Ponyfill;
21
98
  //# sourceMappingURL=utf8.js.map
package/dist/utf8.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utf8.js","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":";;;AACA,+DAG8B;AAC9B,iEAA+E;AAC/E,+CAA2D;AAC3D,2DAA4E;AAE/D,QAAA,WAAW;AACtB,iCAAiC,CAAC,wCAAiB,IAAI,0CAAmB,CAAA;AAE5E,iCAAiC;AACjC,IAAI,mBAAW,KAAK,0CAAmB,EAAE,CAAC;IACxC,aAAa;IACb,OAAO,CAAC,IAAI,CACV,oHAAoH,CACrH,CAAA;AACH,CAAC;AAEY,QAAA,OAAO;AAClB,iCAAiC,CAAC,yBAAW,IAAI,4BAAc,CAAA;AAEpD,QAAA,YAAY;AACvB,iCAAiC,CAAC,oCAAgB,IAAI,wCAAoB,CAAA;AAE/D,QAAA,cAAc;AAIzB,iCAAiC,CAAC,wCAAkB,IAAI,4CAAsB,CAAA","sourcesContent":["import { Base64Alphabet } from './uint8array.js'\nimport {\n utf8FromBase64Node,\n utf8FromBase64Ponyfill,\n} from './utf8-from-base64.js'\nimport { graphemeLenNative, graphemeLenPonyfill } from './utf8-grapheme-len.js'\nimport { utf8LenCompute, utf8LenNode } from './utf8-len.js'\nimport { utf8ToBase64Node, utf8ToBase64Ponyfill } from './utf8-to-base64.js'\n\nexport const graphemeLen: (str: string) => number =\n /* v8 ignore next -- @preserve */ graphemeLenNative ?? graphemeLenPonyfill\n\n/* v8 ignore next -- @preserve */\nif (graphemeLen === graphemeLenPonyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Intl.Segmenter is not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\nexport const utf8Len: (string: string) => number =\n /* v8 ignore next -- @preserve */ utf8LenNode ?? utf8LenCompute\n\nexport const utf8ToBase64: (str: string, alphabet?: Base64Alphabet) => string =\n /* v8 ignore next -- @preserve */ utf8ToBase64Node ?? utf8ToBase64Ponyfill\n\nexport const utf8FromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => string =\n /* v8 ignore next -- @preserve */ utf8FromBase64Node ?? utf8FromBase64Ponyfill\n"]}
1
+ {"version":3,"file":"utf8.js","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":";;;AACA,+DAG8B;AAC9B,iEAA+E;AAC/E,+CAA2D;AAC3D,2DAA4E;AAE5E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACU,QAAA,WAAW;AACtB,iCAAiC,CAAC,wCAAiB,IAAI,0CAAmB,CAAA;AAE5E,iCAAiC;AACjC,IAAI,mBAAW,KAAK,0CAAmB,EAAE,CAAC;IACxC,aAAa;IACb,OAAO,CAAC,IAAI,CACV,oHAAoH,CACrH,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACU,QAAA,OAAO;AAClB,iCAAiC,CAAC,yBAAW,IAAI,4BAAc,CAAA;AAEjE;;;;;;;;;;;;;;;GAeG;AACU,QAAA,YAAY;AACvB,iCAAiC,CAAC,oCAAgB,IAAI,wCAAoB,CAAA;AAE5E;;;;;;;;;;;;;;;GAeG;AACU,QAAA,cAAc;AAIzB,iCAAiC,CAAC,wCAAkB,IAAI,4CAAsB,CAAA","sourcesContent":["import { Base64Alphabet } from './uint8array.js'\nimport {\n utf8FromBase64Node,\n utf8FromBase64Ponyfill,\n} from './utf8-from-base64.js'\nimport { graphemeLenNative, graphemeLenPonyfill } from './utf8-grapheme-len.js'\nimport { utf8LenCompute, utf8LenNode } from './utf8-len.js'\nimport { utf8ToBase64Node, utf8ToBase64Ponyfill } from './utf8-to-base64.js'\n\n/**\n * Counts the number of grapheme clusters (user-perceived characters) in a string.\n *\n * Grapheme clusters represent what users typically think of as \"characters\",\n * handling complex cases like:\n * - Emoji with skin tones and ZWJ sequences (e.g., family emoji)\n * - Combined characters (e.g., 'e' + combining accent)\n * - Regional indicator pairs (flag emoji)\n *\n * Uses native {@link Intl.Segmenter} when available, falling back to a ponyfill.\n *\n * @param str - The string to measure\n * @returns The number of grapheme clusters\n *\n * @example\n * ```typescript\n * import { graphemeLen } from '@atproto/lex-data'\n *\n * graphemeLen('hello') // 5\n * graphemeLen('cafe\\u0301') // 4 (cafe with combining accent)\n * graphemeLen('\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F467}\\u{200D}\\u{1F466}') // 1 (family emoji)\n * ```\n */\nexport const graphemeLen: (str: string) => number =\n /* v8 ignore next -- @preserve */ graphemeLenNative ?? graphemeLenPonyfill\n\n/* v8 ignore next -- @preserve */\nif (graphemeLen === graphemeLenPonyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Intl.Segmenter is not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\n/**\n * Calculates the UTF-8 byte length of a string.\n *\n * Returns the number of bytes the string would occupy when encoded as UTF-8.\n * This is important for Lexicon validation where schemas specify byte limits.\n *\n * Uses Node.js Buffer.byteLength when available for performance,\n * falling back to a computed implementation.\n *\n * @param str - The string to measure\n * @returns The UTF-8 byte length\n *\n * @example\n * ```typescript\n * import { utf8Len } from '@atproto/lex-data'\n *\n * utf8Len('hello') // 5 (ASCII: 1 byte per char)\n * utf8Len('\\u00e9') // 2 (e with accent: 2 bytes)\n * utf8Len('\\u{1F600}') // 4 (emoji: 4 bytes)\n * utf8Len('\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F467}\\u{200D}\\u{1F466}') // 25 (family emoji)\n * ```\n */\nexport const utf8Len: (string: string) => number =\n /* v8 ignore next -- @preserve */ utf8LenNode ?? utf8LenCompute\n\n/**\n * Encodes a UTF-8 string to base64.\n *\n * First encodes the string as UTF-8 bytes, then encodes those bytes as base64.\n *\n * @param str - The string to encode\n * @param alphabet - The base64 alphabet to use ('base64' or 'base64url')\n * @returns The base64-encoded string\n *\n * @example\n * ```typescript\n * import { utf8ToBase64 } from '@atproto/lex-data'\n *\n * utf8ToBase64('Hello') // 'SGVsbG8='\n * ```\n */\nexport const utf8ToBase64: (str: string, alphabet?: Base64Alphabet) => string =\n /* v8 ignore next -- @preserve */ utf8ToBase64Node ?? utf8ToBase64Ponyfill\n\n/**\n * Decodes a base64 string to UTF-8.\n *\n * Decodes the base64 to bytes, then interprets those bytes as UTF-8 text.\n *\n * @param b64 - The base64 string to decode\n * @param alphabet - The base64 alphabet to use ('base64' or 'base64url')\n * @returns The decoded UTF-8 string\n *\n * @example\n * ```typescript\n * import { utf8FromBase64 } from '@atproto/lex-data'\n *\n * utf8FromBase64('SGVsbG8=') // 'Hello'\n * ```\n */\nexport const utf8FromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => string =\n /* v8 ignore next -- @preserve */ utf8FromBase64Node ?? utf8FromBase64Ponyfill\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/lex-data",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "license": "MIT",
5
5
  "description": "Core utilities for AT Lexicons",
6
6
  "keywords": [
@@ -31,7 +31,7 @@
31
31
  "types": "./dist/index.d.ts",
32
32
  "browser": "./dist/index.js",
33
33
  "import": "./dist/index.js",
34
- "require": "./dist/index.js"
34
+ "default": "./dist/index.js"
35
35
  }
36
36
  },
37
37
  "dependencies": {
package/src/blob.ts CHANGED
@@ -3,7 +3,28 @@ import { LexValue } from './lex.js'
3
3
  import { isPlainObject, isPlainProto } from './object.js'
4
4
 
5
5
  /**
6
- * @note {@link BlobRef} is just a {@link LexMap} with a specific shape.
6
+ * Reference to binary data (like images, videos, etc.) in the AT Protocol data model.
7
+ *
8
+ * A BlobRef is a {@link LexMap} with a specific structure that identifies binary
9
+ * content by its content hash (CID), along with metadata about the content type
10
+ * and size.
11
+ *
12
+ * @typeParam Ref - The type of CID reference, defaults to any {@link Cid}
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import type { BlobRef } from '@atproto/lex-data'
17
+ *
18
+ * const imageRef: BlobRef = {
19
+ * $type: 'blob',
20
+ * mimeType: 'image/jpeg',
21
+ * ref: cid, // CID of the blob content
22
+ * size: 12345
23
+ * }
24
+ * ```
25
+ *
26
+ * @see {@link isBlobRef} to check if a value is a valid BlobRef
27
+ * @see {@link LegacyBlobRef} for the older blob reference format
7
28
  */
8
29
  export type BlobRef<Ref extends Cid = Cid> = {
9
30
  $type: 'blob'
@@ -12,17 +33,25 @@ export type BlobRef<Ref extends Cid = Cid> = {
12
33
  size: number
13
34
  }
14
35
 
36
+ /**
37
+ * Options for validating a {@link BlobRef}.
38
+ */
15
39
  export type BlobRefCheckOptions = {
16
40
  /**
17
41
  * If `false`, skips strict CID validation of {@link BlobRef.ref}, allowing
18
42
  * any valid CID. Otherwise, validates that the CID is v1, uses the raw
19
43
  * multicodec, and has a sha256 multihash.
20
44
  *
21
- * @defaults to `true`
45
+ * @default true
22
46
  */
23
47
  strict?: boolean
24
48
  }
25
49
 
50
+ /**
51
+ * Infers the BlobRef type based on the check options.
52
+ *
53
+ * @typeParam TOptions - The options used for checking
54
+ */
26
55
  export type InferCheckedBlobRef<TOptions extends BlobRefCheckOptions> =
27
56
  TOptions extends { strict: false }
28
57
  ? BlobRef
@@ -30,6 +59,34 @@ export type InferCheckedBlobRef<TOptions extends BlobRefCheckOptions> =
30
59
  ? BlobRef
31
60
  : BlobRef<RawCid>
32
61
 
62
+ /**
63
+ * Type guard to check if a value is a valid {@link BlobRef}.
64
+ *
65
+ * Validates the structure of the input including:
66
+ * - `$type` must be `'blob'`
67
+ * - `mimeType` must be a valid MIME type string (containing '/')
68
+ * - `size` must be a non-negative safe integer
69
+ * - `ref` must be a valid CID (strict validation by default)
70
+ *
71
+ * @param input - The value to check
72
+ * @param options - Optional validation options
73
+ * @returns `true` if the input is a valid BlobRef
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { isBlobRef } from '@atproto/lex-data'
78
+ *
79
+ * if (isBlobRef(data)) {
80
+ * console.log(data.mimeType) // e.g., 'image/jpeg'
81
+ * console.log(data.size) // e.g., 12345
82
+ * }
83
+ *
84
+ * // Allow any valid CID (not just raw CIDs)
85
+ * if (isBlobRef(data, { strict: false })) {
86
+ * // ...
87
+ * }
88
+ * ```
89
+ */
33
90
  export function isBlobRef(input: unknown): input is BlobRef<RawCid>
34
91
  export function isBlobRef<TOptions extends BlobRefCheckOptions>(
35
92
  input: unknown,
@@ -89,13 +146,53 @@ export function isBlobRef(
89
146
  }
90
147
 
91
148
  /**
92
- * @note {@link LegacyBlobRef} is just a {@link LexMap} with a specific shape.
149
+ * Legacy format for blob references used in older AT Protocol data.
150
+ *
151
+ * This is the older format that stores the CID as a string rather than
152
+ * as a structured CID object. New code should use {@link BlobRef} instead.
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * import type { LegacyBlobRef } from '@atproto/lex-data'
157
+ *
158
+ * const legacyRef: LegacyBlobRef = {
159
+ * cid: 'bafyreib...',
160
+ * mimeType: 'image/jpeg'
161
+ * }
162
+ * ```
163
+ *
164
+ * @see {@link isLegacyBlobRef} to check if a value is a LegacyBlobRef
165
+ * @see {@link BlobRef} for the current blob reference format
166
+ * @deprecated Use {@link BlobRef} for new code
93
167
  */
94
168
  export type LegacyBlobRef = {
95
169
  cid: string
96
170
  mimeType: string
97
171
  }
98
172
 
173
+ /**
174
+ * Type guard to check if a value is a valid {@link LegacyBlobRef}.
175
+ *
176
+ * Validates the structure of the input:
177
+ * - `cid` must be a valid CID string
178
+ * - `mimeType` must be a non-empty string
179
+ * - No additional properties allowed
180
+ *
181
+ * @param input - The value to check
182
+ * @returns `true` if the input is a valid LegacyBlobRef
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * import { isLegacyBlobRef } from '@atproto/lex-data'
187
+ *
188
+ * if (isLegacyBlobRef(data)) {
189
+ * console.log(data.cid) // CID as string
190
+ * console.log(data.mimeType) // e.g., 'image/jpeg'
191
+ * }
192
+ * ```
193
+ *
194
+ * @see {@link isBlobRef} for checking the current blob reference format
195
+ */
99
196
  export function isLegacyBlobRef(input: unknown): input is LegacyBlobRef {
100
197
  if (!isPlainObject(input)) {
101
198
  return false
@@ -123,13 +220,24 @@ export function isLegacyBlobRef(input: unknown): input is LegacyBlobRef {
123
220
  return true
124
221
  }
125
222
 
223
+ /**
224
+ * Options for enumerating blob references within a {@link LexValue}.
225
+ */
126
226
  export type EnumBlobRefsOptions = BlobRefCheckOptions & {
127
227
  /**
128
- * @defaults to `false`
228
+ * If `true`, also yields {@link LegacyBlobRef} objects in addition to
229
+ * {@link BlobRef} objects.
230
+ *
231
+ * @default false
129
232
  */
130
233
  allowLegacy?: boolean
131
234
  }
132
235
 
236
+ /**
237
+ * Infers the yielded type of {@link enumBlobRefs} based on options.
238
+ *
239
+ * @typeParam TOptions - The options used for enumeration
240
+ */
133
241
  export type InferEnumBlobRefs<TOptions extends EnumBlobRefsOptions> =
134
242
  TOptions extends { allowLegacy: true }
135
243
  ? InferCheckedBlobRef<TOptions> | LegacyBlobRef
@@ -138,8 +246,37 @@ export type InferEnumBlobRefs<TOptions extends EnumBlobRefsOptions> =
138
246
  : InferCheckedBlobRef<TOptions>
139
247
 
140
248
  /**
141
- * Enumerates all {@link BlobRef}s (and, optionally, {@link LegacyBlobRef}s)
142
- * found within a {@link LexValue}.
249
+ * Generator that enumerates all {@link BlobRef}s (and, optionally,
250
+ * {@link LegacyBlobRef}s) found within a {@link LexValue}.
251
+ *
252
+ * Performs a deep traversal of the input value, yielding any blob references
253
+ * found. This is useful for extracting all media references from a record.
254
+ *
255
+ * @param input - The LexValue to search for blob references
256
+ * @param options - Optional configuration for the enumeration
257
+ * @yields Each blob reference found in the input
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * import { enumBlobRefs } from '@atproto/lex-data'
262
+ *
263
+ * const record = {
264
+ * text: 'Hello',
265
+ * images: [
266
+ * { $type: 'blob', mimeType: 'image/jpeg', ref: cid1, size: 1000 },
267
+ * { $type: 'blob', mimeType: 'image/png', ref: cid2, size: 2000 }
268
+ * ]
269
+ * }
270
+ *
271
+ * for (const blobRef of enumBlobRefs(record)) {
272
+ * console.log(blobRef.mimeType, blobRef.size)
273
+ * }
274
+ *
275
+ * // Include legacy blob references
276
+ * for (const ref of enumBlobRefs(record, { allowLegacy: true })) {
277
+ * // ref may be BlobRef or LegacyBlobRef
278
+ * }
279
+ * ```
143
280
  */
144
281
  export function enumBlobRefs(
145
282
  input: LexValue,
@@ -1,5 +1,3 @@
1
- /* eslint-disable import/no-deprecated */
2
-
3
1
  import { base32 } from 'multiformats/bases/base32'
4
2
  import { CID } from 'multiformats/cid'
5
3
  import { create as createDigest } from 'multiformats/hashes/digest'
@@ -75,25 +73,19 @@ describe(BytesCid, () => {
75
73
  */
76
74
  export function createCustomCid<
77
75
  TVersion extends 0 | 1,
78
- TCode extends number,
79
- TMultihashCode extends number,
76
+ TCodec extends number,
77
+ THashCode extends number,
80
78
  >(
81
79
  version: TVersion,
82
- code: TCode,
83
- multihashCode: TMultihashCode,
80
+ code: TCodec,
81
+ hashCode: THashCode,
84
82
  digest: Uint8Array,
85
- ): Cid<TVersion, TCode, TMultihashCode> {
83
+ ): Cid<TVersion, TCodec, THashCode> {
86
84
  return {
87
85
  version,
88
86
  code,
89
- multihash: { code: multihashCode, digest },
90
- bytes: new Uint8Array([
91
- version,
92
- code,
93
- multihashCode,
94
- digest.length,
95
- ...digest,
96
- ]),
87
+ multihash: { code: hashCode, digest },
88
+ bytes: new Uint8Array([version, code, hashCode, digest.length, ...digest]),
97
89
  toString,
98
90
  equals,
99
91
  }