@atproto/lex-data 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/blob.d.ts +20 -12
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js +5 -16
- package/dist/blob.js.map +1 -1
- package/dist/cid.d.ts +124 -30
- package/dist/cid.d.ts.map +1 -1
- package/dist/cid.js +191 -39
- package/dist/cid.js.map +1 -1
- package/dist/lex-equals.js +1 -1
- package/dist/lex-equals.js.map +1 -1
- package/package.json +1 -1
- package/src/blob.test.ts +6 -3
- package/src/blob.ts +40 -33
- package/src/cid-implementation.test.ts +137 -0
- package/src/cid.test.ts +172 -53
- package/src/cid.ts +349 -55
- package/src/lex-equals.ts +2 -2
package/src/cid.ts
CHANGED
|
@@ -1,22 +1,42 @@
|
|
|
1
1
|
import { CID } from 'multiformats/cid'
|
|
2
|
+
import { create as createDigest } from 'multiformats/hashes/digest'
|
|
3
|
+
import { sha256, sha512 } from 'multiformats/hashes/sha2'
|
|
4
|
+
import { isObject } from './object.js'
|
|
5
|
+
import { ui8Equals } from './uint8array.js'
|
|
2
6
|
|
|
3
|
-
export const DAG_CBOR_MULTICODEC = 0x71
|
|
4
|
-
export
|
|
7
|
+
export const DAG_CBOR_MULTICODEC = 0x71 // DRISL conformant DAG-CBOR
|
|
8
|
+
export type DAG_CBOR_MULTICODEC = typeof DAG_CBOR_MULTICODEC
|
|
5
9
|
|
|
6
|
-
export const
|
|
10
|
+
export const RAW_MULTICODEC = 0x55 // raw binary codec used in DASL CIDs
|
|
11
|
+
export type RAW_MULTICODEC = typeof RAW_MULTICODEC
|
|
7
12
|
|
|
8
|
-
export
|
|
9
|
-
|
|
13
|
+
export const SHA256_MULTIHASH = sha256.code
|
|
14
|
+
export type SHA256_MULTIHASH = typeof SHA256_MULTIHASH
|
|
15
|
+
|
|
16
|
+
export const SHA512_MULTIHASH = sha512.code
|
|
17
|
+
export type SHA512_MULTIHASH = typeof SHA512_MULTIHASH
|
|
18
|
+
|
|
19
|
+
export interface Multihash<TCode extends number = number> {
|
|
20
|
+
/**
|
|
21
|
+
* Code of the multihash
|
|
22
|
+
*/
|
|
23
|
+
code: TCode
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Raw digest
|
|
27
|
+
*/
|
|
10
28
|
digest: Uint8Array
|
|
11
|
-
|
|
12
|
-
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function multihashEquals(a: Multihash, b: Multihash): boolean {
|
|
32
|
+
return a.code === b.code && ui8Equals(a.digest, b.digest)
|
|
13
33
|
}
|
|
14
34
|
|
|
15
35
|
declare module 'multiformats/cid' {
|
|
16
36
|
/**
|
|
17
37
|
* @deprecated use the {@link Cid} interface from `@atproto/lex-data`, and
|
|
18
|
-
* related helpers ({@link
|
|
19
|
-
* {@link
|
|
38
|
+
* related helpers ({@link isCid}, {@link ifCid}, {@link asCid},
|
|
39
|
+
* {@link parseCid}, {@link decodeCid}), instead.
|
|
20
40
|
*
|
|
21
41
|
* This is marked as deprecated because we want to discourage direct usage of
|
|
22
42
|
* `multiformats/cid` in dependent packages, and instead have them rely on the
|
|
@@ -29,8 +49,8 @@ declare module 'multiformats/cid' {
|
|
|
29
49
|
*
|
|
30
50
|
* In order to avoid compatibility issues, while preparing for future breaking
|
|
31
51
|
* changes (CID in multiformats v10+ has a slightly different interface), as
|
|
32
|
-
* we update or swap out `multiformats`,
|
|
33
|
-
* interface.
|
|
52
|
+
* we update or swap out `multiformats`, `@atproto/lex-data` provides its own
|
|
53
|
+
* stable {@link Cid} interface.
|
|
34
54
|
*/
|
|
35
55
|
interface CID {}
|
|
36
56
|
}
|
|
@@ -53,76 +73,350 @@ declare module 'multiformats/cid' {
|
|
|
53
73
|
|
|
54
74
|
// @NOTE Even though it is not portable, we still re-export CID here so that
|
|
55
75
|
// dependent packages where it can be used, have access to it (instead of
|
|
56
|
-
// importing directly from "multiformats" or"multiformats/cid").
|
|
57
|
-
export { CID }
|
|
76
|
+
// importing directly from "multiformats" or "multiformats/cid").
|
|
77
|
+
export { /** @deprecated */ CID }
|
|
58
78
|
|
|
59
79
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
80
|
+
* Converts a {@link Cid} to a multiformats {@link CID} instance.
|
|
81
|
+
*
|
|
82
|
+
* @deprecated Packages depending on `@atproto/lex-data` should use the
|
|
83
|
+
* {@link Cid} interface instead of relying on `multiformats`'s {@link CID}
|
|
84
|
+
* implementation directly. This is to avoid compatibility issues, and in order
|
|
85
|
+
* to allow better portability, compatibility and future updates.
|
|
62
86
|
*/
|
|
63
|
-
export
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
87
|
+
export function asMultiformatsCID<
|
|
88
|
+
TVersion extends 0 | 1 = 0 | 1,
|
|
89
|
+
TCode extends number = number,
|
|
90
|
+
TMultihashCode extends number = number,
|
|
91
|
+
>(input: Cid<TVersion, TCode, TMultihashCode>) {
|
|
92
|
+
const cid =
|
|
93
|
+
// Already a multiformats CID instance
|
|
94
|
+
CID.asCID(input) ??
|
|
95
|
+
// Create a new multiformats CID instance
|
|
96
|
+
CID.create(
|
|
97
|
+
input.version,
|
|
98
|
+
input.code,
|
|
99
|
+
createDigest(input.multihash.code, input.multihash.digest),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
// @NOTE: the "satisfies" operator is used here to ensure that the Cid
|
|
103
|
+
// interface is indeed compatible with multiformats' CID implementation, which
|
|
104
|
+
// allows us to safely rely on multiformats' CID implementation where Cid are
|
|
105
|
+
// needed.
|
|
106
|
+
return cid satisfies Cid as CID & Cid<TVersion, TCode, TMultihashCode>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Interface for working with CIDs
|
|
111
|
+
*/
|
|
112
|
+
export interface Cid<
|
|
113
|
+
TVersion extends 0 | 1 = 0 | 1,
|
|
114
|
+
TCode extends number = number,
|
|
115
|
+
TMultihashCode extends number = number,
|
|
116
|
+
> {
|
|
117
|
+
// @NOTE This interface is compatible with multiformats' CID implementation
|
|
118
|
+
// which we are using under the hood.
|
|
119
|
+
|
|
120
|
+
readonly version: TVersion
|
|
121
|
+
readonly code: TCode
|
|
122
|
+
readonly multihash: Multihash<TMultihashCode>
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Binary representation of the whole CID.
|
|
126
|
+
*/
|
|
127
|
+
readonly bytes: Uint8Array
|
|
128
|
+
|
|
129
|
+
equals(other: Cid): boolean
|
|
69
130
|
toString(): string
|
|
70
131
|
}
|
|
71
132
|
|
|
72
|
-
|
|
73
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Represents the cid of raw binary data (like media blobs).
|
|
135
|
+
*
|
|
136
|
+
* The use of {@link SHA256_MULTIHASH} is recommended but not required for raw CIDs.
|
|
137
|
+
*
|
|
138
|
+
* @see {@link https://atproto.com/specs/data-model#link-and-cid-formats ATproto Data Model - Link and CID Formats}
|
|
139
|
+
*/
|
|
140
|
+
export type RawCid = Cid<1, RAW_MULTICODEC>
|
|
141
|
+
|
|
142
|
+
export function isRawCid(cid: Cid): cid is RawCid {
|
|
143
|
+
return cid.version === 1 && cid.code === RAW_MULTICODEC
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Represents a DASL compliant CID.
|
|
148
|
+
* @see {@link https://dasl.ing/cid.html DASL-CIDs}
|
|
149
|
+
*/
|
|
150
|
+
export type DaslCid = Cid<
|
|
151
|
+
1,
|
|
152
|
+
RAW_MULTICODEC | DAG_CBOR_MULTICODEC,
|
|
153
|
+
SHA256_MULTIHASH
|
|
154
|
+
>
|
|
155
|
+
|
|
156
|
+
export function isDaslCid(cid: Cid): cid is DaslCid {
|
|
157
|
+
return (
|
|
158
|
+
cid.version === 1 &&
|
|
159
|
+
(cid.code === RAW_MULTICODEC || cid.code === DAG_CBOR_MULTICODEC) &&
|
|
160
|
+
cid.multihash.code === SHA256_MULTIHASH &&
|
|
161
|
+
cid.multihash.digest.byteLength === 32 // Should always be 32 bytes (256 bits) for SHA-256, but double-checking anyways
|
|
162
|
+
)
|
|
74
163
|
}
|
|
75
164
|
|
|
76
|
-
|
|
77
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Represents the cid of ATProto DAG-CBOR data (like repository MST nodes).
|
|
167
|
+
* @see {@link https://atproto.com/specs/data-model#link-and-cid-formats ATproto Data Model - Link and CID Formats}
|
|
168
|
+
*/
|
|
169
|
+
export type CborCid = Cid<1, DAG_CBOR_MULTICODEC, SHA256_MULTIHASH>
|
|
170
|
+
|
|
171
|
+
export function isCborCid(cid: Cid): cid is CborCid {
|
|
172
|
+
return cid.code === DAG_CBOR_MULTICODEC && isDaslCid(cid)
|
|
78
173
|
}
|
|
79
174
|
|
|
80
|
-
export
|
|
81
|
-
|
|
175
|
+
export type CheckCidOptions = {
|
|
176
|
+
flavor?: 'raw' | 'cbor' | 'dasl'
|
|
82
177
|
}
|
|
83
178
|
|
|
84
|
-
export
|
|
85
|
-
|
|
179
|
+
export type InferCheckedCid<TOptions> = TOptions extends { flavor: 'raw' }
|
|
180
|
+
? RawCid
|
|
181
|
+
: TOptions extends { flavor: 'cbor' }
|
|
182
|
+
? CborCid
|
|
183
|
+
: Cid
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Type guard to check whether a {@link Cid} instance meets specific flavor
|
|
187
|
+
* constraints.
|
|
188
|
+
*/
|
|
189
|
+
export function checkCid<TOptions extends CheckCidOptions>(
|
|
190
|
+
cid: Cid,
|
|
191
|
+
options: TOptions,
|
|
192
|
+
): cid is InferCheckedCid<TOptions>
|
|
193
|
+
export function checkCid(cid: Cid, options?: CheckCidOptions): boolean
|
|
194
|
+
export function checkCid(cid: Cid, options?: CheckCidOptions): boolean {
|
|
195
|
+
switch (options?.flavor) {
|
|
196
|
+
case undefined:
|
|
197
|
+
return true
|
|
198
|
+
case 'cbor':
|
|
199
|
+
return isCborCid(cid)
|
|
200
|
+
case 'dasl':
|
|
201
|
+
return isDaslCid(cid)
|
|
202
|
+
case 'raw':
|
|
203
|
+
return isRawCid(cid)
|
|
204
|
+
default:
|
|
205
|
+
throw new TypeError(`Unknown CID flavor: ${options?.flavor}`)
|
|
206
|
+
}
|
|
86
207
|
}
|
|
87
208
|
|
|
88
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Type guard to check whether a value is a valid {@link Cid} instance,
|
|
211
|
+
* optionally checking for specific flavor constraints.
|
|
212
|
+
*/
|
|
213
|
+
export function isCid<TOptions extends CheckCidOptions>(
|
|
89
214
|
value: unknown,
|
|
90
|
-
options
|
|
91
|
-
): value is
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
215
|
+
options: TOptions,
|
|
216
|
+
): value is InferCheckedCid<TOptions>
|
|
217
|
+
export function isCid(value: unknown, options?: CheckCidOptions): value is Cid
|
|
218
|
+
export function isCid(value: unknown, options?: CheckCidOptions): value is Cid {
|
|
219
|
+
return isCidImplementation(value) && checkCid(value, options)
|
|
220
|
+
}
|
|
96
221
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Returns the input value as a {@link Cid} if it is valid, or `null` otherwise.
|
|
224
|
+
*/
|
|
225
|
+
export function ifCid<TValue, TOptions extends CheckCidOptions>(
|
|
226
|
+
value: unknown,
|
|
227
|
+
options: TOptions,
|
|
228
|
+
): (TValue & InferCheckedCid<TOptions>) | null
|
|
229
|
+
export function ifCid<TValue>(
|
|
230
|
+
value: TValue,
|
|
231
|
+
options?: CheckCidOptions,
|
|
232
|
+
): (TValue & Cid) | null
|
|
233
|
+
export function ifCid(value: unknown, options?: CheckCidOptions): Cid | null {
|
|
234
|
+
if (isCidImplementation(value) && checkCid(value, options)) return value
|
|
235
|
+
return null
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Returns the input value as a {@link Cid} if it is valid.
|
|
240
|
+
*
|
|
241
|
+
* @throws if the input is not a valid {@link Cid}.
|
|
242
|
+
*/
|
|
243
|
+
export function asCid<TValue, TOptions extends CheckCidOptions>(
|
|
244
|
+
value: TValue,
|
|
245
|
+
options: TOptions,
|
|
246
|
+
): TValue & InferCheckedCid<TOptions>
|
|
247
|
+
export function asCid<TValue>(
|
|
248
|
+
value: TValue,
|
|
249
|
+
options?: CheckCidOptions,
|
|
250
|
+
): Cid & TValue
|
|
251
|
+
export function asCid(value: unknown, options?: CheckCidOptions): Cid {
|
|
252
|
+
if (isCidImplementation(value) && checkCid(value, options)) return value
|
|
253
|
+
throw new Error('Not a valid CID')
|
|
254
|
+
}
|
|
108
255
|
|
|
109
|
-
|
|
256
|
+
/**
|
|
257
|
+
* Decodes a CID from its binary representation.
|
|
258
|
+
*
|
|
259
|
+
* @see {@link https://dasl.ing/cid.html DASL-CIDs}
|
|
260
|
+
* @throws if the input do not represent a valid DASL {@link Cid}
|
|
261
|
+
*/
|
|
262
|
+
export function decodeCid<TOptions extends CheckCidOptions>(
|
|
263
|
+
cidBytes: Uint8Array,
|
|
264
|
+
options: TOptions,
|
|
265
|
+
): InferCheckedCid<TOptions>
|
|
266
|
+
export function decodeCid(cidBytes: Uint8Array, options?: CheckCidOptions): Cid
|
|
267
|
+
export function decodeCid(
|
|
268
|
+
cidBytes: Uint8Array,
|
|
269
|
+
options?: CheckCidOptions,
|
|
270
|
+
): Cid {
|
|
271
|
+
const cid = CID.decode(cidBytes)
|
|
272
|
+
return asCid(cid, options)
|
|
110
273
|
}
|
|
111
274
|
|
|
112
|
-
|
|
113
|
-
|
|
275
|
+
/**
|
|
276
|
+
* Parses a CID string into a Cid object.
|
|
277
|
+
*
|
|
278
|
+
* @throws if the input is not a valid CID string.
|
|
279
|
+
*/
|
|
280
|
+
export function parseCid<TOptions extends CheckCidOptions>(
|
|
281
|
+
input: string,
|
|
282
|
+
options: TOptions,
|
|
283
|
+
): InferCheckedCid<TOptions>
|
|
284
|
+
export function parseCid(input: string, options?: CheckCidOptions): Cid
|
|
285
|
+
export function parseCid(input: string, options?: CheckCidOptions): Cid {
|
|
286
|
+
const cid = CID.parse(input)
|
|
287
|
+
return asCid(cid, options)
|
|
114
288
|
}
|
|
115
289
|
|
|
116
|
-
export function
|
|
290
|
+
export function validateCidString(
|
|
291
|
+
input: string,
|
|
292
|
+
options?: CheckCidOptions,
|
|
293
|
+
): boolean {
|
|
294
|
+
return parseCidSafe(input, options)?.toString() === input
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function parseCidSafe<TOptions extends CheckCidOptions>(
|
|
298
|
+
input: string,
|
|
299
|
+
options: TOptions,
|
|
300
|
+
): InferCheckedCid<TOptions> | null
|
|
301
|
+
export function parseCidSafe(
|
|
302
|
+
input: string,
|
|
303
|
+
options?: CheckCidOptions,
|
|
304
|
+
): Cid | null
|
|
305
|
+
export function parseCidSafe(
|
|
306
|
+
input: string,
|
|
307
|
+
options?: CheckCidOptions,
|
|
308
|
+
): Cid | null {
|
|
117
309
|
try {
|
|
118
|
-
return parseCid(input)
|
|
310
|
+
return parseCid(input, options)
|
|
119
311
|
} catch {
|
|
120
|
-
return
|
|
312
|
+
return null
|
|
121
313
|
}
|
|
122
314
|
}
|
|
123
315
|
|
|
124
|
-
export function ensureValidCidString(
|
|
125
|
-
|
|
316
|
+
export function ensureValidCidString(
|
|
317
|
+
input: string,
|
|
318
|
+
options?: CheckCidOptions,
|
|
319
|
+
): void {
|
|
320
|
+
if (!validateCidString(input, options)) {
|
|
126
321
|
throw new Error(`Invalid CID string`)
|
|
127
322
|
}
|
|
128
323
|
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Verifies whether the multihash of a given {@link cid} matches the hash of the provided {@link bytes}.
|
|
327
|
+
* @params cid The CID to match against the bytes.
|
|
328
|
+
* @params bytes The bytes to verify.
|
|
329
|
+
* @returns true if the CID matches the bytes, false otherwise.
|
|
330
|
+
*/
|
|
331
|
+
export async function isCidForBytes(
|
|
332
|
+
cid: Cid,
|
|
333
|
+
bytes: Uint8Array,
|
|
334
|
+
): Promise<boolean> {
|
|
335
|
+
if (cid.multihash.code === sha256.code) {
|
|
336
|
+
const multihash = await sha256.digest(bytes)
|
|
337
|
+
return multihashEquals(multihash, cid.multihash)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (cid.multihash.code === sha512.code) {
|
|
341
|
+
const multihash = await sha512.digest(bytes)
|
|
342
|
+
return multihashEquals(multihash, cid.multihash)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Don't know how to verify other multihash codes
|
|
346
|
+
throw new Error('Unsupported CID multihash')
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export function createCid<TCode extends number, TMultihashCode extends number>(
|
|
350
|
+
code: TCode,
|
|
351
|
+
multihashCode: TMultihashCode,
|
|
352
|
+
digest: Uint8Array,
|
|
353
|
+
) {
|
|
354
|
+
const cid: Cid = CID.createV1(code, createDigest(multihashCode, digest))
|
|
355
|
+
return cid as Cid<1, TCode, TMultihashCode>
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export async function cidForCbor(bytes: Uint8Array): Promise<CborCid> {
|
|
359
|
+
const multihash = await sha256.digest(bytes)
|
|
360
|
+
return CID.createV1(DAG_CBOR_MULTICODEC, multihash) as CborCid
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export async function cidForRawBytes(bytes: Uint8Array): Promise<RawCid> {
|
|
364
|
+
const multihash = await sha256.digest(bytes)
|
|
365
|
+
return CID.createV1(RAW_MULTICODEC, multihash) as RawCid
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function cidForRawHash(digest: Uint8Array): RawCid {
|
|
369
|
+
// Fool-proofing
|
|
370
|
+
if (digest.length !== 32) {
|
|
371
|
+
throw new Error(`Invalid SHA-256 hash length: ${digest.length}`)
|
|
372
|
+
}
|
|
373
|
+
return createCid(RAW_MULTICODEC, sha256.code, digest)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* @internal
|
|
378
|
+
*/
|
|
379
|
+
function isCidImplementation(value: unknown): value is Cid {
|
|
380
|
+
if (CID.asCID(value)) {
|
|
381
|
+
// CIDs created using older multiformats versions did not have a "bytes"
|
|
382
|
+
// property.
|
|
383
|
+
return (value as { bytes?: Uint8Array }).bytes != null
|
|
384
|
+
} else {
|
|
385
|
+
// Unknown implementation, do a structural check
|
|
386
|
+
try {
|
|
387
|
+
if (!isObject(value)) return false
|
|
388
|
+
|
|
389
|
+
const val = value as Record<string, unknown>
|
|
390
|
+
if (val.version !== 0 && val.version !== 1) return false
|
|
391
|
+
if (!isUint8(val.code)) return false
|
|
392
|
+
|
|
393
|
+
if (!isObject(val.multihash)) return false
|
|
394
|
+
const mh = val.multihash as Record<string, unknown>
|
|
395
|
+
if (!isUint8(mh.code)) return false
|
|
396
|
+
if (!(mh.digest instanceof Uint8Array)) return false
|
|
397
|
+
|
|
398
|
+
// Ensure that the bytes array is consistent with other properties
|
|
399
|
+
if (!(val.bytes instanceof Uint8Array)) return false
|
|
400
|
+
if (val.bytes[0] !== val.version) return false
|
|
401
|
+
if (val.bytes[1] !== val.code) return false
|
|
402
|
+
if (val.bytes[2] !== mh.code) return false
|
|
403
|
+
if (val.bytes[3] !== mh.digest.length) return false
|
|
404
|
+
if (val.bytes.length !== 4 + mh.digest.length) return false
|
|
405
|
+
if (!ui8Equals(val.bytes.subarray(4), mh.digest)) return false
|
|
406
|
+
|
|
407
|
+
if (typeof val.equals !== 'function') return false
|
|
408
|
+
if (val.equals(val) !== true) return false
|
|
409
|
+
|
|
410
|
+
return true
|
|
411
|
+
} catch {
|
|
412
|
+
return false
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @internal
|
|
419
|
+
*/
|
|
420
|
+
function isUint8(val: unknown): val is number {
|
|
421
|
+
return Number.isInteger(val) && (val as number) >= 0 && (val as number) < 256
|
|
422
|
+
}
|
package/src/lex-equals.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ifCid, isCid } from './cid.js'
|
|
2
2
|
import { LexValue } from './lex.js'
|
|
3
3
|
import { isPlainObject } from './object.js'
|
|
4
4
|
import { ui8Equals } from './uint8array.js'
|
|
@@ -44,7 +44,7 @@ export function lexEquals(a: LexValue, b: LexValue): boolean {
|
|
|
44
44
|
if (isCid(a)) {
|
|
45
45
|
// @NOTE CID.equals returns its argument when it is falsy (e.g. null or
|
|
46
46
|
// undefined) so we need to explicitly check that the output is "true".
|
|
47
|
-
return
|
|
47
|
+
return ifCid(b)?.equals(a) === true
|
|
48
48
|
} else if (isCid(b)) {
|
|
49
49
|
return false
|
|
50
50
|
}
|