@fedify/vocab-runtime 2.4.0-dev.1634 → 2.4.0-dev.1655

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.
Files changed (37) hide show
  1. package/deno.json +1 -1
  2. package/dist/mod.cjs +146 -3
  3. package/dist/mod.d.cts +82 -1
  4. package/dist/mod.d.ts +82 -1
  5. package/dist/mod.js +141 -4
  6. package/dist/tests/decimal.test.cjs +5 -4
  7. package/dist/tests/decimal.test.mjs +5 -4
  8. package/dist/tests/digest-BJlumPNJ.mjs +140 -0
  9. package/dist/tests/digest-DLwUyHCK.cjs +175 -0
  10. package/dist/tests/digest.test.cjs +103 -0
  11. package/dist/tests/digest.test.d.cts +1 -0
  12. package/dist/tests/digest.test.d.mts +1 -0
  13. package/dist/tests/digest.test.mjs +103 -0
  14. package/dist/tests/{docloader-CTd4XwqK.cjs → docloader-DVVWmXLI.cjs} +1 -1
  15. package/dist/tests/{docloader-CNzoXrLM.mjs → docloader-HbEvzi-t.mjs} +1 -1
  16. package/dist/tests/docloader.test.cjs +2 -2
  17. package/dist/tests/docloader.test.mjs +2 -2
  18. package/dist/tests/{key-_wXwomh_.cjs → key-BcOWDLMm.cjs} +1 -1
  19. package/dist/tests/{key-CDGDH_vC.mjs → key-Drbw_2tw.mjs} +1 -1
  20. package/dist/tests/key.test.cjs +2 -2
  21. package/dist/tests/key.test.mjs +2 -2
  22. package/dist/tests/langstr.test.cjs +1 -1
  23. package/dist/tests/langstr.test.mjs +1 -1
  24. package/dist/tests/multibase/multibase.test.cjs +1 -1
  25. package/dist/tests/multibase/multibase.test.mjs +1 -1
  26. package/dist/tests/{multibase-B4bvakyA.mjs → multibase-Cluwl8OM.mjs} +12 -1
  27. package/dist/tests/{multibase-Bz_UUDtL.cjs → multibase-DcDQDNnI.cjs} +17 -0
  28. package/dist/tests/{request-BWDludWb.mjs → request-B6s_F7bi.mjs} +1 -1
  29. package/dist/tests/{request-Zpjq9m-W.cjs → request-DvEyU5Zf.cjs} +1 -1
  30. package/dist/tests/request.test.cjs +1 -1
  31. package/dist/tests/request.test.mjs +1 -1
  32. package/package.json +1 -1
  33. package/src/digest.test.ts +220 -0
  34. package/src/digest.ts +229 -0
  35. package/src/mod.ts +10 -0
  36. /package/dist/tests/{langstr-CbAxaeEZ.cjs → langstr-BOQHfJDr.cjs} +0 -0
  37. /package/dist/tests/{langstr-Di5AvKpB.mjs → langstr-DDLc4833.mjs} +0 -0
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.4.0-dev.1634+3b4bfbb6",
3
+ "version": "2.4.0-dev.1655+b8f3c3d5",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts",
package/dist/mod.cjs CHANGED
@@ -4371,7 +4371,7 @@ const preloadedContexts = {
4371
4371
  //#endregion
4372
4372
  //#region deno.json
4373
4373
  var name = "@fedify/vocab-runtime";
4374
- var version = "2.4.0-dev.1634+3b4bfbb6";
4374
+ var version = "2.4.0-dev.1655+b8f3c3d5";
4375
4375
  //#endregion
4376
4376
  //#region src/link.ts
4377
4377
  const parametersNeedLowerCase = ["rel", "type"];
@@ -4936,8 +4936,8 @@ function validateCryptoKey(key, type) {
4936
4936
  }
4937
4937
  //#endregion
4938
4938
  //#region src/multibase/util.ts
4939
- const textDecoder = new TextDecoder();
4940
- const decodeText = (bytes) => textDecoder.decode(bytes);
4939
+ const textDecoder$1 = new TextDecoder();
4940
+ const decodeText = (bytes) => textDecoder$1.decode(bytes);
4941
4941
  const textEncoder = new TextEncoder();
4942
4942
  const encodeText = (text) => textEncoder.encode(text);
4943
4943
  function concat(arrs, length) {
@@ -5526,6 +5526,143 @@ function parseDecimal(value) {
5526
5526
  return normalized;
5527
5527
  }
5528
5528
  //#endregion
5529
+ //#region src/digest.ts
5530
+ const SHA2_256_MULTIHASH_CODE = 18;
5531
+ const SHA2_256_DIGEST_LENGTH = 32;
5532
+ const MAX_DIGEST_MULTIBASE_LENGTH = 1 + (SHA2_256_DIGEST_LENGTH + 2) * 8;
5533
+ const textDecoder = new TextDecoder();
5534
+ const getArrayBufferByteLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")?.get;
5535
+ function isCanonicalVarintPrefix(data, prefix) {
5536
+ const canonical = addMulticodecPrefix(prefix.code, new Uint8Array());
5537
+ if (canonical.length !== prefix.prefixLength) return false;
5538
+ for (let i = 0; i < canonical.length; i++) if (data[i] !== canonical[i]) return false;
5539
+ return true;
5540
+ }
5541
+ function toWebCryptoBytes(bytes) {
5542
+ if (getArrayBufferByteLength != null) try {
5543
+ getArrayBufferByteLength.call(bytes.buffer);
5544
+ return bytes;
5545
+ } catch {}
5546
+ return new Uint8Array(bytes);
5547
+ }
5548
+ /**
5549
+ * Computes the SHA-256 digest of a byte sequence and encodes it as a
5550
+ * base58-btc multibase multihash suitable for FEP-ef61's
5551
+ * `digestMultibase` property.
5552
+ *
5553
+ * @param bytes The bytes to digest.
5554
+ * @returns The base58-btc multibase-encoded SHA-256 multihash.
5555
+ * @since 2.4.0
5556
+ */
5557
+ async function computeDigestMultibase(bytes) {
5558
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", toWebCryptoBytes(bytes)));
5559
+ const multihash = addMulticodecPrefix(SHA2_256_MULTIHASH_CODE, addMulticodecPrefix(digest.length, digest));
5560
+ return textDecoder.decode(encodeMultibase("base58btc", multihash));
5561
+ }
5562
+ /**
5563
+ * Parses and validates a SHA-256 `digestMultibase` value.
5564
+ *
5565
+ * @param value The multibase-encoded multihash to parse.
5566
+ * @returns The digest algorithm and raw digest bytes.
5567
+ * @throws {TypeError} If the value is malformed or uses an unsupported hash
5568
+ * algorithm.
5569
+ * @since 2.4.0
5570
+ */
5571
+ function parseDigestMultibase(value) {
5572
+ if (value.length > MAX_DIGEST_MULTIBASE_LENGTH) throw new TypeError("Invalid digestMultibase encoding.");
5573
+ let multihash;
5574
+ try {
5575
+ multihash = decodeMultibase(value);
5576
+ } catch (error) {
5577
+ throw new TypeError("Invalid digestMultibase encoding.", { cause: error });
5578
+ }
5579
+ const encoding = encodingFromBaseData(value);
5580
+ if (value !== textDecoder.decode(encodeMultibase(encoding.name, multihash))) throw new TypeError("Invalid digestMultibase encoding.");
5581
+ let algorithmPrefix;
5582
+ try {
5583
+ algorithmPrefix = getMulticodecPrefix(multihash);
5584
+ } catch (error) {
5585
+ throw new TypeError("Invalid digestMultibase multihash.", { cause: error });
5586
+ }
5587
+ if (!isCanonicalVarintPrefix(multihash, algorithmPrefix)) throw new TypeError("Invalid digestMultibase multihash.");
5588
+ if (algorithmPrefix.code !== SHA2_256_MULTIHASH_CODE) throw new TypeError(`Unsupported digest algorithm: 0x${algorithmPrefix.code.toString(16)}`);
5589
+ const lengthAndDigest = multihash.subarray(algorithmPrefix.prefixLength);
5590
+ let lengthPrefix;
5591
+ try {
5592
+ lengthPrefix = getMulticodecPrefix(lengthAndDigest);
5593
+ } catch (error) {
5594
+ throw new TypeError("Invalid digestMultibase multihash.", { cause: error });
5595
+ }
5596
+ if (!isCanonicalVarintPrefix(lengthAndDigest, lengthPrefix)) throw new TypeError("Invalid digestMultibase multihash.");
5597
+ const digest = lengthAndDigest.slice(lengthPrefix.prefixLength);
5598
+ if (lengthPrefix.code !== SHA2_256_DIGEST_LENGTH || digest.length !== SHA2_256_DIGEST_LENGTH) throw new TypeError("Invalid SHA-256 digest length.");
5599
+ return {
5600
+ algorithm: "sha2-256",
5601
+ digest
5602
+ };
5603
+ }
5604
+ function extractDigestMultibase(value) {
5605
+ const hashlink = typeof value === "string" ? value : value.href;
5606
+ const match = /^hl:([^:\r\n\u2028\u2029]+)$/i.exec(hashlink);
5607
+ if (match == null || match[0].length !== hashlink.length) throw new TypeError("Invalid simple hashlink.");
5608
+ return match[1];
5609
+ }
5610
+ /**
5611
+ * Parses a metadata-free `hl:` hashlink and validates its resource digest.
5612
+ *
5613
+ * @param value The simple hashlink to parse.
5614
+ * @returns The `digestMultibase` value carried by the hashlink.
5615
+ * @throws {TypeError} If the hashlink is malformed, contains metadata, or
5616
+ * carries an invalid or unsupported digest.
5617
+ * @since 2.4.0
5618
+ */
5619
+ function parseHashlink(value) {
5620
+ const digestMultibase = extractDigestMultibase(value);
5621
+ parseDigestMultibase(digestMultibase);
5622
+ return { digestMultibase };
5623
+ }
5624
+ /**
5625
+ * Creates a metadata-free `hl:` hashlink from a `digestMultibase` value.
5626
+ *
5627
+ * @param digestMultibase The SHA-256 multibase multihash to embed.
5628
+ * @returns The simple hashlink.
5629
+ * @throws {TypeError} If the digest is malformed or unsupported.
5630
+ * @since 2.4.0
5631
+ */
5632
+ function createHashlink(digestMultibase) {
5633
+ parseDigestMultibase(digestMultibase);
5634
+ return `hl:${digestMultibase}`;
5635
+ }
5636
+ /**
5637
+ * Verifies that bytes match a SHA-256 `digestMultibase` value.
5638
+ *
5639
+ * @param bytes The bytes to verify.
5640
+ * @param digestMultibase The expected digest.
5641
+ * @returns Whether the bytes match the digest.
5642
+ * @throws {TypeError} If the digest is malformed or unsupported.
5643
+ * @since 2.4.0
5644
+ */
5645
+ async function verifyDigestMultibase(bytes, digestMultibase) {
5646
+ const expected = parseDigestMultibase(digestMultibase).digest;
5647
+ const actual = new Uint8Array(await crypto.subtle.digest("SHA-256", toWebCryptoBytes(bytes)));
5648
+ if (expected.length !== actual.length) return false;
5649
+ let difference = 0;
5650
+ for (let i = 0; i < expected.length; i++) difference |= expected[i] ^ actual[i];
5651
+ return difference === 0;
5652
+ }
5653
+ /**
5654
+ * Verifies that bytes match the resource digest in a simple hashlink.
5655
+ *
5656
+ * @param bytes The bytes to verify.
5657
+ * @param hashlink The simple hashlink containing the expected digest.
5658
+ * @returns Whether the bytes match the hashlink digest.
5659
+ * @throws {TypeError} If the hashlink or digest is malformed or unsupported.
5660
+ * @since 2.4.0
5661
+ */
5662
+ async function verifyHashlink(bytes, hashlink) {
5663
+ return await verifyDigestMultibase(bytes, extractDigestMultibase(hashlink));
5664
+ }
5665
+ //#endregion
5529
5666
  //#region src/langstr.ts
5530
5667
  /**
5531
5668
  * A language-tagged string which corresponds to the `rdf:langString` type.
@@ -5560,7 +5697,9 @@ exports.UrlError = require_url.UrlError;
5560
5697
  exports.arePortableUrisEqual = require_url.arePortableUrisEqual;
5561
5698
  exports.canParseDecimal = canParseDecimal;
5562
5699
  exports.canonicalizePortableUri = require_url.canonicalizePortableUri;
5700
+ exports.computeDigestMultibase = computeDigestMultibase;
5563
5701
  exports.createActivityPubRequest = createActivityPubRequest;
5702
+ exports.createHashlink = createHashlink;
5564
5703
  exports.decodeMultibase = decodeMultibase;
5565
5704
  exports.encodeMultibase = encodeMultibase;
5566
5705
  exports.encodingFromBaseData = encodingFromBaseData;
@@ -5587,8 +5726,12 @@ exports.isValidPublicIPv6Address = require_url.isValidPublicIPv6Address;
5587
5726
  exports.logRequest = logRequest;
5588
5727
  exports.parseDecimal = parseDecimal;
5589
5728
  exports.parseDidKeyVerificationMethod = parseDidKeyVerificationMethod;
5729
+ exports.parseDigestMultibase = parseDigestMultibase;
5590
5730
  exports.parseGatewayUrl = require_url.parseGatewayUrl;
5731
+ exports.parseHashlink = parseHashlink;
5591
5732
  exports.parseIri = require_url.parseIri;
5592
5733
  exports.parseJsonLdId = require_url.parseJsonLdId;
5593
5734
  exports.preloadedContexts = preloadedContexts;
5594
5735
  exports.validatePublicUrl = require_url.validatePublicUrl;
5736
+ exports.verifyDigestMultibase = verifyDigestMultibase;
5737
+ exports.verifyHashlink = verifyHashlink;
package/dist/mod.d.cts CHANGED
@@ -204,6 +204,87 @@ declare function canParseDecimal(value: string): boolean;
204
204
  */
205
205
  declare function parseDecimal(value: string): Decimal;
206
206
  //#endregion
207
+ //#region src/digest.d.ts
208
+ /**
209
+ * A parsed SHA-256 resource digest.
210
+ *
211
+ * @since 2.4.0
212
+ */
213
+ interface ParsedDigestMultibase {
214
+ /** The multihash algorithm represented by the digest. */
215
+ readonly algorithm: "sha2-256";
216
+ /** The raw 32-byte SHA-256 digest. */
217
+ readonly digest: Uint8Array;
218
+ }
219
+ /**
220
+ * A parsed simple hashlink.
221
+ *
222
+ * @since 2.4.0
223
+ */
224
+ interface ParsedHashlink {
225
+ /** The multibase-encoded multihash carried by the hashlink. */
226
+ readonly digestMultibase: string;
227
+ }
228
+ /**
229
+ * Computes the SHA-256 digest of a byte sequence and encodes it as a
230
+ * base58-btc multibase multihash suitable for FEP-ef61's
231
+ * `digestMultibase` property.
232
+ *
233
+ * @param bytes The bytes to digest.
234
+ * @returns The base58-btc multibase-encoded SHA-256 multihash.
235
+ * @since 2.4.0
236
+ */
237
+ declare function computeDigestMultibase(bytes: Uint8Array): Promise<string>;
238
+ /**
239
+ * Parses and validates a SHA-256 `digestMultibase` value.
240
+ *
241
+ * @param value The multibase-encoded multihash to parse.
242
+ * @returns The digest algorithm and raw digest bytes.
243
+ * @throws {TypeError} If the value is malformed or uses an unsupported hash
244
+ * algorithm.
245
+ * @since 2.4.0
246
+ */
247
+ declare function parseDigestMultibase(value: string): ParsedDigestMultibase;
248
+ /**
249
+ * Parses a metadata-free `hl:` hashlink and validates its resource digest.
250
+ *
251
+ * @param value The simple hashlink to parse.
252
+ * @returns The `digestMultibase` value carried by the hashlink.
253
+ * @throws {TypeError} If the hashlink is malformed, contains metadata, or
254
+ * carries an invalid or unsupported digest.
255
+ * @since 2.4.0
256
+ */
257
+ declare function parseHashlink(value: string | URL): ParsedHashlink;
258
+ /**
259
+ * Creates a metadata-free `hl:` hashlink from a `digestMultibase` value.
260
+ *
261
+ * @param digestMultibase The SHA-256 multibase multihash to embed.
262
+ * @returns The simple hashlink.
263
+ * @throws {TypeError} If the digest is malformed or unsupported.
264
+ * @since 2.4.0
265
+ */
266
+ declare function createHashlink(digestMultibase: string): string;
267
+ /**
268
+ * Verifies that bytes match a SHA-256 `digestMultibase` value.
269
+ *
270
+ * @param bytes The bytes to verify.
271
+ * @param digestMultibase The expected digest.
272
+ * @returns Whether the bytes match the digest.
273
+ * @throws {TypeError} If the digest is malformed or unsupported.
274
+ * @since 2.4.0
275
+ */
276
+ declare function verifyDigestMultibase(bytes: Uint8Array, digestMultibase: string): Promise<boolean>;
277
+ /**
278
+ * Verifies that bytes match the resource digest in a simple hashlink.
279
+ *
280
+ * @param bytes The bytes to verify.
281
+ * @param hashlink The simple hashlink containing the expected digest.
282
+ * @returns Whether the bytes match the hashlink digest.
283
+ * @throws {TypeError} If the hashlink or digest is malformed or unsupported.
284
+ * @since 2.4.0
285
+ */
286
+ declare function verifyHashlink(bytes: Uint8Array, hashlink: string | URL): Promise<boolean>;
287
+ //#endregion
207
288
  //#region src/langstr.d.ts
208
289
  /**
209
290
  * A language-tagged string which corresponds to the `rdf:langString` type.
@@ -390,4 +471,4 @@ declare function isValidPublicIPv4Address(address: string): boolean;
390
471
  declare function isValidPublicIPv6Address(address: string): boolean;
391
472
  declare function expandIPv6Address(address: string): string;
392
473
  //#endregion
393
- export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseGatewayUrl, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
474
+ export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type ParsedDigestMultibase, type ParsedHashlink, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, computeDigestMultibase, createActivityPubRequest, createHashlink, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseDigestMultibase, parseGatewayUrl, parseHashlink, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl, verifyDigestMultibase, verifyHashlink };
package/dist/mod.d.ts CHANGED
@@ -204,6 +204,87 @@ declare function canParseDecimal(value: string): boolean;
204
204
  */
205
205
  declare function parseDecimal(value: string): Decimal;
206
206
  //#endregion
207
+ //#region src/digest.d.ts
208
+ /**
209
+ * A parsed SHA-256 resource digest.
210
+ *
211
+ * @since 2.4.0
212
+ */
213
+ interface ParsedDigestMultibase {
214
+ /** The multihash algorithm represented by the digest. */
215
+ readonly algorithm: "sha2-256";
216
+ /** The raw 32-byte SHA-256 digest. */
217
+ readonly digest: Uint8Array;
218
+ }
219
+ /**
220
+ * A parsed simple hashlink.
221
+ *
222
+ * @since 2.4.0
223
+ */
224
+ interface ParsedHashlink {
225
+ /** The multibase-encoded multihash carried by the hashlink. */
226
+ readonly digestMultibase: string;
227
+ }
228
+ /**
229
+ * Computes the SHA-256 digest of a byte sequence and encodes it as a
230
+ * base58-btc multibase multihash suitable for FEP-ef61's
231
+ * `digestMultibase` property.
232
+ *
233
+ * @param bytes The bytes to digest.
234
+ * @returns The base58-btc multibase-encoded SHA-256 multihash.
235
+ * @since 2.4.0
236
+ */
237
+ declare function computeDigestMultibase(bytes: Uint8Array): Promise<string>;
238
+ /**
239
+ * Parses and validates a SHA-256 `digestMultibase` value.
240
+ *
241
+ * @param value The multibase-encoded multihash to parse.
242
+ * @returns The digest algorithm and raw digest bytes.
243
+ * @throws {TypeError} If the value is malformed or uses an unsupported hash
244
+ * algorithm.
245
+ * @since 2.4.0
246
+ */
247
+ declare function parseDigestMultibase(value: string): ParsedDigestMultibase;
248
+ /**
249
+ * Parses a metadata-free `hl:` hashlink and validates its resource digest.
250
+ *
251
+ * @param value The simple hashlink to parse.
252
+ * @returns The `digestMultibase` value carried by the hashlink.
253
+ * @throws {TypeError} If the hashlink is malformed, contains metadata, or
254
+ * carries an invalid or unsupported digest.
255
+ * @since 2.4.0
256
+ */
257
+ declare function parseHashlink(value: string | URL): ParsedHashlink;
258
+ /**
259
+ * Creates a metadata-free `hl:` hashlink from a `digestMultibase` value.
260
+ *
261
+ * @param digestMultibase The SHA-256 multibase multihash to embed.
262
+ * @returns The simple hashlink.
263
+ * @throws {TypeError} If the digest is malformed or unsupported.
264
+ * @since 2.4.0
265
+ */
266
+ declare function createHashlink(digestMultibase: string): string;
267
+ /**
268
+ * Verifies that bytes match a SHA-256 `digestMultibase` value.
269
+ *
270
+ * @param bytes The bytes to verify.
271
+ * @param digestMultibase The expected digest.
272
+ * @returns Whether the bytes match the digest.
273
+ * @throws {TypeError} If the digest is malformed or unsupported.
274
+ * @since 2.4.0
275
+ */
276
+ declare function verifyDigestMultibase(bytes: Uint8Array, digestMultibase: string): Promise<boolean>;
277
+ /**
278
+ * Verifies that bytes match the resource digest in a simple hashlink.
279
+ *
280
+ * @param bytes The bytes to verify.
281
+ * @param hashlink The simple hashlink containing the expected digest.
282
+ * @returns Whether the bytes match the hashlink digest.
283
+ * @throws {TypeError} If the hashlink or digest is malformed or unsupported.
284
+ * @since 2.4.0
285
+ */
286
+ declare function verifyHashlink(bytes: Uint8Array, hashlink: string | URL): Promise<boolean>;
287
+ //#endregion
207
288
  //#region src/langstr.d.ts
208
289
  /**
209
290
  * A language-tagged string which corresponds to the `rdf:langString` type.
@@ -390,4 +471,4 @@ declare function isValidPublicIPv4Address(address: string): boolean;
390
471
  declare function isValidPublicIPv6Address(address: string): boolean;
391
472
  declare function expandIPv6Address(address: string): string;
392
473
  //#endregion
393
- export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseGatewayUrl, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
474
+ export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type ParsedDigestMultibase, type ParsedHashlink, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, computeDigestMultibase, createActivityPubRequest, createHashlink, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseDigestMultibase, parseGatewayUrl, parseHashlink, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl, verifyDigestMultibase, verifyHashlink };
package/dist/mod.js CHANGED
@@ -4367,7 +4367,7 @@ const preloadedContexts = {
4367
4367
  //#endregion
4368
4368
  //#region deno.json
4369
4369
  var name = "@fedify/vocab-runtime";
4370
- var version = "2.4.0-dev.1634+3b4bfbb6";
4370
+ var version = "2.4.0-dev.1655+b8f3c3d5";
4371
4371
  //#endregion
4372
4372
  //#region src/link.ts
4373
4373
  const parametersNeedLowerCase = ["rel", "type"];
@@ -4932,8 +4932,8 @@ function validateCryptoKey(key, type) {
4932
4932
  }
4933
4933
  //#endregion
4934
4934
  //#region src/multibase/util.ts
4935
- const textDecoder = new TextDecoder();
4936
- const decodeText = (bytes) => textDecoder.decode(bytes);
4935
+ const textDecoder$1 = new TextDecoder();
4936
+ const decodeText = (bytes) => textDecoder$1.decode(bytes);
4937
4937
  const textEncoder = new TextEncoder();
4938
4938
  const encodeText = (text) => textEncoder.encode(text);
4939
4939
  function concat(arrs, length) {
@@ -5522,6 +5522,143 @@ function parseDecimal(value) {
5522
5522
  return normalized;
5523
5523
  }
5524
5524
  //#endregion
5525
+ //#region src/digest.ts
5526
+ const SHA2_256_MULTIHASH_CODE = 18;
5527
+ const SHA2_256_DIGEST_LENGTH = 32;
5528
+ const MAX_DIGEST_MULTIBASE_LENGTH = 1 + (SHA2_256_DIGEST_LENGTH + 2) * 8;
5529
+ const textDecoder = new TextDecoder();
5530
+ const getArrayBufferByteLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")?.get;
5531
+ function isCanonicalVarintPrefix(data, prefix) {
5532
+ const canonical = addMulticodecPrefix(prefix.code, new Uint8Array());
5533
+ if (canonical.length !== prefix.prefixLength) return false;
5534
+ for (let i = 0; i < canonical.length; i++) if (data[i] !== canonical[i]) return false;
5535
+ return true;
5536
+ }
5537
+ function toWebCryptoBytes(bytes) {
5538
+ if (getArrayBufferByteLength != null) try {
5539
+ getArrayBufferByteLength.call(bytes.buffer);
5540
+ return bytes;
5541
+ } catch {}
5542
+ return new Uint8Array(bytes);
5543
+ }
5544
+ /**
5545
+ * Computes the SHA-256 digest of a byte sequence and encodes it as a
5546
+ * base58-btc multibase multihash suitable for FEP-ef61's
5547
+ * `digestMultibase` property.
5548
+ *
5549
+ * @param bytes The bytes to digest.
5550
+ * @returns The base58-btc multibase-encoded SHA-256 multihash.
5551
+ * @since 2.4.0
5552
+ */
5553
+ async function computeDigestMultibase(bytes) {
5554
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", toWebCryptoBytes(bytes)));
5555
+ const multihash = addMulticodecPrefix(SHA2_256_MULTIHASH_CODE, addMulticodecPrefix(digest.length, digest));
5556
+ return textDecoder.decode(encodeMultibase("base58btc", multihash));
5557
+ }
5558
+ /**
5559
+ * Parses and validates a SHA-256 `digestMultibase` value.
5560
+ *
5561
+ * @param value The multibase-encoded multihash to parse.
5562
+ * @returns The digest algorithm and raw digest bytes.
5563
+ * @throws {TypeError} If the value is malformed or uses an unsupported hash
5564
+ * algorithm.
5565
+ * @since 2.4.0
5566
+ */
5567
+ function parseDigestMultibase(value) {
5568
+ if (value.length > MAX_DIGEST_MULTIBASE_LENGTH) throw new TypeError("Invalid digestMultibase encoding.");
5569
+ let multihash;
5570
+ try {
5571
+ multihash = decodeMultibase(value);
5572
+ } catch (error) {
5573
+ throw new TypeError("Invalid digestMultibase encoding.", { cause: error });
5574
+ }
5575
+ const encoding = encodingFromBaseData(value);
5576
+ if (value !== textDecoder.decode(encodeMultibase(encoding.name, multihash))) throw new TypeError("Invalid digestMultibase encoding.");
5577
+ let algorithmPrefix;
5578
+ try {
5579
+ algorithmPrefix = getMulticodecPrefix(multihash);
5580
+ } catch (error) {
5581
+ throw new TypeError("Invalid digestMultibase multihash.", { cause: error });
5582
+ }
5583
+ if (!isCanonicalVarintPrefix(multihash, algorithmPrefix)) throw new TypeError("Invalid digestMultibase multihash.");
5584
+ if (algorithmPrefix.code !== SHA2_256_MULTIHASH_CODE) throw new TypeError(`Unsupported digest algorithm: 0x${algorithmPrefix.code.toString(16)}`);
5585
+ const lengthAndDigest = multihash.subarray(algorithmPrefix.prefixLength);
5586
+ let lengthPrefix;
5587
+ try {
5588
+ lengthPrefix = getMulticodecPrefix(lengthAndDigest);
5589
+ } catch (error) {
5590
+ throw new TypeError("Invalid digestMultibase multihash.", { cause: error });
5591
+ }
5592
+ if (!isCanonicalVarintPrefix(lengthAndDigest, lengthPrefix)) throw new TypeError("Invalid digestMultibase multihash.");
5593
+ const digest = lengthAndDigest.slice(lengthPrefix.prefixLength);
5594
+ if (lengthPrefix.code !== SHA2_256_DIGEST_LENGTH || digest.length !== SHA2_256_DIGEST_LENGTH) throw new TypeError("Invalid SHA-256 digest length.");
5595
+ return {
5596
+ algorithm: "sha2-256",
5597
+ digest
5598
+ };
5599
+ }
5600
+ function extractDigestMultibase(value) {
5601
+ const hashlink = typeof value === "string" ? value : value.href;
5602
+ const match = /^hl:([^:\r\n\u2028\u2029]+)$/i.exec(hashlink);
5603
+ if (match == null || match[0].length !== hashlink.length) throw new TypeError("Invalid simple hashlink.");
5604
+ return match[1];
5605
+ }
5606
+ /**
5607
+ * Parses a metadata-free `hl:` hashlink and validates its resource digest.
5608
+ *
5609
+ * @param value The simple hashlink to parse.
5610
+ * @returns The `digestMultibase` value carried by the hashlink.
5611
+ * @throws {TypeError} If the hashlink is malformed, contains metadata, or
5612
+ * carries an invalid or unsupported digest.
5613
+ * @since 2.4.0
5614
+ */
5615
+ function parseHashlink(value) {
5616
+ const digestMultibase = extractDigestMultibase(value);
5617
+ parseDigestMultibase(digestMultibase);
5618
+ return { digestMultibase };
5619
+ }
5620
+ /**
5621
+ * Creates a metadata-free `hl:` hashlink from a `digestMultibase` value.
5622
+ *
5623
+ * @param digestMultibase The SHA-256 multibase multihash to embed.
5624
+ * @returns The simple hashlink.
5625
+ * @throws {TypeError} If the digest is malformed or unsupported.
5626
+ * @since 2.4.0
5627
+ */
5628
+ function createHashlink(digestMultibase) {
5629
+ parseDigestMultibase(digestMultibase);
5630
+ return `hl:${digestMultibase}`;
5631
+ }
5632
+ /**
5633
+ * Verifies that bytes match a SHA-256 `digestMultibase` value.
5634
+ *
5635
+ * @param bytes The bytes to verify.
5636
+ * @param digestMultibase The expected digest.
5637
+ * @returns Whether the bytes match the digest.
5638
+ * @throws {TypeError} If the digest is malformed or unsupported.
5639
+ * @since 2.4.0
5640
+ */
5641
+ async function verifyDigestMultibase(bytes, digestMultibase) {
5642
+ const expected = parseDigestMultibase(digestMultibase).digest;
5643
+ const actual = new Uint8Array(await crypto.subtle.digest("SHA-256", toWebCryptoBytes(bytes)));
5644
+ if (expected.length !== actual.length) return false;
5645
+ let difference = 0;
5646
+ for (let i = 0; i < expected.length; i++) difference |= expected[i] ^ actual[i];
5647
+ return difference === 0;
5648
+ }
5649
+ /**
5650
+ * Verifies that bytes match the resource digest in a simple hashlink.
5651
+ *
5652
+ * @param bytes The bytes to verify.
5653
+ * @param hashlink The simple hashlink containing the expected digest.
5654
+ * @returns Whether the bytes match the hashlink digest.
5655
+ * @throws {TypeError} If the hashlink or digest is malformed or unsupported.
5656
+ * @since 2.4.0
5657
+ */
5658
+ async function verifyHashlink(bytes, hashlink) {
5659
+ return await verifyDigestMultibase(bytes, extractDigestMultibase(hashlink));
5660
+ }
5661
+ //#endregion
5525
5662
  //#region src/langstr.ts
5526
5663
  /**
5527
5664
  * A language-tagged string which corresponds to the `rdf:langString` type.
@@ -5550,4 +5687,4 @@ LanguageString.prototype[Symbol.for("nodejs.util.inspect.custom")] = function(_d
5550
5687
  return `<${this.locale.baseName}> ${inspect(this.toString(), options)}`;
5551
5688
  };
5552
5689
  //#endregion
5553
- export { FetchError, LanguageString, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseGatewayUrl, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
5690
+ export { FetchError, LanguageString, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, computeDigestMultibase, createActivityPubRequest, createHashlink, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseDigestMultibase, parseGatewayUrl, parseHashlink, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl, verifyDigestMultibase, verifyHashlink };
@@ -1,9 +1,10 @@
1
1
  require("./chunk-C2EiDwsr.cjs");
2
- require("./docloader-CTd4XwqK.cjs");
2
+ require("./docloader-DVVWmXLI.cjs");
3
3
  require("./url-CsOV_B_P.cjs");
4
- require("./key-_wXwomh_.cjs");
5
- require("./multibase-Bz_UUDtL.cjs");
6
- require("./langstr-CbAxaeEZ.cjs");
4
+ require("./key-BcOWDLMm.cjs");
5
+ require("./multibase-DcDQDNnI.cjs");
6
+ require("./digest-DLwUyHCK.cjs");
7
+ require("./langstr-BOQHfJDr.cjs");
7
8
  let node_assert = require("node:assert");
8
9
  let node_test = require("node:test");
9
10
  //#region src/decimal.ts
@@ -1,8 +1,9 @@
1
- import "./docloader-CNzoXrLM.mjs";
1
+ import "./docloader-HbEvzi-t.mjs";
2
2
  import "./url-Du7RQQgP.mjs";
3
- import "./key-CDGDH_vC.mjs";
4
- import "./multibase-B4bvakyA.mjs";
5
- import "./langstr-Di5AvKpB.mjs";
3
+ import "./key-Drbw_2tw.mjs";
4
+ import "./multibase-Cluwl8OM.mjs";
5
+ import "./digest-BJlumPNJ.mjs";
6
+ import "./langstr-DDLc4833.mjs";
6
7
  import { deepStrictEqual, throws } from "node:assert";
7
8
  import { test } from "node:test";
8
9
  //#region src/decimal.ts