@atproto/lex-data 0.0.7 → 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 +12 -0
- package/dist/cid.d.ts +73 -48
- package/dist/cid.d.ts.map +1 -1
- package/dist/cid.js +132 -39
- package/dist/cid.js.map +1 -1
- package/package.json +1 -1
- package/src/cid-implementation.test.ts +137 -0
- package/src/cid.test.ts +125 -23
- package/src/cid.ts +228 -99
package/src/cid.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { CID } from 'multiformats/cid'
|
|
2
|
-
import {
|
|
3
|
-
create as createDigest,
|
|
4
|
-
equals as digestEquals,
|
|
5
|
-
} from 'multiformats/hashes/digest'
|
|
2
|
+
import { create as createDigest } from 'multiformats/hashes/digest'
|
|
6
3
|
import { sha256, sha512 } from 'multiformats/hashes/sha2'
|
|
4
|
+
import { isObject } from './object.js'
|
|
5
|
+
import { ui8Equals } from './uint8array.js'
|
|
7
6
|
|
|
8
7
|
export const DAG_CBOR_MULTICODEC = 0x71 // DRISL conformant DAG-CBOR
|
|
9
8
|
export type DAG_CBOR_MULTICODEC = typeof DAG_CBOR_MULTICODEC
|
|
@@ -14,11 +13,23 @@ export type RAW_MULTICODEC = typeof RAW_MULTICODEC
|
|
|
14
13
|
export const SHA256_MULTIHASH = sha256.code
|
|
15
14
|
export type SHA256_MULTIHASH = typeof SHA256_MULTIHASH
|
|
16
15
|
|
|
17
|
-
export
|
|
18
|
-
|
|
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
|
+
*/
|
|
19
28
|
digest: Uint8Array
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function multihashEquals(a: Multihash, b: Multihash): boolean {
|
|
32
|
+
return a.code === b.code && ui8Equals(a.digest, b.digest)
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
declare module 'multiformats/cid' {
|
|
@@ -38,8 +49,8 @@ declare module 'multiformats/cid' {
|
|
|
38
49
|
*
|
|
39
50
|
* In order to avoid compatibility issues, while preparing for future breaking
|
|
40
51
|
* changes (CID in multiformats v10+ has a slightly different interface), as
|
|
41
|
-
* we update or swap out `multiformats`,
|
|
42
|
-
* interface.
|
|
52
|
+
* we update or swap out `multiformats`, `@atproto/lex-data` provides its own
|
|
53
|
+
* stable {@link Cid} interface.
|
|
43
54
|
*/
|
|
44
55
|
interface CID {}
|
|
45
56
|
}
|
|
@@ -62,30 +73,71 @@ declare module 'multiformats/cid' {
|
|
|
62
73
|
|
|
63
74
|
// @NOTE Even though it is not portable, we still re-export CID here so that
|
|
64
75
|
// dependent packages where it can be used, have access to it (instead of
|
|
65
|
-
// importing directly from "multiformats" or"multiformats/cid").
|
|
66
|
-
export { CID }
|
|
76
|
+
// importing directly from "multiformats" or "multiformats/cid").
|
|
77
|
+
export { /** @deprecated */ CID }
|
|
67
78
|
|
|
68
79
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
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.
|
|
71
86
|
*/
|
|
72
|
-
export
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
78
130
|
toString(): string
|
|
79
131
|
}
|
|
80
132
|
|
|
81
133
|
/**
|
|
82
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
|
+
*
|
|
83
138
|
* @see {@link https://atproto.com/specs/data-model#link-and-cid-formats ATproto Data Model - Link and CID Formats}
|
|
84
139
|
*/
|
|
85
|
-
export
|
|
86
|
-
version: 1
|
|
87
|
-
code: RAW_MULTICODEC
|
|
88
|
-
}
|
|
140
|
+
export type RawCid = Cid<1, RAW_MULTICODEC>
|
|
89
141
|
|
|
90
142
|
export function isRawCid(cid: Cid): cid is RawCid {
|
|
91
143
|
return cid.version === 1 && cid.code === RAW_MULTICODEC
|
|
@@ -95,18 +147,18 @@ export function isRawCid(cid: Cid): cid is RawCid {
|
|
|
95
147
|
* Represents a DASL compliant CID.
|
|
96
148
|
* @see {@link https://dasl.ing/cid.html DASL-CIDs}
|
|
97
149
|
*/
|
|
98
|
-
export
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
150
|
+
export type DaslCid = Cid<
|
|
151
|
+
1,
|
|
152
|
+
RAW_MULTICODEC | DAG_CBOR_MULTICODEC,
|
|
153
|
+
SHA256_MULTIHASH
|
|
154
|
+
>
|
|
103
155
|
|
|
104
156
|
export function isDaslCid(cid: Cid): cid is DaslCid {
|
|
105
157
|
return (
|
|
106
158
|
cid.version === 1 &&
|
|
107
159
|
(cid.code === RAW_MULTICODEC || cid.code === DAG_CBOR_MULTICODEC) &&
|
|
108
160
|
cid.multihash.code === SHA256_MULTIHASH &&
|
|
109
|
-
cid.multihash.
|
|
161
|
+
cid.multihash.digest.byteLength === 32 // Should always be 32 bytes (256 bits) for SHA-256, but double-checking anyways
|
|
110
162
|
)
|
|
111
163
|
}
|
|
112
164
|
|
|
@@ -114,17 +166,16 @@ export function isDaslCid(cid: Cid): cid is DaslCid {
|
|
|
114
166
|
* Represents the cid of ATProto DAG-CBOR data (like repository MST nodes).
|
|
115
167
|
* @see {@link https://atproto.com/specs/data-model#link-and-cid-formats ATproto Data Model - Link and CID Formats}
|
|
116
168
|
*/
|
|
117
|
-
export
|
|
118
|
-
code: DAG_CBOR_MULTICODEC
|
|
119
|
-
}
|
|
169
|
+
export type CborCid = Cid<1, DAG_CBOR_MULTICODEC, SHA256_MULTIHASH>
|
|
120
170
|
|
|
121
171
|
export function isCborCid(cid: Cid): cid is CborCid {
|
|
122
172
|
return cid.code === DAG_CBOR_MULTICODEC && isDaslCid(cid)
|
|
123
173
|
}
|
|
124
174
|
|
|
125
|
-
export type
|
|
175
|
+
export type CheckCidOptions = {
|
|
126
176
|
flavor?: 'raw' | 'cbor' | 'dasl'
|
|
127
177
|
}
|
|
178
|
+
|
|
128
179
|
export type InferCheckedCid<TOptions> = TOptions extends { flavor: 'raw' }
|
|
129
180
|
? RawCid
|
|
130
181
|
: TOptions extends { flavor: 'cbor' }
|
|
@@ -132,67 +183,74 @@ export type InferCheckedCid<TOptions> = TOptions extends { flavor: 'raw' }
|
|
|
132
183
|
: Cid
|
|
133
184
|
|
|
134
185
|
/**
|
|
135
|
-
*
|
|
186
|
+
* Type guard to check whether a {@link Cid} instance meets specific flavor
|
|
187
|
+
* constraints.
|
|
136
188
|
*/
|
|
137
|
-
export function
|
|
138
|
-
|
|
189
|
+
export function checkCid<TOptions extends CheckCidOptions>(
|
|
190
|
+
cid: Cid,
|
|
139
191
|
options: TOptions,
|
|
140
|
-
): InferCheckedCid<TOptions>
|
|
141
|
-
export function
|
|
142
|
-
export function
|
|
143
|
-
const cid = CID.asCID(value)
|
|
144
|
-
if (!cid) {
|
|
145
|
-
return null
|
|
146
|
-
}
|
|
147
|
-
|
|
192
|
+
): cid is InferCheckedCid<TOptions>
|
|
193
|
+
export function checkCid(cid: Cid, options?: CheckCidOptions): boolean
|
|
194
|
+
export function checkCid(cid: Cid, options?: CheckCidOptions): boolean {
|
|
148
195
|
switch (options?.flavor) {
|
|
196
|
+
case undefined:
|
|
197
|
+
return true
|
|
149
198
|
case 'cbor':
|
|
150
|
-
return isCborCid(cid)
|
|
151
|
-
case 'raw':
|
|
152
|
-
return isRawCid(cid) ? cid : null
|
|
199
|
+
return isCborCid(cid)
|
|
153
200
|
case 'dasl':
|
|
154
|
-
return isDaslCid(cid)
|
|
201
|
+
return isDaslCid(cid)
|
|
202
|
+
case 'raw':
|
|
203
|
+
return isRawCid(cid)
|
|
155
204
|
default:
|
|
156
|
-
|
|
205
|
+
throw new TypeError(`Unknown CID flavor: ${options?.flavor}`)
|
|
157
206
|
}
|
|
158
207
|
}
|
|
159
208
|
|
|
160
|
-
|
|
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>(
|
|
161
214
|
value: unknown,
|
|
162
215
|
options: TOptions,
|
|
163
216
|
): value is InferCheckedCid<TOptions>
|
|
164
|
-
export function isCid(value: unknown, options?:
|
|
165
|
-
export function isCid(value: unknown, options?:
|
|
166
|
-
return
|
|
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)
|
|
167
220
|
}
|
|
168
221
|
|
|
169
222
|
/**
|
|
170
|
-
*
|
|
223
|
+
* Returns the input value as a {@link Cid} if it is valid, or `null` otherwise.
|
|
171
224
|
*/
|
|
172
|
-
export function
|
|
225
|
+
export function ifCid<TValue, TOptions extends CheckCidOptions>(
|
|
173
226
|
value: unknown,
|
|
174
227
|
options: TOptions,
|
|
175
|
-
): InferCheckedCid<TOptions>
|
|
176
|
-
export function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
|
181
236
|
}
|
|
182
237
|
|
|
183
238
|
/**
|
|
184
|
-
*
|
|
239
|
+
* Returns the input value as a {@link Cid} if it is valid.
|
|
185
240
|
*
|
|
186
|
-
* @throws if the input is not a valid
|
|
241
|
+
* @throws if the input is not a valid {@link Cid}.
|
|
187
242
|
*/
|
|
188
|
-
export function
|
|
189
|
-
|
|
243
|
+
export function asCid<TValue, TOptions extends CheckCidOptions>(
|
|
244
|
+
value: TValue,
|
|
190
245
|
options: TOptions,
|
|
191
|
-
): InferCheckedCid<TOptions>
|
|
192
|
-
export function
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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')
|
|
196
254
|
}
|
|
197
255
|
|
|
198
256
|
/**
|
|
@@ -201,48 +259,63 @@ export function parseCid(input: string, options?: CidCheckOptions): Cid {
|
|
|
201
259
|
* @see {@link https://dasl.ing/cid.html DASL-CIDs}
|
|
202
260
|
* @throws if the input do not represent a valid DASL {@link Cid}
|
|
203
261
|
*/
|
|
204
|
-
export function decodeCid<TOptions extends
|
|
262
|
+
export function decodeCid<TOptions extends CheckCidOptions>(
|
|
205
263
|
cidBytes: Uint8Array,
|
|
206
264
|
options: TOptions,
|
|
207
265
|
): InferCheckedCid<TOptions>
|
|
208
|
-
export function decodeCid(cidBytes: Uint8Array, options?:
|
|
266
|
+
export function decodeCid(cidBytes: Uint8Array, options?: CheckCidOptions): Cid
|
|
209
267
|
export function decodeCid(
|
|
210
268
|
cidBytes: Uint8Array,
|
|
211
|
-
options?:
|
|
269
|
+
options?: CheckCidOptions,
|
|
212
270
|
): Cid {
|
|
213
271
|
const cid = CID.decode(cidBytes)
|
|
214
272
|
return asCid(cid, options)
|
|
215
273
|
}
|
|
216
274
|
|
|
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)
|
|
288
|
+
}
|
|
289
|
+
|
|
217
290
|
export function validateCidString(
|
|
218
291
|
input: string,
|
|
219
|
-
options?:
|
|
292
|
+
options?: CheckCidOptions,
|
|
220
293
|
): boolean {
|
|
221
|
-
return
|
|
294
|
+
return parseCidSafe(input, options)?.toString() === input
|
|
222
295
|
}
|
|
223
296
|
|
|
224
|
-
export function
|
|
297
|
+
export function parseCidSafe<TOptions extends CheckCidOptions>(
|
|
225
298
|
input: string,
|
|
226
299
|
options: TOptions,
|
|
227
|
-
): InferCheckedCid<TOptions> |
|
|
228
|
-
export function
|
|
300
|
+
): InferCheckedCid<TOptions> | null
|
|
301
|
+
export function parseCidSafe(
|
|
229
302
|
input: string,
|
|
230
|
-
options?:
|
|
231
|
-
): Cid |
|
|
232
|
-
export function
|
|
303
|
+
options?: CheckCidOptions,
|
|
304
|
+
): Cid | null
|
|
305
|
+
export function parseCidSafe(
|
|
233
306
|
input: string,
|
|
234
|
-
options?:
|
|
235
|
-
): Cid |
|
|
307
|
+
options?: CheckCidOptions,
|
|
308
|
+
): Cid | null {
|
|
236
309
|
try {
|
|
237
310
|
return parseCid(input, options)
|
|
238
311
|
} catch {
|
|
239
|
-
return
|
|
312
|
+
return null
|
|
240
313
|
}
|
|
241
314
|
}
|
|
242
315
|
|
|
243
316
|
export function ensureValidCidString(
|
|
244
317
|
input: string,
|
|
245
|
-
options?:
|
|
318
|
+
options?: CheckCidOptions,
|
|
246
319
|
): void {
|
|
247
320
|
if (!validateCidString(input, options)) {
|
|
248
321
|
throw new Error(`Invalid CID string`)
|
|
@@ -260,34 +333,90 @@ export async function isCidForBytes(
|
|
|
260
333
|
bytes: Uint8Array,
|
|
261
334
|
): Promise<boolean> {
|
|
262
335
|
if (cid.multihash.code === sha256.code) {
|
|
263
|
-
const
|
|
264
|
-
return
|
|
336
|
+
const multihash = await sha256.digest(bytes)
|
|
337
|
+
return multihashEquals(multihash, cid.multihash)
|
|
265
338
|
}
|
|
266
339
|
|
|
267
340
|
if (cid.multihash.code === sha512.code) {
|
|
268
|
-
const
|
|
269
|
-
return
|
|
341
|
+
const multihash = await sha512.digest(bytes)
|
|
342
|
+
return multihashEquals(multihash, cid.multihash)
|
|
270
343
|
}
|
|
271
344
|
|
|
272
345
|
// Don't know how to verify other multihash codes
|
|
273
346
|
throw new Error('Unsupported CID multihash')
|
|
274
347
|
}
|
|
275
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
|
+
|
|
276
358
|
export async function cidForCbor(bytes: Uint8Array): Promise<CborCid> {
|
|
277
|
-
const
|
|
278
|
-
return CID.createV1(DAG_CBOR_MULTICODEC,
|
|
359
|
+
const multihash = await sha256.digest(bytes)
|
|
360
|
+
return CID.createV1(DAG_CBOR_MULTICODEC, multihash) as CborCid
|
|
279
361
|
}
|
|
280
362
|
|
|
281
363
|
export async function cidForRawBytes(bytes: Uint8Array): Promise<RawCid> {
|
|
282
|
-
const
|
|
283
|
-
return CID.createV1(RAW_MULTICODEC,
|
|
364
|
+
const multihash = await sha256.digest(bytes)
|
|
365
|
+
return CID.createV1(RAW_MULTICODEC, multihash) as RawCid
|
|
284
366
|
}
|
|
285
367
|
|
|
286
|
-
export function cidForRawHash(
|
|
368
|
+
export function cidForRawHash(digest: Uint8Array): RawCid {
|
|
287
369
|
// Fool-proofing
|
|
288
|
-
if (
|
|
289
|
-
throw new Error(`Invalid SHA-256 hash length: ${
|
|
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
|
+
}
|
|
290
414
|
}
|
|
291
|
-
|
|
292
|
-
|
|
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
|
|
293
422
|
}
|