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

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 (41) hide show
  1. package/deno.json +2 -1
  2. package/dist/internal/portable-dereference.cjs +315 -0
  3. package/dist/internal/portable-dereference.d.cts +87 -0
  4. package/dist/internal/portable-dereference.d.ts +87 -0
  5. package/dist/internal/portable-dereference.js +311 -0
  6. package/dist/mod.cjs +8 -2
  7. package/dist/mod.d.cts +2 -1
  8. package/dist/mod.d.ts +2 -1
  9. package/dist/mod.js +8 -2
  10. package/dist/portable-CduElToy.d.ts +52 -0
  11. package/dist/portable-DxF2Ut-Z.d.cts +52 -0
  12. package/dist/tests/{body-DRpkDnEg.cjs → body-B-qUpCl3.cjs} +1 -1
  13. package/dist/tests/{body-BEIDQFV6.mjs → body-hdMfBU1p.mjs} +1 -1
  14. package/dist/tests/body.test.cjs +1 -1
  15. package/dist/tests/body.test.mjs +1 -1
  16. package/dist/tests/decimal.test.cjs +1 -1
  17. package/dist/tests/decimal.test.mjs +1 -1
  18. package/dist/tests/{docloader-M8t8o-GD.cjs → docloader-BLHl6D4V.cjs} +2 -2
  19. package/dist/tests/{docloader-DHux1ztB.mjs → docloader-C_fQRm09.mjs} +2 -2
  20. package/dist/tests/docloader.test.cjs +2 -2
  21. package/dist/tests/docloader.test.mjs +2 -2
  22. package/dist/tests/internal/portable-dereference.test.cjs +123 -0
  23. package/dist/tests/internal/portable-dereference.test.d.cts +1 -0
  24. package/dist/tests/internal/portable-dereference.test.d.mts +1 -0
  25. package/dist/tests/internal/portable-dereference.test.mjs +124 -0
  26. package/dist/tests/jsonld-CmDhHNTx.cjs +12 -0
  27. package/dist/tests/jsonld-DweIJ07b.mjs +5 -0
  28. package/dist/tests/jsonld-cache.test.cjs +17 -22
  29. package/dist/tests/jsonld-cache.test.mjs +1 -4
  30. package/dist/tests/{request-eP_YLVjb.mjs → request-Bbg1-1C3.mjs} +8 -2
  31. package/dist/tests/{request-BbczASfn.cjs → request-CcifKcqU.cjs} +8 -2
  32. package/dist/tests/request.test.cjs +4 -1
  33. package/dist/tests/request.test.mjs +4 -1
  34. package/package.json +11 -1
  35. package/src/internal/portable-dereference.test.ts +74 -0
  36. package/src/internal/portable-dereference.ts +426 -0
  37. package/src/mod.ts +4 -0
  38. package/src/portable.ts +52 -0
  39. package/src/request.test.ts +10 -1
  40. package/src/request.ts +9 -1
  41. package/tsdown.config.ts +1 -0
package/deno.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.4.0-dev.2035+d1f8f8e2",
3
+ "version": "2.4.0-dev.2054+1756e190",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts",
7
7
  "./internal/jsonld-cache": "./src/internal/jsonld-cache.ts",
8
+ "./internal/portable-dereference": "./src/internal/portable-dereference.ts",
8
9
  "./internal/signed-representation": "./src/internal/signed-representation.ts",
9
10
  "./jsonld": "./src/jsonld.ts",
10
11
  "./temporal": "./src/temporal.ts"
