@atproto/lex-json 0.0.10 → 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.
package/src/lex-json.ts CHANGED
@@ -11,6 +11,29 @@ import { encodeLexBytes, parseLexBytes } from './bytes.js'
11
11
  import { JsonObject, JsonValue } from './json.js'
12
12
  import { encodeLexLink, parseLexLink } from './link.js'
13
13
 
14
+ /**
15
+ * Serialize a Lex value to a JSON string.
16
+ *
17
+ * This function serializes AT Protocol data model values to JSON, automatically
18
+ * encoding special types:
19
+ * - `Cid` instances are encoded as `{$link: string}`
20
+ * - `Uint8Array` instances are encoded as `{$bytes: string}` (base64)
21
+ *
22
+ * @param input - The Lex value to stringify
23
+ * @returns A JSON string representation of the value
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { lexStringify } from '@atproto/lex'
28
+ *
29
+ * // Stringify with CID and bytes encoding
30
+ * const json = lexStringify({
31
+ * ref: someCid,
32
+ * data: new Uint8Array([72, 101, 108, 108, 111])
33
+ * })
34
+ * // json is '{"ref":{"$link":"bafyrei..."},"data":{"$bytes":"SGVsbG8="}}'
35
+ * ```
36
+ */
14
37
  export function lexStringify(input: LexValue): string {
15
38
  // @NOTE Because of the way the "replacer" works in JSON.stringify, it's
16
39
  // simpler to convert Lex to JSON first rather than trying to do it
@@ -18,14 +41,60 @@ export function lexStringify(input: LexValue): string {
18
41
  return JSON.stringify(lexToJson(input))
19
42
  }
20
43
 
44
+ /**
45
+ * Options for parsing JSON to Lex values.
46
+ */
21
47
  export type LexParseOptions = {
22
48
  /**
23
- * Forbids the presence of invalid Lex values (e.g. non-integer numbers,
24
- * malformed $link, $bytes, blob objects, etc.)
49
+ * When enabled, forbids the presence of invalid Lex values such as:
50
+ * - Non-integer numbers (only safe integers are valid in the Lex data model)
51
+ * - Malformed `$link` objects
52
+ * - Malformed `$bytes` objects
53
+ * - Objects with invalid or empty `$type` properties
54
+ * - Invalid {@link BlobRef} (`$type: 'blob'`) objects
55
+ *
56
+ * When disabled (default), invalid special objects are left as plain objects.
57
+ *
58
+ * @default false
25
59
  */
26
60
  strict?: boolean
27
61
  }
28
62
 
63
+ /**
64
+ * Parses a JSON string into Lex values.
65
+ *
66
+ * This function parses JSON and automatically decodes AT Protocol special types:
67
+ * - `{$link: string}` objects are decoded to `Cid` instances
68
+ * - `{$bytes: string}` objects are decoded to `Uint8Array` instances
69
+ * - `{$type: 'blob'}` objects are validated
70
+ *
71
+ * @typeParam T - Type cast for the resulting Lex value. Use when you want to specify the expected structure of the parsed data.
72
+ * @param input - The JSON string to parse
73
+ * @param options - Parsing options (e.g., strict mode)
74
+ * @returns The parsed Lex value
75
+ * @throws {SyntaxError} If the input is not valid JSON
76
+ * @throws {TypeError} If strict mode is enabled and invalid Lex values are found
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * import { lexParse } from '@atproto/lex'
81
+ *
82
+ * // Parse JSON with $link and $bytes decoding
83
+ * const parsed = lexParse<{
84
+ * ref: Cid
85
+ * data: Uint8Array
86
+ * }>(`{
87
+ * "ref": { "$link": "bafyrei..." },
88
+ * "data": { "$bytes": "SGVsbG8sIHdvcmxkIQ==" }
89
+ * }`)
90
+ *
91
+ * // Parse a single CID
92
+ * const someCid = lexParse<Cid>('{"$link": "bafyrei..."}')
93
+ *
94
+ * // Parse binary data
95
+ * const someBytes = lexParse<Uint8Array>('{"$bytes": "SGVsbG8sIHdvcmxkIQ=="}')
96
+ * ```
97
+ */
29
98
  export function lexParse<T extends LexValue = LexValue>(
30
99
  input: string,
31
100
  options: LexParseOptions = { strict: false },
@@ -48,6 +117,35 @@ export function lexParse<T extends LexValue = LexValue>(
48
117
  })
49
118
  }
50
119
 
