@fedify/vocab-runtime 2.4.0-dev.2027 → 2.4.0-dev.2035

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 (33) hide show
  1. package/deno.json +1 -1
  2. package/dist/internal/jsonld-cache.cjs +1 -1
  3. package/dist/internal/jsonld-cache.js +1 -1
  4. package/dist/mod.cjs +4 -2
  5. package/dist/mod.d.cts +74 -1
  6. package/dist/mod.d.ts +74 -1
  7. package/dist/mod.js +3 -3
  8. package/dist/tests/{body-C8W6PG-f.mjs → body-BEIDQFV6.mjs} +1 -1
  9. package/dist/tests/{body-CjqMU6be.cjs → body-DRpkDnEg.cjs} +1 -1
  10. package/dist/tests/body.test.cjs +1 -1
  11. package/dist/tests/body.test.mjs +1 -1
  12. package/dist/tests/decimal.test.cjs +2 -2
  13. package/dist/tests/decimal.test.mjs +2 -2
  14. package/dist/tests/{docloader-BcthkJvx.mjs → docloader-DHux1ztB.mjs} +3 -3
  15. package/dist/tests/{docloader-DDwe-rFE.cjs → docloader-M8t8o-GD.cjs} +3 -3
  16. package/dist/tests/docloader.test.cjs +3 -3
  17. package/dist/tests/docloader.test.mjs +3 -3
  18. package/dist/tests/jsonld-cache.test.cjs +1 -1
  19. package/dist/tests/jsonld-cache.test.mjs +1 -1
  20. package/dist/tests/{request-DV2_yz3V.cjs → request-BbczASfn.cjs} +1 -1
  21. package/dist/tests/{request-CeEwiwiU.mjs → request-eP_YLVjb.mjs} +1 -1
  22. package/dist/tests/request.test.cjs +1 -1
  23. package/dist/tests/request.test.mjs +1 -1
  24. package/dist/{url-i33c0US6.cjs → tests/url-BqlldzT8.cjs} +164 -1
  25. package/dist/tests/{url-Basm1L_c.mjs → url-DgJM9WJn.mjs} +147 -1
  26. package/dist/tests/url.test.cjs +220 -1
  27. package/dist/tests/url.test.mjs +220 -1
  28. package/dist/{url-BHAShw9J.js → url-CEhi4hb4.js} +147 -1
  29. package/dist/{tests/url-CPfMatUL.cjs → url-Cke4irYD.cjs} +155 -2
  30. package/package.json +2 -2
  31. package/src/mod.ts +2 -0
  32. package/src/url.test.ts +361 -0
  33. package/src/url.ts +235 -0
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.4.0-dev.2027+fcf88bfc",
3
+ "version": "2.4.0-dev.2035+d1f8f8e2",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts",
@@ -1,6 +1,6 @@
1
1
 
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_url = require("../url-i33c0US6.cjs");
3
+ const require_url = require("../url-Cke4irYD.cjs");
4
4
  const require_jsonld = require("../jsonld.cjs");
5
5
  //#region src/internal/jsonld-cache.ts
6
6
  const noJsonLdContext = Symbol("noJsonLdContext");
@@ -1,5 +1,5 @@
1
1
 
2
- import { a as formatIri, c as haveSameIriOrigin, s as haveSameFe34Origin } from "../url-BHAShw9J.js";
2
+ import { a as formatIri, c as haveSameFe34Origin, l as haveSameIriOrigin } from "../url-CEhi4hb4.js";
3
3
  import jsonld_default from "../jsonld.js";
4
4
  //#region src/internal/jsonld-cache.ts
5
5
  const noJsonLdContext = Symbol("noJsonLdContext");
package/dist/mod.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require_rolldown_runtime = require("./rolldown-runtime-B7lfambq.cjs");
4
4
  const require_contexts = require("./contexts-2hEbs3Qk.cjs");
5
- const require_url = require("./url-i33c0US6.cjs");
5
+ const require_url = require("./url-Cke4irYD.cjs");
6
6
  let _logtape_logtape = require("@logtape/logtape");
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
8
8
  let node_process = require("node:process");
@@ -16,7 +16,7 @@ let _multiformats_base_x = require("@multiformats/base-x");
16
16
  _multiformats_base_x = require_rolldown_runtime.__toESM(_multiformats_base_x, 1);
17
17
  //#region deno.json
18
18
  var name = "@fedify/vocab-runtime";
19
- var version = "2.4.0-dev.2027+fcf88bfc";
19
+ var version = "2.4.0-dev.2035+d1f8f8e2";
20
20
  //#endregion
21
21
  //#region src/request.ts