@@ -0,0 +1,315 @@
1
+
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_contexts = require("../contexts-2hEbs3Qk.cjs");
4
+ const require_url = require("../url-Cke4irYD.cjs");
5
+ const require_jsonld = require("../jsonld.cjs");
6
+ let _logtape_logtape = require("@logtape/logtape");
7
+ let _opentelemetry_api = require("@opentelemetry/api");
8
+ //#region src/internal/portable-dereference.ts
9
+ const logger = (0, _logtape_logtape.getLogger)([
10
+ "fedify",
11
+ "vocab",
12
+ "gateway"
13
+ ]);
14
+ /**
15
+ * The maximum number of `@gateway` location hints to try for one reference.
16
+ * Hints come from possibly untrusted documents, so they are bounded to keep
17
+ * a single accessor call from fanning out to many servers.
18
+ */
19
+ const MAX_GATEWAY_HINTS = 5;
20
+ const LOCATION_HINT_PARAMETER = "@gateway";
21
+ const BASELINE_CONTEXT_URLS = /* @__PURE__ */ new Set([
22
+ "https://w3id.org/identity/v1",
23
+ "https://www.w3.org/ns/activitystreams",
24
+ "https://w3id.org/security/v1",
25
+ "https://w3id.org/security/data-integrity/v1"
26
+ ]);
27
+ /**
28
+ * Checks whether a URL is an FEP-ef61 portable ActivityPub IRI.
29
+ *
30
+ * @internal Technically exported for generated vocabulary classes, but not
31
+ * part of the public API contract. This is not considered public API for
32
+ * Semantic Versioning decisions.
33
+ */
34
+ function isPortableIri(url) {
35
+ return url.protocol === "ap+ef61:" || url.protocol === "ap:";
36
+ }
37
+ /**
38
+ * Picks the ordered list of FEP-ef61 gateways to fetch a portable IRI from.
39
+ *
40
+ * If `gateways` is given, it is used as is (even when empty), and `@gateway`
41
+ * location hints in the IRI are ignored. Otherwise, up to
42
+ * {@link MAX_GATEWAY_HINTS} valid `@gateway` hints are used. Duplicate
43
+ * gateways are dropped in both cases.
44
+ *
45
+ * @throws {TypeError} If an explicit gateway is not an HTTP(S) origin.
46
+ * @internal
47
+ */
48
+ function getPortableGatewayCandidates(url, gateways) {
49
+ const candidates = [];
50
+ const seen = /* @__PURE__ */ new Set();
51
+ const add = (gateway) => {
52
+ if (seen.has(gateway.href)) return;
53
+ seen.add(gateway.href);
54
+ candidates.push(gateway);
55
+ };
56
+ if (gateways != null) {
57
+ for (const gateway of gateways) {
58
+ const parsed = parseGatewayOrigin(gateway);
59
+ if (parsed == null) throw new TypeError("FEP-ef61 gateways must be HTTP(S) origins with no credentials, path, query, or fragment: " + String(gateway));
60
+ add(parsed);
61
+ }
62
+ return candidates;
63
+ }
64
+ for (const hint of new URLSearchParams(url.search).getAll(LOCATION_HINT_PARAMETER)) {
65
+ if (candidates.length >= MAX_GATEWAY_HINTS) break;
66
+ const parsed = parseGatewayOrigin(hint);
67
+ if (parsed == null) {
68
+ logger.debug("Ignoring an invalid FEP-ef61 gateway hint {hint} in {url}.", {
69
+ hint,
70
+ url: require_url.formatIri(url)
71
+ });
72
+ continue;
73
+ }
74
+ add(parsed);
75
+ }
76
+ return candidates;
77
+ }
78
+ function parseGatewayOrigin(gateway) {
79
+ let url;
80
+ if (gateway instanceof URL) url = new URL(gateway.href);
81
+ else if (typeof gateway === "string" && URL.canParse(gateway)) url = new URL(gateway);
82
+ else return null;
83
+ if (url.protocol !== "http:" && url.protocol !== "https:" || url.href !== `${url.origin}/`) return null;
84
+ return url;
85
+ }
86
+ /**
87
+ * Creates a context loader that returns the same context documents for the
88
+ * whole dereference operation, so that the identity check, the proof
89
+ * verifier, and the parser interpret the fetched document identically even
90
+ * if the underlying loader is nondeterministic. Failed loads are not
91
+ * remembered, so a transient failure does not affect the next gateway.
92
+ *
93
+ * The parsed object keeps the loader for its own later dereferences, so
94
+ * `release()` turns it into a plain pass-through to the underlying loader
95
+ * once the operation is over.
96
+ */
97
+ function createSnapshotContextLoader(contextLoader) {
98
+ const cache = /* @__PURE__ */ new Map();
99
+ let released = false;
100
+ const release = () => {
101
+ released = true;
102
+ cache.clear();
103
+ };
104
+ const loader = async (url, options) => {
105
+ if (released) return await contextLoader(url, options);
106
+ const key = URL.canParse(url) ? new URL(url).href : url;
107
+ if (BASELINE_CONTEXT_URLS.has(key)) return {
108
+ contextUrl: null,
109
+ document: structuredClone(require_contexts.preloadedContexts[key]),
110
+ documentUrl: key
111
+ };
112
+ let promise = cache.get(key);
113
+ if (promise == null) {
114
+ const loading = contextLoader(url, options).then((document) => structuredClone(document));
115
+ promise = loading;
116
+ cache.set(key, loading);
117
+ loading.catch(() => {
118
+ if (cache.get(key) === loading) cache.delete(key);
119
+ });
120
+ }
121
+ return structuredClone(await promise);
122
+ };
123
+ return {
124
+ loader,
125
+ release
126
+ };
127
+ }
128
+ /**
129
+ * The error thrown by {@link dereferencePortableIri} under
130
+ * `crossOrigin: "throw"` when gateways returned objects but none of them
131
+ * satisfied the identity and proof checks.
132
+ *
133
+ * @internal Not part of the public API contract.
134
+ */
135
+ var PortableObjectRejectedError = class extends Error {
136
+ constructor(message) {
137
+ super(message);
138
+ this.name = "PortableObjectRejectedError";
139
+ }
140
+ };
141
+ var PortableObjectRejection = class {
142
+ message;
143
+ values;
144
+ constructor(message, values = {}) {
145
+ this.message = message;
146
+ this.values = values;
147
+ }
148
+ };
149
+ /**
150
+ * Dereferences an FEP-ef61 portable IRI through its gateways.
151
+ *
152
+ * Gateways are tried one by one until one of them returns a single-node
153
+ * document whose `@id`, if any, canonically matches the requested IRI and
154
+ * which passes `verifyPortableObject`. When there is no gateway to try, the document
155
+ * loader is asked for the portable IRI itself, and its result is validated
156
+ * the same way.
157
+ *
158
+ * @returns The parsed object, or `null` if no valid object was retrieved and
159
+ * `suppressError` is set or the failure was a rejected object
160
+ * (unless `crossOrigin` is `"throw"`).
161
+ * @throws {TypeError} If `gateways` has an invalid entry (always), if no
162
+ * verifier is given, or if the IRI cannot be turned into
163
+ * a gateway URL (unless `suppressError` is set).
164
+ * @internal Technically exported for generated vocabulary classes, but not
165
+ * part of the public API contract. This is not considered public API for
166
+ * Semantic Versioning decisions.
167
+ */
168
+ async function dereferencePortableIri(url, options) {
169
+ url = require_url.parseIri(url);
170
+ const lookupUrl = require_url.formatIri(url);
171
+ const { span } = options;
172
+ const gateways = getPortableGatewayCandidates(url, options.gateways);
173
+ const fail = (error) => {
174
+ span?.setStatus({
175
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
176
+ message: String(error)
177
+ });
178
+ if (options.suppressError) {
179
+ logger.error("Failed to dereference {url}: {error}", {
180
+ url: lookupUrl,
181
+ error
182
+ });
183
+ return null;
184
+ }
185
+ throw error;
186
+ };
187
+ const verify = options.verifyPortableObject;
188
+ if (verify == null) return fail(/* @__PURE__ */ new TypeError("Dereferencing the portable object " + lookupUrl + " requires the verifyPortableObject option, e.g., verifyPortableObjectProof() from @fedify/fedify."));
189
+ const requestUrls = [];
190
+ let expectedId;
191
+ try {
192
+ expectedId = require_url.canonicalizePortableUri(lookupUrl);
193
+ for (const gateway of gateways) requestUrls.push({
194
+ url: require_url.toCompatibleEf61Id(url, gateway).href,
195
+ gateway
196
+ });
197
+ } catch (error) {
198
+ return fail(error);
199
+ }
200
+ if (requestUrls.length < 1) requestUrls.push({
201
+ url: lookupUrl,
202
+ gateway: null
203
+ });
204
+ const snapshot = createSnapshotContextLoader(options.contextLoader);
205
+ const contextLoader = snapshot.loader;
206
+ const attempts = [];
207
+ const { signal } = options;
208
+ try {
209
+ for (const { url: requestUrl, gateway } of requestUrls) {
210
+ signal?.throwIfAborted();
211
+ let remoteDocument;
212
+ try {
213
+ remoteDocument = await options.documentLoader(requestUrl, signal == null ? void 0 : { signal });
214
+ } catch (error) {
215
+ signal?.throwIfAborted();
216
+ logger.debug("Failed to fetch {url} from {requestUrl}: {error}", {
217
+ url: lookupUrl,
218
+ requestUrl,
219
+ error
220
+ });
221
+ attempts.push({
222
+ type: "error",
223
+ error
224
+ });
225
+ continue;
226
+ }
227
+ const { document } = remoteDocument;
228
+ try {
229
+ await checkPortableObjectId(document, expectedId, contextLoader);
230
+ let result;
231
+ try {
232
+ result = await verify(document, {
233
+ documentLoader: options.documentLoader,
234
+ contextLoader,
235
+ tracerProvider: options.tracerProvider
236
+ });
237
+ } catch (error) {
238
+ throw new PortableObjectRejection("the proof verifier failed: {error}", { error });
239
+ }
240
+ if (!result.verified) throw new PortableObjectRejection("it does not satisfy the FEP-ef61 proof policy: {result}", { result });
241
+ const object = await options.parse(document, {
242
+ contextLoader,
243
+ baseUrl: url
244
+ });
245
+ signal?.throwIfAborted();
246
+ if (gateway != null) span?.setAttribute("activitypub.gateway", gateway.href);
247
+ return object;
248
+ } catch (error) {
249
+ signal?.throwIfAborted();
250
+ if (error instanceof PortableObjectRejection) {
251
+ logger.warn("Rejected the portable object {url} served from {requestUrl}, because " + error.message, {
252
+ ...error.values,
253
+ url: lookupUrl,
254
+ requestUrl
255
+ });
256
+ attempts.push({
257
+ type: "rejected",
258
+ source: requestUrl
259
+ });
260
+ continue;
261
+ }
262
+ logger.debug("Failed to parse {url} from {requestUrl}: {error}", {
263
+ url: lookupUrl,
264
+ requestUrl,
265
+ error
266
+ });
267
+ attempts.push({
268
+ type: "error",
269
+ error
270
+ });
271
+ }
272
+ }
273
+ } finally {
274
+ snapshot.release();
275
+ }
276
+ const rejected = attempts.filter((a) => a.type === "rejected");
277
+ if (rejected.length > 0) {
278
+ const message = "No gateway returned a valid portable object for " + lookupUrl + "; refusing to return the object. Objects retrieved from: " + rejected.map((a) => a.source).join(", ") + ".";
279
+ if (options.suppressError || options.crossOrigin !== "throw") {
280
+ span?.setStatus({
281
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
282
+ message
283
+ });
284
+ logger.warn(message);
285
+ return null;
286
+ }
287
+ throw new PortableObjectRejectedError(message);
288
+ }
289
+ const errors = attempts.flatMap((a) => a.type === "error" ? [a.error] : []);
290
+ return fail(errors.length === 1 ? errors[0] : new AggregateError(errors, "Failed to dereference " + lookupUrl + " through any of its gateways: " + requestUrls.map((r) => r.url).join(", ")));
291
+ }
292
+ async function checkPortableObjectId(document, expectedId, contextLoader) {
293
+ if (document == null || typeof document !== "object" || Array.isArray(document)) throw new PortableObjectRejection("it is not a single JSON object");
294
+ const expanded = await require_jsonld.expand(document, {
295
+ documentLoader: contextLoader,
296
+ keepFreeFloatingNodes: true
297
+ });
298
+ if (expanded.length !== 1) throw new PortableObjectRejection("it does not have exactly one top-level node");
299
+ const id = expanded[0]["@id"];
300
+ if (id == null) return;
301
+ if (typeof id !== "string") throw new PortableObjectRejection("it has an invalid @id");
302
+ let actualId;
303
+ try {
304
+ actualId = require_url.canonicalizePortableUri(id);
305
+ } catch (error) {
306
+ if (!(error instanceof TypeError)) throw error;
307
+ actualId = null;
308
+ }
309
+ if (actualId !== expectedId) throw new PortableObjectRejection("its @id ({objectId}) does not match the requested portable ID", { objectId: id });
310
+ }
311
+ //#endregion
312
+ exports.PortableObjectRejectedError = PortableObjectRejectedError;
313
+ exports.dereferencePortableIri = dereferencePortableIri;
314
+ exports.getPortableGatewayCandidates = getPortableGatewayCandidates;
315
+ exports.isPortableIri = isPortableIri;
@@ -0,0 +1,87 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ import { n as DocumentLoader } from "../docloader-Dr8wEkif.cjs";
3
+ import { t as PortableObjectVerifier } from "../portable-DxF2Ut-Z.cjs";
4
+ import { Span, TracerProvider } from "@opentelemetry/api";
5
+
6
+ //#region src/internal/portable-dereference.d.ts
7
+ /**
8
+ * Checks whether a URL is an FEP-ef61 portable ActivityPub IRI.
9
+ *
10
+ * @internal Technically exported for generated vocabulary classes, but not
11
+ * part of the public API contract. This is not considered public API for
12
+ * Semantic Versioning decisions.
13
+ */
14
+ declare function isPortableIri(url: URL): boolean;
15
+ /**
16
+ * Picks the ordered list of FEP-ef61 gateways to fetch a portable IRI from.
17
+ *
18
+ * If `gateways` is given, it is used as is (even when empty), and `@gateway`
19
+ * location hints in the IRI are ignored. Otherwise, up to
20
+ * {@link MAX_GATEWAY_HINTS} valid `@gateway` hints are used. Duplicate
21
+ * gateways are dropped in both cases.
22
+ *
23
+ * @throws {TypeError} If an explicit gateway is not an HTTP(S) origin.
24
+ * @internal
25
+ */
26
+ declare function getPortableGatewayCandidates(url: URL, gateways?: readonly (string | URL)[]): URL[];
27
+ /**
28
+ * Options for {@link dereferencePortableIri}.
29
+ *
30
+ * @internal Technically exported for generated vocabulary classes, but not
31
+ * part of the public API contract. This is not considered public API for
32
+ * Semantic Versioning decisions.
33
+ */
34
+ interface DereferencePortableIriOptions<T> {
35
+ documentLoader: DocumentLoader;
36
+ contextLoader: DocumentLoader;
37
+ tracerProvider: TracerProvider;
38
+ gateways?: readonly (string | URL)[];
39
+ verifyPortableObject?: PortableObjectVerifier;
40
+ suppressError?: boolean;
41
+ crossOrigin?: "ignore" | "throw" | "trust";
42
+ /**
43
+ * The signal for cancelling the dereference. It is passed to the document
44
+ * loader for requests to gateways, and checked between attempts. Requests
45
+ * for JSON-LD contexts and verification methods may not be cancelled.
46
+ */
47
+ signal?: AbortSignal;
48
+ parse: (document: unknown, options: {
49
+ contextLoader: DocumentLoader;
50
+ baseUrl: URL;
51
+ }) => Promise<T>;
52
+ span?: Span;
53
+ }
54
+ /**
55
+ * The error thrown by {@link dereferencePortableIri} under
56
+ * `crossOrigin: "throw"` when gateways returned objects but none of them
57
+ * satisfied the identity and proof checks.
58
+ *
59
+ * @internal Not part of the public API contract.
60
+ */
61
+ declare class PortableObjectRejectedError extends Error {
62
+ constructor(message: string);
63
+ }
64
+ /**
65
+ * Dereferences an FEP-ef61 portable IRI through its gateways.
66
+ *
67
+ * Gateways are tried one by one until one of them returns a single-node
68
+ * document whose `@id`, if any, canonically matches the requested IRI and
69
+ * which passes `verifyPortableObject`. When there is no gateway to try, the document
70
+ * loader is asked for the portable IRI itself, and its result is validated
71
+ * the same way.
72
+ *
73
+ * @returns The parsed object, or `null` if no valid object was retrieved and
74
+ * `suppressError` is set or the failure was a rejected object
75
+ * (unless `crossOrigin` is `"throw"`).
76
+ * @throws {TypeError} If `gateways` has an invalid entry (always), if no
77
+ * verifier is given, or if the IRI cannot be turned into
78
+ * a gateway URL (unless `suppressError` is set).
79
+ * @internal Technically exported for generated vocabulary classes, but not
80
+ * part of the public API contract. This is not considered public API for
81
+ * Semantic Versioning decisions.
82
+ */
83
+ declare function dereferencePortableIri<T extends {
84
+ id: URL | null;
85
+ }>(url: URL, options: DereferencePortableIriOptions<T>): Promise<T | null>;
86
+ //#endregion
87
+ export { DereferencePortableIriOptions, PortableObjectRejectedError, dereferencePortableIri, getPortableGatewayCandidates, isPortableIri };
@@ -0,0 +1,87 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ import { n as DocumentLoader } from "../docloader-Dr8wEkif.js";
3
+ import { t as PortableObjectVerifier } from "../portable-CduElToy.js";
4
+ import { Span, TracerProvider } from "@opentelemetry/api";
5
+
6
+ //#region src/internal/portable-dereference.d.ts
7
+ /**
8
+ * Checks whether a URL is an FEP-ef61 portable ActivityPub IRI.
9
+ *
10
+ * @internal Technically exported for generated vocabulary classes, but not
11
+ * part of the public API contract. This is not considered public API for
12
+ * Semantic Versioning decisions.
13
+ */
14
+ declare function isPortableIri(url: URL): boolean;
15
+ /**
16
+ * Picks the ordered list of FEP-ef61 gateways to fetch a portable IRI from.
17
+ *
18
+ * If `gateways` is given, it is used as is (even when empty), and `@gateway`
19
+ * location hints in the IRI are ignored. Otherwise, up to
20
+ * {@link MAX_GATEWAY_HINTS} valid `@gateway` hints are used. Duplicate
21
+ * gateways are dropped in both cases.
22
+ *
23
+ * @throws {TypeError} If an explicit gateway is not an HTTP(S) origin.
24
+ * @internal
25
+ */
26
+ declare function getPortableGatewayCandidates(url: URL, gateways?: readonly (string | URL)[]): URL[];
27
+ /**
28
+ * Options for {@link dereferencePortableIri}.
29
+ *
30
+ * @internal Technically exported for generated vocabulary classes, but not
31
+ * part of the public API contract. This is not considered public API for
32
+ * Semantic Versioning decisions.
33
+ */
34
+ interface DereferencePortableIriOptions<T> {
35
+ documentLoader: DocumentLoader;
36
+ contextLoader: DocumentLoader;
37
+ tracerProvider: TracerProvider;
38
+ gateways?: readonly (string | URL)[];
39
+ verifyPortableObject?: PortableObjectVerifier;
40
+ suppressError?: boolean;
41
+ crossOrigin?: "ignore" | "throw" | "trust";
42
+ /**
43
+ * The signal for cancelling the dereference. It is passed to the document
44
+ * loader for requests to gateways, and checked between attempts. Requests
45
+ * for JSON-LD contexts and verification methods may not be cancelled.
46
+ */
47
+ signal?: AbortSignal;
48
+ parse: (document: unknown, options: {
49
+ contextLoader: DocumentLoader;
50
+ baseUrl: URL;
51
+ }) => Promise<T>;
52
+ span?: Span;
53
+ }
54
+ /**
55
+ * The error thrown by {@link dereferencePortableIri} under
56
+ * `crossOrigin: "throw"` when gateways returned objects but none of them
57
+ * satisfied the identity and proof checks.
58
+ *
59
+ * @internal Not part of the public API contract.
60
+ */
61
+ declare class PortableObjectRejectedError extends Error {
62
+ constructor(message: string);
63
+ }
64
+ /**
65
+ * Dereferences an FEP-ef61 portable IRI through its gateways.
66
+ *
67
+ * Gateways are tried one by one until one of them returns a single-node
68
+ * document whose `@id`, if any, canonically matches the requested IRI and
69
+ * which passes `verifyPortableObject`. When there is no gateway to try, the document
70
+ * loader is asked for the portable IRI itself, and its result is validated
71
+ * the same way.
72
+ *
73
+ * @returns The parsed object, or `null` if no valid object was retrieved and
74
+ * `suppressError` is set or the failure was a rejected object
75
+ * (unless `crossOrigin` is `"throw"`).
76
+ * @throws {TypeError} If `gateways` has an invalid entry (always), if no
77
+ * verifier is given, or if the IRI cannot be turned into
78
+ * a gateway URL (unless `suppressError` is set).
79
+ * @internal Technically exported for generated vocabulary classes, but not
80
+ * part of the public API contract. This is not considered public API for
81
+ * Semantic Versioning decisions.
82
+ */
83
+ declare function dereferencePortableIri<T extends {
84
+ id: URL | null;
85
+ }>(url: URL, options: DereferencePortableIriOptions<T>): Promise<T | null>;
86
+ //#endregion
87
+ export { DereferencePortableIriOptions, PortableObjectRejectedError, dereferencePortableIri, getPortableGatewayCandidates, isPortableIri };