120
+ /**
121
+ * Converts a parsed JSON representation of Lexicon value to a {@link LexValue}.
122
+ *
123
+ * This function transforms already-parsed JSON objects into Lex values by
124
+ * decoding AT Protocol special types:
125
+ * - `{$link: string}` objects are converted to `Cid` instances
126
+ * - `{$bytes: string}` objects are converted to `Uint8Array` instances
127
+ *
128
+ * Use this when you have a JavaScript object (e.g., from `JSON.parse()`) and
129
+ * need to convert it to the Lex data model. For parsing JSON strings directly,
130
+ * use {@link lexParse} instead.
131
+ *
132
+ * @param value - The JSON value to convert
133
+ * @param options - Parsing options (e.g., strict mode)
134
+ * @returns The converted Lex value
135
+ * @throws {TypeError} If strict mode is enabled and invalid Lex values are found
136
+ * @throws {TypeError} If the value contains unsupported types (e.g., undefined at top level)
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * import { jsonToLex } from '@atproto/lex'
141
+ *
142
+ * // Convert parsed JSON to Lex values
143
+ * const lex = jsonToLex({
144
+ * ref: { $link: 'bafyrei...' }, // Converted to Cid
145
+ * data: { $bytes: 'SGVsbG8sIHdvcmxkIQ==' } // Converted to Uint8Array
146
+ * })
147
+ * ```
148
+ */
51
149
  export function jsonToLex(
52
150
  value: JsonValue,
53
151
  options: LexParseOptions = { strict: false },
@@ -120,6 +218,33 @@ function jsonObjectToLexMap(
120
218
  return copy ?? input
121
219
  }
122
220
 
221
+ /**
222
+ * Converts a Lex value to a JSON-compatible value.
223
+ *
224
+ * This function transforms Lex data model values into plain JavaScript objects
225
+ * suitable for JSON serialization:
226
+ * - `Cid` instances are converted to `{$link: string}` objects
227
+ * - `Uint8Array` instances are converted to `{$bytes: string}` objects (base64)
228
+ *
229
+ * Use this when you need to convert Lex values to plain objects (e.g., for
230
+ * custom serialization or inspection). For direct JSON string output, use
231
+ * {@link lexStringify} instead.
232
+ *
233
+ * @param value - The Lex value to convert
234
+ * @returns The JSON-compatible value
235
+ * @throws {TypeError} If the value contains unsupported types
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * import { lexToJson } from '@atproto/lex'
240
+ *
241
+ * // Convert Lex values to JSON-compatible objects
242
+ * const obj = lexToJson({
243
+ * ref: someCid, // Converted to { $link: string }
244
+ * data: someBytes // Converted to { $bytes: string }
245
+ * })
246
+ * ```
247
+ */
123
248
  export function lexToJson(value: LexValue): JsonValue {
124
249
  switch (typeof value) {
125
250
  case 'object':
package/src/link.ts CHANGED
@@ -6,6 +6,35 @@ import {
6
6
  } from '@atproto/lex-data'
7
7
  import { JsonValue } from './json.js'
8
8
 
9
+ /**
10
+ * Parses a `{$link: string}` JSON object into a {@link Cid} instance.
11
+ *
12
+ * In the AT Protocol data model, CID references are represented in JSON as an
13
+ * object with a single `$link` property containing a base32-encoded CID string,
14
+ * prefixed with "b". This function decodes that representation into a `Cid`
15
+ * object.
16
+ *
17
+ * @param input - An object potentially containing a `{$link: string}` property
18
+ * @param options - Optional CID validation options
19
+ * @returns The parsed {@link Cid} if the input is a valid `$link` object,
20
+ * or `undefined` if the input is not a valid `$link` representation
21
+ * @throws {TypeError} If `$link` is present but is not a valid CID string
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // Parse a $link object to Cid
26
+ * const cid = parseLexLink({ $link: 'bafyreib2rxk3rybloqtqwbo' })
27
+ * // cid is a Cid instance
28
+ *
29
+ * // Returns undefined for non-$link objects
30
+ * const result = parseLexLink({ foo: 'bar' })
31
+ * // result is undefined
32
+ *
33
+ * // Returns undefined for objects with extra properties
34
+ * const invalid = parseLexLink({ $link: 'bafyrei...', extra: true })
35
+ * // invalid is undefined
36
+ * ```
37
+ */
9
38
  export function parseLexLink<TOptions extends CheckCidOptions>(
10
39
  input: undefined | Record<string, unknown>,
11
40
  options: TOptions,
@@ -31,25 +60,42 @@ export function parseLexLink(
31
60
  const { $link } = input
32
61
 
33
62
  if (typeof $link !== 'string') {
34
- throw new TypeError('$link must be a base32-encoded CID string')
63
+ return undefined
35
64
  }
36
65
 
37
66
  if ($link.length === 0) {
38
- throw new TypeError('CID string in $link cannot be empty')
67
+ return undefined
39
68
  }
40
69
 
41
70
  // Arbitrary limit to prevent DoS via extremely long CIDs
42
71
  if ($link.length > 2048) {
43
- throw new TypeError('CID string in $link is too long')
72
+ return undefined
44
73
  }
45
74
 
46
75
  try {
47
76
  return parseCid($link, options)
48
77
  } catch (cause) {
49
- throw new TypeError('Invalid CID string in $link', { cause })
78
+ return undefined
50
79
  }
51
80
  }
52
81
 
82
+ /**
83
+ * Encodes a {@link Cid} instance into a `{$link: string}` JSON representation.
84
+ *
85
+ * In the AT Protocol data model, CID references are represented in JSON as an
86
+ * object with a single `$link` property containing a base32-encoded CID string,
87
+ * prefixed with "b". This function performs that encoding.
88
+ *
89
+ * @param cid - The CID to encode
90
+ * @returns An object with a `$link` property containing the string representation of the CID
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const cid = CID.parse('bafyreib2rxk3rybloqtqwbo')
95
+ * const encoded = encodeLexLink(cid)
96
+ * // encoded is { $link: 'bafyreib2rxk3rybloqtqwbo' }
97
+ * ```
98
+ */
53
99
  export function encodeLexLink(cid: Cid): JsonValue {
54
100
  return { $link: cid.toString() }
55
101
  }