22
22
  /**
@@ -1379,6 +1379,7 @@ exports.exportDidKey = exportDidKey;
1379
1379
  exports.exportMultibaseKey = exportMultibaseKey;
1380
1380
  exports.exportSpki = exportSpki;
1381
1381
  exports.formatIri = require_url.formatIri;
1382
+ exports.fromCompatibleEf61Id = require_url.fromCompatibleEf61Id;
1382
1383
  exports.getDocumentLoader = getDocumentLoader;
1383
1384
  exports.getFe34Origin = require_url.getFe34Origin;
1384
1385
  exports.getRemoteDocument = getRemoteDocument;
@@ -1403,6 +1404,7 @@ exports.parseHashlink = parseHashlink;
1403
1404
  exports.parseIri = require_url.parseIri;
1404
1405
  exports.parseJsonLdId = require_url.parseJsonLdId;
1405
1406
  exports.preloadedContexts = require_contexts.preloadedContexts;
1407
+ exports.toCompatibleEf61Id = require_url.toCompatibleEf61Id;
1406
1408
  exports.validatePublicUrl = require_url.validatePublicUrl;
1407
1409
  exports.verifyDigestMultibase = verifyDigestMultibase;
1408
1410
  exports.verifyHashlink = verifyHashlink;
package/dist/mod.d.cts CHANGED
@@ -466,6 +466,79 @@ declare function isGatewayUrl(url: URL): boolean;
466
466
  */
467
467
  declare function parseGatewayUrl(url: string): URL;
468
468
  /**
469
+ * Converts an [FEP-ef61] compatible identifier into a portable ActivityPub
470
+ * URI.
471
+ *
472
+ * A compatible identifier is an HTTP(S) URL under a gateway's fixed
473
+ * `/.well-known/apgateway/` path, such as
474
+ * `https://server.example/.well-known/apgateway/did:key:z6Mk.../objects/1`.
475
+ * This function removes the gateway part and returns the corresponding
476
+ * portable URI, e.g., `ap+ef61://did:key:z6Mk.../objects/1`, in the same
477
+ * internal `URL` form that {@link parseIri} produces. The path, query, and
478
+ * fragment are preserved, so the result is a portable URI, not a comparison
479
+ * form; pass its `href` to {@link canonicalizePortableUri} or
480
+ * {@link arePortableUrisEqual} to compare it with other portable URIs.
481
+ *
482
+ * The conversion only reveals the *claimed* portable identifier. Anyone can
483
+ * publish a compatible identifier for any DID on their own server, so the
484
+ * gateway that served it is neither the object's origin nor authorized to act
485
+ * for the DID. Callers must still verify the retrieved document's Object
486
+ * Integrity Proof against the DID, as FEP-ef61 requires, and should keep the
487
+ * original URL if they need the gateway as a retrieval hint.
488
+ *
489
+ * Arbitrary gateway paths are not supported.
490
+ *
491
+ * [FEP-ef61]: https://w3id.org/fep/ef61
492
+ *
493
+ * @param input The URL to convert.
494
+ * @returns The portable ActivityPub URI, or `null` if the input is not an
495
+ * HTTP(S) URL whose path starts with `/.well-known/apgateway/did:`.
496
+ * Other gateway routes, such as the gateway discovery endpoint and
497
+ * hashlink media URLs, also yield `null`.
498
+ * @throws {TypeError} If the input looks like a compatible identifier but is
499
+ * malformed, e.g., it has an invalid DID, no object path,
500
+ * invalid percent-encoding, credentials, or location
501
+ * hints (`@gateway` query parameters, or the legacy
502
+ * `gateways` parameter), which FEP-ef61 forbids in
503
+ * compatible identifiers.
504
+ * @since 2.4.0
505
+ */
506
+ declare function fromCompatibleEf61Id(input: string | URL): URL | null;
507
+ /**
508
+ * Converts a portable ActivityPub URI into an [FEP-ef61] compatible
509
+ * identifier, which is an HTTP(S) URL under the gateway's fixed
510
+ * `/.well-known/apgateway/` path.
511
+ *
512
+ * For example, `ap+ef61://did:key:z6Mk.../objects/1` and
513
+ * `https://server.example` yield
514
+ * `https://server.example/.well-known/apgateway/did:key:z6Mk.../objects/1`.
515
+ * Both `ap:` and `ap+ef61:` URIs with decoded or percent-encoded DID
516
+ * authorities are accepted. Publishers should use the first gateway in the
517
+ * actor's `gateways` list, as FEP-ef61 requires.
518
+ *
519
+ * The path and fragment are preserved, with characters that are not allowed
520
+ * in HTTP(S) URLs percent-encoded the same way as
521
+ * {@link canonicalizePortableUri} does. FEP-ef61 location hints (`@gateway`
522
+ * query parameters, and the legacy `gateways` parameter) are removed, since
523
+ * compatible identifiers must not have them; other query parameters are kept
524
+ * in order.
525
+ *
526
+ * Arbitrary gateway paths are not supported.
527
+ *
528
+ * [FEP-ef61]: https://w3id.org/fep/ef61
529
+ *
530
+ * @param portableId The `ap:` or `ap+ef61:` URI to convert.
531
+ * @param gateway The gateway's HTTP(S) origin, e.g., `https://server.example`.
532
+ * @returns The compatible identifier.
533
+ * @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
534
+ * URI, if its path has `.` or `..` segments (which
535
+ * HTTP(S) URLs cannot represent), or if the gateway is
536
+ * not an HTTP(S) origin with no credentials, path, query,
537
+ * or fragment.
538
+ * @since 2.4.0
539
+ */
540
+ declare function toCompatibleEf61Id(portableId: string | URL, gateway: string | URL): URL;
541
+ /**
469
542
  * Validates a URL to prevent SSRF attacks.
470
543
  */
471
544
  declare function validatePublicUrl(url: string): Promise<void>;
@@ -473,4 +546,4 @@ declare function isValidPublicIPv4Address(address: string): boolean;
473
546
  declare function isValidPublicIPv6Address(address: string): boolean;
474
547
  declare function expandIPv6Address(address: string): string;
475
548
  //#endregion
476
- 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 };
549
+ 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, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseDigestMultibase, parseGatewayUrl, parseHashlink, parseIri, parseJsonLdId, preloadedContexts, toCompatibleEf61Id, validatePublicUrl, verifyDigestMultibase, verifyHashlink };
package/dist/mod.d.ts CHANGED
@@ -465,6 +465,79 @@ declare function isGatewayUrl(url: URL): boolean;
465
465
  */
466
466
  declare function parseGatewayUrl(url: string): URL;
467
467
  /**
468
+ * Converts an [FEP-ef61] compatible identifier into a portable ActivityPub
469
+ * URI.
470
+ *
471
+ * A compatible identifier is an HTTP(S) URL under a gateway's fixed
472
+ * `/.well-known/apgateway/` path, such as
473
+ * `https://server.example/.well-known/apgateway/did:key:z6Mk.../objects/1`.
474
+ * This function removes the gateway part and returns the corresponding
475
+ * portable URI, e.g., `ap+ef61://did:key:z6Mk.../objects/1`, in the same
476
+ * internal `URL` form that {@link parseIri} produces. The path, query, and
477
+ * fragment are preserved, so the result is a portable URI, not a comparison
478
+ * form; pass its `href` to {@link canonicalizePortableUri} or
479
+ * {@link arePortableUrisEqual} to compare it with other portable URIs.
480
+ *
481
+ * The conversion only reveals the *claimed* portable identifier. Anyone can
482
+ * publish a compatible identifier for any DID on their own server, so the
483
+ * gateway that served it is neither the object's origin nor authorized to act
484
+ * for the DID. Callers must still verify the retrieved document's Object
485
+ * Integrity Proof against the DID, as FEP-ef61 requires, and should keep the
486
+ * original URL if they need the gateway as a retrieval hint.
487
+ *
488
+ * Arbitrary gateway paths are not supported.
489
+ *
490
+ * [FEP-ef61]: https://w3id.org/fep/ef61
491
+ *
492
+ * @param input The URL to convert.
493
+ * @returns The portable ActivityPub URI, or `null` if the input is not an
494
+ * HTTP(S) URL whose path starts with `/.well-known/apgateway/did:`.
495
+ * Other gateway routes, such as the gateway discovery endpoint and
496
+ * hashlink media URLs, also yield `null`.
497
+ * @throws {TypeError} If the input looks like a compatible identifier but is
498
+ * malformed, e.g., it has an invalid DID, no object path,
499
+ * invalid percent-encoding, credentials, or location
500
+ * hints (`@gateway` query parameters, or the legacy
501
+ * `gateways` parameter), which FEP-ef61 forbids in
502
+ * compatible identifiers.
503
+ * @since 2.4.0
504
+ */
505
+ declare function fromCompatibleEf61Id(input: string | URL): URL | null;
506
+ /**
507
+ * Converts a portable ActivityPub URI into an [FEP-ef61] compatible
508
+ * identifier, which is an HTTP(S) URL under the gateway's fixed
509
+ * `/.well-known/apgateway/` path.
510
+ *
511
+ * For example, `ap+ef61://did:key:z6Mk.../objects/1` and
512
+ * `https://server.example` yield
513
+ * `https://server.example/.well-known/apgateway/did:key:z6Mk.../objects/1`.
514
+ * Both `ap:` and `ap+ef61:` URIs with decoded or percent-encoded DID
515
+ * authorities are accepted. Publishers should use the first gateway in the
516
+ * actor's `gateways` list, as FEP-ef61 requires.
517
+ *
518
+ * The path and fragment are preserved, with characters that are not allowed
519
+ * in HTTP(S) URLs percent-encoded the same way as
520
+ * {@link canonicalizePortableUri} does. FEP-ef61 location hints (`@gateway`
521
+ * query parameters, and the legacy `gateways` parameter) are removed, since
522
+ * compatible identifiers must not have them; other query parameters are kept
523
+ * in order.
524
+ *
525
+ * Arbitrary gateway paths are not supported.
526
+ *
527
+ * [FEP-ef61]: https://w3id.org/fep/ef61
528
+ *
529
+ * @param portableId The `ap:` or `ap+ef61:` URI to convert.
530
+ * @param gateway The gateway's HTTP(S) origin, e.g., `https://server.example`.
531
+ * @returns The compatible identifier.
532
+ * @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
533
+ * URI, if its path has `.` or `..` segments (which
534
+ * HTTP(S) URLs cannot represent), or if the gateway is
535
+ * not an HTTP(S) origin with no credentials, path, query,
536
+ * or fragment.
537
+ * @since 2.4.0
538
+ */
539
+ declare function toCompatibleEf61Id(portableId: string | URL, gateway: string | URL): URL;
540
+ /**
468
541
  * Validates a URL to prevent SSRF attacks.
469
542
  */
470
543
  declare function validatePublicUrl(url: string): Promise<void>;
@@ -472,4 +545,4 @@ declare function isValidPublicIPv4Address(address: string): boolean;
472
545
  declare function isValidPublicIPv6Address(address: string): boolean;
473
546
  declare function expandIPv6Address(address: string): string;
474
547
  //#endregion
475
- 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 };
548
+ 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, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseDigestMultibase, parseGatewayUrl, parseHashlink, parseIri, parseJsonLdId, preloadedContexts, toCompatibleEf61Id, validatePublicUrl, verifyDigestMultibase, verifyHashlink };
package/dist/mod.js CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { t as preloadedContexts } from "./contexts-DoZUIW7y.js";
3
- import { a as formatIri, c as haveSameIriOrigin, d as isValidPublicIPv6Address, f as parseGatewayUrl, h as validatePublicUrl, i as expandIPv6Address, l as isGatewayUrl, m as parseJsonLdId, n as arePortableUrisEqual, o as getFe34Origin, p as parseIri, r as canonicalizePortableUri, s as haveSameFe34Origin, t as UrlError, u as isValidPublicIPv4Address } from "./url-BHAShw9J.js";
3
+ import { _ as validatePublicUrl, a as formatIri, c as haveSameFe34Origin, d as isValidPublicIPv4Address, f as isValidPublicIPv6Address, g as toCompatibleEf61Id, h as parseJsonLdId, i as expandIPv6Address, l as haveSameIriOrigin, m as parseIri, n as arePortableUrisEqual, o as fromCompatibleEf61Id, p as parseGatewayUrl, r as canonicalizePortableUri, s as getFe34Origin, t as UrlError, u as isGatewayUrl } from "./url-CEhi4hb4.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
6
6
  import process from "node:process";
@@ -12,7 +12,7 @@ import { PublicKeyInfo } from "pkijs";
12
12
  import baseX from "@multiformats/base-x";
13
13
  //#region deno.json
14
14
  var name = "@fedify/vocab-runtime";
15
- var version = "2.4.0-dev.2027+fcf88bfc";
15
+ var version = "2.4.0-dev.2035+d1f8f8e2";
16
16
  //#endregion
17
17
  //#region src/request.ts
18
18
  /**
@@ -1358,4 +1358,4 @@ LanguageString.prototype[Symbol.for("nodejs.util.inspect.custom")] = function(_d
1358
1358
  return `<${this.locale.baseName}> ${inspect(this.toString(), options)}`;
1359
1359
  };
1360
1360
  //#endregion
1361
- 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 };
1361
+ export { FetchError, LanguageString, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, computeDigestMultibase, createActivityPubRequest, createHashlink, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isGatewayUrl, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseDigestMultibase, parseGatewayUrl, parseHashlink, parseIri, parseJsonLdId, preloadedContexts, toCompatibleEf61Id, validatePublicUrl, verifyDigestMultibase, verifyHashlink };
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "./request-CeEwiwiU.mjs";
1
+ import { t as FetchError } from "./request-eP_YLVjb.mjs";
2
2
  import { getLogger } from "@logtape/logtape";
3
3
  //#region src/body.ts
4
4
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,4 +1,4 @@
1
- const require_request = require("./request-DV2_yz3V.cjs");
1
+ const require_request = require("./request-BbczASfn.cjs");
2
2
  let _logtape_logtape = require("@logtape/logtape");
3
3
  //#region src/body.ts
4
4
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,4 +1,4 @@
1
- const require_body = require("./body-CjqMU6be.cjs");
1
+ const require_body = require("./body-DRpkDnEg.cjs");
2
2
  let node_assert_strict = require("node:assert/strict");
3
3
  let node_test = require("node:test");
4
4
  let node_zlib = require("node:zlib");
@@ -1,4 +1,4 @@
1
- import { r as readBoundedText, t as BodyTooLargeError } from "./body-C8W6PG-f.mjs";
1
+ import { r as readBoundedText, t as BodyTooLargeError } from "./body-BEIDQFV6.mjs";
2
2
  import { deepStrictEqual, ok, rejects } from "node:assert/strict";
3
3
  import { test } from "node:test";
4
4
  import { gunzipSync, gzipSync } from "node:zlib";
@@ -1,5 +1,5 @@
1
- require("./url-CPfMatUL.cjs");
2
- require("./docloader-DDwe-rFE.cjs");
1
+ require("./url-BqlldzT8.cjs");
2
+ require("./docloader-M8t8o-GD.cjs");
3
3
  require("./key-8Qg2SbZi.cjs");
4
4
  require("./multibase-B5Mea7Ip.cjs");
5
5
  require("./digest-3FeH2Y-Q.cjs");
@@ -1,5 +1,5 @@
1
- import "./url-Basm1L_c.mjs";
2
- import "./docloader-BcthkJvx.mjs";
1
+ import "./url-DgJM9WJn.mjs";
2
+ import "./docloader-DHux1ztB.mjs";
3
3
  import "./key-C7MNhlkO.mjs";
4
4
  import "./multibase-BPnF_L4e.mjs";
5
5
  import "./digest-COC7xDiQ.mjs";
@@ -1,8 +1,8 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-CeEwiwiU.mjs";
2
- import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-C8W6PG-f.mjs";
1
+ import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-eP_YLVjb.mjs";
2
+ import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-BEIDQFV6.mjs";
3
3
  import { t as preloadedContexts } from "./contexts-BBX_qhBL.mjs";
4
4
  import { t as HttpHeaderLink } from "./link-Cevmc87v.mjs";
5
- import { g as validatePublicUrl, t as UrlError } from "./url-Basm1L_c.mjs";
5
+ import { t as UrlError, v as validatePublicUrl } from "./url-DgJM9WJn.mjs";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  //#region src/docloader.ts
@@ -1,8 +1,8 @@
1
- const require_request = require("./request-DV2_yz3V.cjs");
2
- const require_body = require("./body-CjqMU6be.cjs");
1
+ const require_request = require("./request-BbczASfn.cjs");
2
+ const require_body = require("./body-DRpkDnEg.cjs");
3
3
  const require_contexts = require("./contexts-Ch3v2Cgu.cjs");
4
4
  const require_link = require("./link-DlKm8bEr.cjs");
5
- const require_url = require("./url-CPfMatUL.cjs");
5
+ const require_url = require("./url-BqlldzT8.cjs");
6
6
  let _logtape_logtape = require("@logtape/logtape");
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
8
8
  //#region src/docloader.ts
@@ -1,8 +1,8 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
2
- const require_request = require("./request-DV2_yz3V.cjs");
2
+ const require_request = require("./request-BbczASfn.cjs");
3
3
  const require_contexts = require("./contexts-Ch3v2Cgu.cjs");
4
- const require_url = require("./url-CPfMatUL.cjs");
5
- const require_docloader = require("./docloader-DDwe-rFE.cjs");
4
+ const require_url = require("./url-BqlldzT8.cjs");
5
+ const require_docloader = require("./docloader-M8t8o-GD.cjs");
6
6
  let node_test = require("node:test");
7
7
  let node_zlib = require("node:zlib");
8
8
  let node_assert = require("node:assert");
@@ -1,7 +1,7 @@
1
- import { t as FetchError } from "./request-CeEwiwiU.mjs";
1
+ import { t as FetchError } from "./request-eP_YLVjb.mjs";
2
2
  import { n as cid_v1_default, t as preloadedContexts } from "./contexts-BBX_qhBL.mjs";
3
- import { t as UrlError } from "./url-Basm1L_c.mjs";
4
- import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-BcthkJvx.mjs";
3
+ import { t as UrlError } from "./url-DgJM9WJn.mjs";
4
+ import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-DHux1ztB.mjs";
5
5
  import { test } from "node:test";
6
6
  import { gzipSync } from "node:zlib";
7
7
  import { deepStrictEqual, ok, rejects } from "node:assert";
@@ -1,5 +1,5 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
2
- const require_url = require("./url-CPfMatUL.cjs");
2
+ const require_url = require("./url-BqlldzT8.cjs");
3
3
  let node_test = require("node:test");
4
4
  let node_assert = require("node:assert");
5
5
  let jsonld_dist_jsonld_esm_js = require("jsonld/dist/jsonld.esm.js");
@@ -1,4 +1,4 @@
1
- import { a as formatIri, c as haveSameIriOrigin, p as parseIri, s as haveSameFe34Origin } from "./url-Basm1L_c.mjs";
1
+ import { a as formatIri, c as haveSameFe34Origin, l as haveSameIriOrigin, m as parseIri } from "./url-DgJM9WJn.mjs";
2
2
  import { test } from "node:test";
3
3
  import { deepStrictEqual, ok, strictEqual } from "node:assert";
4
4
  import jsonld from "jsonld/dist/jsonld.esm.js";
@@ -3,7 +3,7 @@ let node_process = require("node:process");
3
3
  node_process = require_rolldown_runtime.__toESM(node_process, 1);
4
4
  //#region deno.json
5
5
  var name = "@fedify/vocab-runtime";
6
- var version = "2.4.0-dev.2027+fcf88bfc";
6
+ var version = "2.4.0-dev.2035+d1f8f8e2";
7
7
  //#endregion
8
8
  //#region src/request.ts
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  import process from "node:process";
2
2
  //#region deno.json
3
3
  var name = "@fedify/vocab-runtime";
4
- var version = "2.4.0-dev.2027+fcf88bfc";
4
+ var version = "2.4.0-dev.2035+d1f8f8e2";
5
5
  //#endregion
6
6
  //#region src/request.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
2
- const require_request = require("./request-DV2_yz3V.cjs");
2
+ const require_request = require("./request-BbczASfn.cjs");
3
3
  let node_test = require("node:test");
4
4
  let node_process = require("node:process");
5
5
  node_process = require_rolldown_runtime.__toESM(node_process, 1);
@@ -1,4 +1,4 @@
1
- import { o as version, r as getUserAgent } from "./request-CeEwiwiU.mjs";
1
+ import { o as version, r as getUserAgent } from "./request-eP_YLVjb.mjs";
2
2
  import { test } from "node:test";
3
3
  import process from "node:process";
4
4
  import { deepStrictEqual } from "node:assert";
@@ -1,4 +1,3 @@
1
-
2
1
  let node_dns_promises = require("node:dns/promises");
3
2
  let node_net = require("node:net");
4
3
  //#region src/url.ts
@@ -224,6 +223,152 @@ function parseGatewayUrl(url) {
224
223
  if (!isGatewayUrl(parsed)) throw new TypeError("FEP-ef61 gateways must be HTTP(S) base URIs with no credentials, path, query, or fragment.");
225
224
  return parsed;
226
225
  }
226
+ const COMPATIBLE_ID_PATH_PREFIX = "/.well-known/apgateway/";
227
+ const COMPATIBLE_ID_DID_PATTERN = /^did(?::|%3A)/i;
228
+ const LOCATION_HINT_PARAMETERS = /* @__PURE__ */ new Set(["@gateway", "gateways"]);
229
+ /**
230
+ * Converts an [FEP-ef61] compatible identifier into a portable ActivityPub
231
+ * URI.
232
+ *
233
+ * A compatible identifier is an HTTP(S) URL under a gateway's fixed
234
+ * `/.well-known/apgateway/` path, such as
235
+ * `https://server.example/.well-known/apgateway/did:key:z6Mk.../objects/1`.
236
+ * This function removes the gateway part and returns the corresponding
237
+ * portable URI, e.g., `ap+ef61://did:key:z6Mk.../objects/1`, in the same
238
+ * internal `URL` form that {@link parseIri} produces. The path, query, and
239
+ * fragment are preserved, so the result is a portable URI, not a comparison
240
+ * form; pass its `href` to {@link canonicalizePortableUri} or
241
+ * {@link arePortableUrisEqual} to compare it with other portable URIs.
242
+ *
243
+ * The conversion only reveals the *claimed* portable identifier. Anyone can
244
+ * publish a compatible identifier for any DID on their own server, so the
245
+ * gateway that served it is neither the object's origin nor authorized to act
246
+ * for the DID. Callers must still verify the retrieved document's Object
247
+ * Integrity Proof against the DID, as FEP-ef61 requires, and should keep the
248
+ * original URL if they need the gateway as a retrieval hint.
249
+ *
250
+ * Arbitrary gateway paths are not supported.
251
+ *
252
+ * [FEP-ef61]: https://w3id.org/fep/ef61
253
+ *
254
+ * @param input The URL to convert.
255
+ * @returns The portable ActivityPub URI, or `null` if the input is not an
256
+ * HTTP(S) URL whose path starts with `/.well-known/apgateway/did:`.
257
+ * Other gateway routes, such as the gateway discovery endpoint and
258
+ * hashlink media URLs, also yield `null`.
259
+ * @throws {TypeError} If the input looks like a compatible identifier but is
260
+ * malformed, e.g., it has an invalid DID, no object path,
261
+ * invalid percent-encoding, credentials, or location
262
+ * hints (`@gateway` query parameters, or the legacy
263
+ * `gateways` parameter), which FEP-ef61 forbids in
264
+ * compatible identifiers.
265
+ * @since 2.4.0
266
+ */
267
+ function fromCompatibleEf61Id(input) {
268
+ return convertCompatibleEf61Id(input)?.url ?? null;
269
+ }
270
+ function convertCompatibleEf61Id(input) {
271
+ let url;
272
+ if (input instanceof URL) url = input;
273
+ else if (typeof input === "string" && URL.canParse(input)) url = new URL(input);
274
+ else return null;
275
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
276
+ if (!url.pathname.startsWith(COMPATIBLE_ID_PATH_PREFIX)) return null;
277
+ const tail = url.pathname.slice(23);
278
+ if (!COMPATIBLE_ID_DID_PATTERN.test(tail)) return null;
279
+ if (url.username !== "" || url.password !== "") throw new TypeError("Invalid FEP-ef61 compatible identifier: credentials are not allowed.");
280
+ const iri = "ap+ef61://" + url.href.slice(url.origin.length + 23);
281
+ try {
282
+ const parsed = parsePortableIri(iri);
283
+ if (parsed == null) throw new TypeError("Not a portable IRI.");
284
+ canonicalizePortableUri(iri);
285
+ if ((url.search === "" ? [] : normalizePortableComponent(url.search.slice(1)).split("&")).some(isLocationHint)) throw new TypeError("Location hints are not allowed.");
286
+ return {
287
+ url: parsed,
288
+ iri
289
+ };
290
+ } catch (error) {
291
+ if (error instanceof TypeError) throw new TypeError("Invalid FEP-ef61 compatible identifier.", { cause: error });
292
+ throw error;
293
+ }
294
+ }
295
+ /**
296
+ * Converts a portable ActivityPub URI into an [FEP-ef61] compatible
297
+ * identifier, which is an HTTP(S) URL under the gateway's fixed
298
+ * `/.well-known/apgateway/` path.
299
+ *
300
+ * For example, `ap+ef61://did:key:z6Mk.../objects/1` and
301
+ * `https://server.example` yield
302
+ * `https://server.example/.well-known/apgateway/did:key:z6Mk.../objects/1`.
303
+ * Both `ap:` and `ap+ef61:` URIs with decoded or percent-encoded DID
304
+ * authorities are accepted. Publishers should use the first gateway in the
305
+ * actor's `gateways` list, as FEP-ef61 requires.
306
+ *
307
+ * The path and fragment are preserved, with characters that are not allowed
308
+ * in HTTP(S) URLs percent-encoded the same way as
309
+ * {@link canonicalizePortableUri} does. FEP-ef61 location hints (`@gateway`
310
+ * query parameters, and the legacy `gateways` parameter) are removed, since
311
+ * compatible identifiers must not have them; other query parameters are kept
312
+ * in order.
313
+ *
314
+ * Arbitrary gateway paths are not supported.
315
+ *
316
+ * [FEP-ef61]: https://w3id.org/fep/ef61
317
+ *
318
+ * @param portableId The `ap:` or `ap+ef61:` URI to convert.
319
+ * @param gateway The gateway's HTTP(S) origin, e.g., `https://server.example`.
320
+ * @returns The compatible identifier.
321
+ * @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
322
+ * URI, if its path has `.` or `..` segments (which
323
+ * HTTP(S) URLs cannot represent), or if the gateway is
324
+ * not an HTTP(S) origin with no credentials, path, query,
325
+ * or fragment.
326
+ * @since 2.4.0
327
+ */
328
+ function toCompatibleEf61Id(portableId, gateway) {
329
+ const gatewayUrl = parseCompatibleEf61Gateway(gateway);
330
+ const raw = getRawPortableIri(portableId);
331
+ const match = raw.match(PORTABLE_IRI_PATTERN);
332
+ const parsed = parsePortableIri(raw);
333
+ if (match == null || parsed == null) throw new TypeError("Invalid portable ActivityPub IRI.");
334
+ let did = decodePortableAuthority(parsed.host);
335
+ if (/%25/i.test(did)) did = did.replace(/%/g, "%25");
336
+ const path = normalizePortableComponent(match[3]);
337
+ if (path.split("/").some((segment) => segment === "." || segment === "..")) throw new TypeError("FEP-ef61 compatible identifiers cannot represent portable IRI paths with dot segments.");
338
+ const query = match[4] == null ? "" : stripLocationHints(normalizePortableComponent(match[4].slice(1)));
339
+ const fragment = match[5] == null ? "" : normalizePortableComponent(match[5]);
340
+ const result = new URL(gatewayUrl.origin + COMPATIBLE_ID_PATH_PREFIX + did + path + query + fragment);
341
+ const converted = convertCompatibleEf61Id(result);
342
+ if (converted == null || canonicalizePortableUri(converted.iri) !== canonicalizePortableUri(raw)) throw new TypeError("The portable ActivityPub IRI cannot be represented as an FEP-ef61 compatible identifier.");
343
+ return result;
344
+ }
345
+ function parseCompatibleEf61Gateway(gateway) {
346
+ const url = gateway instanceof URL ? gateway : typeof gateway === "string" && URL.canParse(gateway) ? new URL(gateway) : null;
347
+ if (url == null || url.protocol !== "http:" && url.protocol !== "https:" || url.href !== `${url.origin}/`) throw new TypeError("FEP-ef61 gateways for compatible identifiers must be HTTP(S) origins with no credentials, path, query, or fragment.");
348
+ return url;
349
+ }
350
+ function getRawPortableIri(portableId) {
351
+ if (portableId instanceof URL) {
352
+ if (portableId.protocol !== "ap:" && portableId.protocol !== "ap+ef61:") throw new TypeError("Invalid portable ActivityPub IRI.");
353
+ if (portableId.username !== "" || portableId.password !== "" || portableId.port !== "") throw new TypeError("Invalid portable ActivityPub IRI authority.");
354
+ return portableId.href;
355
+ }
356
+ if (typeof portableId !== "string") throw new TypeError("Invalid portable ActivityPub IRI.");
357
+ return portableId;
358
+ }
359
+ function stripLocationHints(query) {
360
+ const pairs = query.split("&").filter((pair) => !isLocationHint(pair));
361
+ return pairs.length < 1 ? "" : `?${pairs.join("&")}`;
362
+ }
363
+ function isLocationHint(pair) {
364
+ const name = pair.split("=", 1)[0].replace(/\+/g, " ");
365
+ try {
366
+ return LOCATION_HINT_PARAMETERS.has(decodeURIComponent(name));
367
+ } catch (error) {
368
+ if (error instanceof URIError) return false;
369
+ throw error;
370
+ }
371
+ }
227
372
  /**
228
373
  * Validates a URL to prevent SSRF attacks.
229
374
  */
@@ -447,6 +592,12 @@ Object.defineProperty(exports, "formatIri", {
447
592
  return formatIri;
448
593
  }
449
594
  });
595
+ Object.defineProperty(exports, "fromCompatibleEf61Id", {
596
+ enumerable: true,
597
+ get: function() {
598
+ return fromCompatibleEf61Id;
599
+ }
600
+ });
450
601
  Object.defineProperty(exports, "getFe34Origin", {
451
602
  enumerable: true,
452
603
  get: function() {
@@ -501,6 +652,18 @@ Object.defineProperty(exports, "parseJsonLdId", {
501
652
  return parseJsonLdId;
502
653
  }
503
654
  });
655
+ Object.defineProperty(exports, "toCompatibleEf61Id", {
656
+ enumerable: true,
657
+ get: function() {
658
+ return toCompatibleEf61Id;
659
+ }
660
+ });
661
+ Object.defineProperty(exports, "validateLookupAddresses", {
662
+ enumerable: true,
663
+ get: function() {
664
+ return validateLookupAddresses;
665
+ }
666
+ });
504
667
  Object.defineProperty(exports, "validatePublicUrl", {
505
668
  enumerable: true,
506
669
  get: function() {