@fedify/vocab-runtime 2.4.0-dev.2115 → 2.4.0-dev.2127

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 (46) hide show
  1. package/deno.json +1 -1
  2. package/dist/{docloader-Dr8wEkif.d.cts → docloader-oRpq1nQ8.d.cts} +8 -1
  3. package/dist/{docloader-Dr8wEkif.d.ts → docloader-oRpq1nQ8.d.ts} +8 -1
  4. package/dist/internal/jsonld-cache.cjs +50 -0
  5. package/dist/internal/jsonld-cache.d.cts +28 -2
  6. package/dist/internal/jsonld-cache.d.ts +28 -2
  7. package/dist/internal/jsonld-cache.js +48 -1
  8. package/dist/internal/portable-dereference.cjs +28 -12
  9. package/dist/internal/portable-dereference.d.cts +12 -4
  10. package/dist/internal/portable-dereference.d.ts +12 -4
  11. package/dist/internal/portable-dereference.js +28 -12
  12. package/dist/mod.cjs +15 -9
  13. package/dist/mod.d.cts +8 -2
  14. package/dist/mod.d.ts +8 -2
  15. package/dist/mod.js +15 -9
  16. package/dist/{portable-comBI05Y.d.cts → portable-Drfl02vZ.d.cts} +1 -1
  17. package/dist/{portable-DH3947GK.d.ts → portable-rwhiyMvY.d.ts} +1 -1
  18. package/dist/tests/{body-Cr12B-9D.cjs → body-BCEAkwBy.cjs} +1 -1
  19. package/dist/tests/{body-CVwHI1SD.mjs → body-BUO7KBud.mjs} +1 -1
  20. package/dist/tests/body.test.cjs +1 -1
  21. package/dist/tests/body.test.mjs +1 -1
  22. package/dist/tests/decimal.test.cjs +1 -1
  23. package/dist/tests/decimal.test.mjs +1 -1
  24. package/dist/tests/{docloader-DWKS3B09.mjs → docloader-BBjIii4r.mjs} +16 -10
  25. package/dist/tests/{docloader-Bknd2EAC.cjs → docloader-DOtl16c7.cjs} +16 -10
  26. package/dist/tests/docloader.test.cjs +49 -2
  27. package/dist/tests/docloader.test.mjs +49 -2
  28. package/dist/tests/internal/portable-dereference.test.cjs +67 -6
  29. package/dist/tests/internal/portable-dereference.test.mjs +67 -6
  30. package/dist/tests/jsonld-cache-9jap4yM0.cjs +373 -0
  31. package/dist/tests/jsonld-cache-DnZS0z1G.mjs +324 -0
  32. package/dist/tests/jsonld-cache.test.cjs +20 -291
  33. package/dist/tests/jsonld-cache.test.mjs +2 -273
  34. package/dist/tests/{request-f7iixEM_.mjs → request-C6bviL-E.mjs} +1 -1
  35. package/dist/tests/{request-BdOpOc_q.cjs → request-DzzSwifZ.cjs} +1 -1
  36. package/dist/tests/request.test.cjs +1 -1
  37. package/dist/tests/request.test.mjs +1 -1
  38. package/package.json +1 -1
  39. package/src/docloader.test.ts +73 -0
  40. package/src/docloader.ts +46 -17
  41. package/src/internal/jsonld-cache.ts +60 -0
  42. package/src/internal/portable-dereference.test.ts +71 -0
  43. package/src/internal/portable-dereference.ts +37 -24
  44. package/src/preprocessor.ts +7 -0
  45. package/dist/tests/jsonld-CmDhHNTx.cjs +0 -12
  46. package/dist/tests/jsonld-DweIJ07b.mjs +0 -5
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.4.0-dev.2115+e2feaf2b",
3
+ "version": "2.4.0-dev.2127+c41ce2eb",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts",
@@ -100,6 +100,12 @@ interface DocumentLoaderOptions {
100
100
  * @since 1.8.0
101
101
  */
102
102
  signal?: AbortSignal;
103
+ /**
104
+ * Whether to lower error-level logs for recoverable document loading
105
+ * failures to warning-level logs. The loader still throws the error.
106
+ * @default `false`
107
+ */
108
+ suppressError?: boolean;
103
109
  }
104
110
  /**
105
111
  * A JSON-LD document loader that fetches documents from the Web.
@@ -160,11 +166,12 @@ type AuthenticatedDocumentLoaderFactory = (identity: {
160
166
  * @param url The URL of the document to load.
161
167
  * @param response The response to get the document from.
162
168
  * @param fetch The function to fetch the document.
169
+ * @param options The options for loading the document.
163
170
  * @returns The loaded remote document.
164
171
  * @throws {FetchError} If the response is not OK.
165
172
  * @internal
166
173
  */
167
- declare function getRemoteDocument(url: string, response: Response, fetch: (url: string, options?: DocumentLoaderOptions) => Promise<RemoteDocument>): Promise<RemoteDocument>;
174
+ declare function getRemoteDocument(url: string, response: Response, fetch: (url: string, options?: DocumentLoaderOptions) => Promise<RemoteDocument>, options?: DocumentLoaderOptions): Promise<RemoteDocument>;
168
175
  /**
169
176
  * Options for {@link getDocumentLoader}.
170
177
  * @since 1.3.0
@@ -100,6 +100,12 @@ interface DocumentLoaderOptions {
100
100
  * @since 1.8.0
101
101
  */
102
102
  signal?: AbortSignal;
103
+ /**
104
+ * Whether to lower error-level logs for recoverable document loading
105
+ * failures to warning-level logs. The loader still throws the error.
106
+ * @default `false`
107
+ */
108
+ suppressError?: boolean;
103
109
  }
104
110
  /**
105
111
  * A JSON-LD document loader that fetches documents from the Web.
@@ -160,11 +166,12 @@ type AuthenticatedDocumentLoaderFactory = (identity: {
160
166
  * @param url The URL of the document to load.
161
167
  * @param response The response to get the document from.
162
168
  * @param fetch The function to fetch the document.
169
+ * @param options The options for loading the document.
163
170
  * @returns The loaded remote document.
164
171
  * @throws {FetchError} If the response is not OK.
165
172
  * @internal
166
173
  */
167
- declare function getRemoteDocument(url: string, response: Response, fetch: (url: string, options?: DocumentLoaderOptions) => Promise<RemoteDocument>): Promise<RemoteDocument>;
174
+ declare function getRemoteDocument(url: string, response: Response, fetch: (url: string, options?: DocumentLoaderOptions) => Promise<RemoteDocument>, options?: DocumentLoaderOptions): Promise<RemoteDocument>;
168
175
  /**
169
176
  * Options for {@link getDocumentLoader}.
170
177
  * @since 1.3.0
@@ -4,6 +4,53 @@ 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");
7
+ const documentLoaderWrappers = /* @__PURE__ */ new WeakMap();
8
+ /**
9
+ * Registers a loader wrapper with the shared released-wrapper registry.
10
+ * Both suppression and snapshot wrappers must use this registry so mixed
11
+ * chains can be unwrapped. The caller updates the state on release.
12
+ * @internal Not a public API.
13
+ */
14
+ function registerDocumentLoaderWrapper(loader, state) {
15
+ documentLoaderWrappers.set(loader, state);
16
+ }
17
+ /**
18
+ * Removes released loader wrappers, stopping at the first active wrapper.
19
+ * Active wrappers retain their operation's suppression or snapshot cache.
20
+ * @internal Not a public API.
21
+ */
22
+ function unwrapReleasedDocumentLoader(base) {
23
+ for (let state = documentLoaderWrappers.get(base); state?.released; state = documentLoaderWrappers.get(base)) base = state.base;
24
+ return base;
25
+ }
26
+ /**
27
+ * Lowers context loading failure logs for one accessor operation. Parsed
28
+ * objects retain the loader, so release it before returning to the caller.
29
+ * Released wrappers are unwrapped to avoid accumulating loader chains.
30
+ * @internal Used by generated vocabulary accessors; not a public API.
31
+ */
32
+ function createScopedContextLoader(base, suppressError) {
33
+ base = unwrapReleasedDocumentLoader(base);
34
+ if (!suppressError) return {
35
+ loader: base,
36
+ release: () => {}
37
+ };
38
+ const state = {
39
+ base,
40
+ released: false
41
+ };
42
+ const loader = (url, options) => base(url, state.released ? options : {
43
+ ...options,
44
+ suppressError: true
45
+ });
46
+ registerDocumentLoaderWrapper(loader, state);
47
+ return {
48
+ loader,
49
+ release: () => {
50
+ state.released = true;
51
+ }
52
+ };
53
+ }
7
54
  /**
8
55
  * Checks whether an IRI is trusted relative to another IRI.
9
56
  *
@@ -274,6 +321,9 @@ function combineContexts(inheritedContext, ownContext) {
274
321
  }
275
322
  //#endregion
276
323
  exports.compactJsonLdCache = compactJsonLdCache;
324
+ exports.createScopedContextLoader = createScopedContextLoader;
277
325
  exports.getJsonLdContext = getJsonLdContext;
278
326
  exports.isTrustedIriOrigin = isTrustedIriOrigin;
279
327
  exports.normalizeJsonLdIris = normalizeJsonLdIris;
328
+ exports.registerDocumentLoaderWrapper = registerDocumentLoaderWrapper;
329
+ exports.unwrapReleasedDocumentLoader = unwrapReleasedDocumentLoader;
@@ -1,8 +1,34 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as DocumentLoader } from "../docloader-Dr8wEkif.cjs";
2
+ import { n as DocumentLoader } from "../docloader-oRpq1nQ8.cjs";
3
3
 
4
4
  //#region src/internal/jsonld-cache.d.ts
5
5
  /**
6
+ * Registers a loader wrapper with the shared released-wrapper registry.
7
+ * Both suppression and snapshot wrappers must use this registry so mixed
8
+ * chains can be unwrapped. The caller updates the state on release.
9
+ * @internal Not a public API.
10
+ */
11
+ declare function registerDocumentLoaderWrapper(loader: DocumentLoader, state: {
12
+ readonly base: DocumentLoader;
13
+ released: boolean;
14
+ }): void;
15
+ /**
16
+ * Removes released loader wrappers, stopping at the first active wrapper.
17
+ * Active wrappers retain their operation's suppression or snapshot cache.
18
+ * @internal Not a public API.
19
+ */
20
+ declare function unwrapReleasedDocumentLoader(base: DocumentLoader): DocumentLoader;
21
+ /**
22
+ * Lowers context loading failure logs for one accessor operation. Parsed
23
+ * objects retain the loader, so release it before returning to the caller.
24
+ * Released wrappers are unwrapped to avoid accumulating loader chains.
25
+ * @internal Used by generated vocabulary accessors; not a public API.
26
+ */
27
+ declare function createScopedContextLoader(base: DocumentLoader, suppressError?: boolean): {
28
+ loader: DocumentLoader;
29
+ release: () => void;
30
+ };
31
+ /**
6
32
  * Options for deciding whether two IRIs should be treated as same-origin.
7
33
  *
8
34
  * @internal Technically exported for generated vocabulary classes, but not
@@ -45,4 +71,4 @@ declare function getJsonLdContext(value: unknown, depth?: number): unknown;
45
71
  */
46
72
  declare function compactJsonLdCache(normalized: unknown, original: unknown, documentLoader?: DocumentLoader, depth?: number, inheritedContext?: unknown): Promise<unknown>;
47
73
  //#endregion
48
- export { IriTrustOptions, compactJsonLdCache, getJsonLdContext, isTrustedIriOrigin, normalizeJsonLdIris };
74
+ export { IriTrustOptions, compactJsonLdCache, createScopedContextLoader, getJsonLdContext, isTrustedIriOrigin, normalizeJsonLdIris, registerDocumentLoaderWrapper, unwrapReleasedDocumentLoader };
@@ -1,8 +1,34 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as DocumentLoader } from "../docloader-Dr8wEkif.js";
2
+ import { n as DocumentLoader } from "../docloader-oRpq1nQ8.js";
3
3
 
4
4
  //#region src/internal/jsonld-cache.d.ts
5
5
  /**
6
+ * Registers a loader wrapper with the shared released-wrapper registry.
7
+ * Both suppression and snapshot wrappers must use this registry so mixed
8
+ * chains can be unwrapped. The caller updates the state on release.
9
+ * @internal Not a public API.
10
+ */
11
+ declare function registerDocumentLoaderWrapper(loader: DocumentLoader, state: {
12
+ readonly base: DocumentLoader;
13
+ released: boolean;
14
+ }): void;
15
+ /**
16
+ * Removes released loader wrappers, stopping at the first active wrapper.
17
+ * Active wrappers retain their operation's suppression or snapshot cache.
18
+ * @internal Not a public API.
19
+ */
20
+ declare function unwrapReleasedDocumentLoader(base: DocumentLoader): DocumentLoader;
21
+ /**
22
+ * Lowers context loading failure logs for one accessor operation. Parsed
23
+ * objects retain the loader, so release it before returning to the caller.
24
+ * Released wrappers are unwrapped to avoid accumulating loader chains.
25
+ * @internal Used by generated vocabulary accessors; not a public API.
26
+ */
27
+ declare function createScopedContextLoader(base: DocumentLoader, suppressError?: boolean): {
28
+ loader: DocumentLoader;
29
+ release: () => void;
30
+ };
31
+ /**
6
32
  * Options for deciding whether two IRIs should be treated as same-origin.
7
33
  *
8
34
  * @internal Technically exported for generated vocabulary classes, but not
@@ -45,4 +71,4 @@ declare function getJsonLdContext(value: unknown, depth?: number): unknown;
45
71
  */
46
72
  declare function compactJsonLdCache(normalized: unknown, original: unknown, documentLoader?: DocumentLoader, depth?: number, inheritedContext?: unknown): Promise<unknown>;
47
73
  //#endregion
48
- export { IriTrustOptions, compactJsonLdCache, getJsonLdContext, isTrustedIriOrigin, normalizeJsonLdIris };
74
+ export { IriTrustOptions, compactJsonLdCache, createScopedContextLoader, getJsonLdContext, isTrustedIriOrigin, normalizeJsonLdIris, registerDocumentLoaderWrapper, unwrapReleasedDocumentLoader };
@@ -3,6 +3,53 @@ import { a as formatIri, c as haveSameFe34Origin, l as haveSameIriOrigin } from
3
3
  import jsonld_default from "../jsonld.js";
4
4
  //#region src/internal/jsonld-cache.ts
5
5
  const noJsonLdContext = Symbol("noJsonLdContext");
6
+ const documentLoaderWrappers = /* @__PURE__ */ new WeakMap();
7
+ /**
8
+ * Registers a loader wrapper with the shared released-wrapper registry.
9
+ * Both suppression and snapshot wrappers must use this registry so mixed
10
+ * chains can be unwrapped. The caller updates the state on release.
11
+ * @internal Not a public API.
12
+ */
13
+ function registerDocumentLoaderWrapper(loader, state) {
14
+ documentLoaderWrappers.set(loader, state);
15
+ }
16
+ /**
17
+ * Removes released loader wrappers, stopping at the first active wrapper.
18
+ * Active wrappers retain their operation's suppression or snapshot cache.
19
+ * @internal Not a public API.
20
+ */
21
+ function unwrapReleasedDocumentLoader(base) {
22
+ for (let state = documentLoaderWrappers.get(base); state?.released; state = documentLoaderWrappers.get(base)) base = state.base;
23
+ return base;
24
+ }
25
+ /**
26
+ * Lowers context loading failure logs for one accessor operation. Parsed
27
+ * objects retain the loader, so release it before returning to the caller.
28
+ * Released wrappers are unwrapped to avoid accumulating loader chains.
29
+ * @internal Used by generated vocabulary accessors; not a public API.
30
+ */
31
+ function createScopedContextLoader(base, suppressError) {
32
+ base = unwrapReleasedDocumentLoader(base);
33
+ if (!suppressError) return {
34
+ loader: base,
35
+ release: () => {}
36
+ };
37
+ const state = {
38
+ base,
39
+ released: false
40
+ };
41
+ const loader = (url, options) => base(url, state.released ? options : {
42
+ ...options,
43
+ suppressError: true
44
+ });
45
+ registerDocumentLoaderWrapper(loader, state);
46
+ return {
47
+ loader,
48
+ release: () => {
49
+ state.released = true;
50
+ }
51
+ };
52
+ }
6
53
  /**
7
54
  * Checks whether an IRI is trusted relative to another IRI.
8
55
  *
@@ -272,4 +319,4 @@ function combineContexts(inheritedContext, ownContext) {
272
319
  return [...inherited, ...own];
273
320
  }
274
321
  //#endregion
275
- export { compactJsonLdCache, getJsonLdContext, isTrustedIriOrigin, normalizeJsonLdIris };
322
+ export { compactJsonLdCache, createScopedContextLoader, getJsonLdContext, isTrustedIriOrigin, normalizeJsonLdIris, registerDocumentLoaderWrapper, unwrapReleasedDocumentLoader };
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require_contexts = require("../contexts-2hEbs3Qk.cjs");
4
4
  const require_url = require("../url-Cke4irYD.cjs");
5
5
  const require_jsonld = require("../jsonld.cjs");
6
+ const require_internal_jsonld_cache = require("./jsonld-cache.cjs");
6
7
  let _logtape_logtape = require("@logtape/logtape");
7
8
  let _opentelemetry_api = require("@opentelemetry/api");
8
9
  //#region src/internal/portable-dereference.ts
@@ -38,7 +39,15 @@ function getObjectId(object) {
38
39
  }
39
40
  /**
40
41
  * Checks whether a vocabulary object is part of a chain of portable objects,
41
- * i.e., whether it has a portable ID or was obtained from a portable object.
42
+ * i.e., whether it has a portable ID, has an FEP-ef61 compatible identifier
43
+ * as its ID (even a malformed one, so that it fails closed), or was obtained
44
+ * from a portable object. Accessors of such objects dereference references
45
+ * as portable objects.
46
+ *
47
+ * Being part of a chain does not mean that the object itself is verified:
48
+ * an object parsed from arbitrary JSON-LD is in a chain just because of its
49
+ * ID. Only {@link dereferencePortableIri} records that an object was
50
+ * accepted by a verifier.
42
51
  *
43
52
  * @internal Technically exported for generated vocabulary classes, but not
44
53
  * part of the public API contract. This is not considered public API for
@@ -47,7 +56,7 @@ function getObjectId(object) {
47
56
  function isInPortableChain(object) {
48
57
  if (provenances.has(object)) return true;
49
58
  const id = getObjectId(object);
50
- return id != null && isPortableIri(id);
59
+ return id != null && (isPortableIri(id) || isCompatibleEf61Iri(id));
51
60
  }
52
61
  /**
53
62
  * Checks whether a vocabulary object was accepted without an integrity
@@ -393,8 +402,8 @@ function parseGatewayOrigin(gateway) {
393
402
  * part of the public API contract. This is not considered public API for
394
403
  * Semantic Versioning decisions.
395
404
  */
396
- function createSnapshotContextLoader(contextLoader) {
397
- for (let wrapped = snapshotLoaders.get(contextLoader); wrapped?.released; wrapped = snapshotLoaders.get(contextLoader)) contextLoader = wrapped.base;
405
+ function createSnapshotContextLoader(contextLoader, suppressError) {
406
+ contextLoader = require_internal_jsonld_cache.unwrapReleasedDocumentLoader(contextLoader);
398
407
  const cache = /* @__PURE__ */ new Map();
399
408
  let released = false;
400
409
  const release = () => {
@@ -412,7 +421,10 @@ function createSnapshotContextLoader(contextLoader) {
412
421
  };
413
422
  let promise = cache.get(key);
414
423
  if (promise == null) {
415
- const loading = contextLoader(url, options).then((document) => structuredClone(document));
424
+ const loading = contextLoader(url, suppressError ? {
425
+ ...options,
426
+ suppressError: true
427
+ } : options).then((document) => structuredClone(document));
416
428
  promise = loading;
417
429
  cache.set(key, loading);
418
430
  loading.catch(() => {
@@ -425,13 +437,12 @@ function createSnapshotContextLoader(contextLoader) {
425
437
  base: contextLoader,
426
438
  released: false
427
439
  };
428
- snapshotLoaders.set(loader, state);
440
+ require_internal_jsonld_cache.registerDocumentLoaderWrapper(loader, state);
429
441
  return {
430
442
  loader,
431
443
  release
432
444
  };
433
445
  }
434
- const snapshotLoaders = /* @__PURE__ */ new WeakMap();
435
446
  /**
436
447
  * The error thrown by {@link dereferencePortableIri} under
437
448
  * `crossOrigin: "throw"` when gateways returned objects but none of them
@@ -487,7 +498,7 @@ async function dereferencePortableIri(url, options) {
487
498
  message: String(error)
488
499
  });
489
500
  if (options.suppressError) {
490
- logger.error("Failed to dereference {url}: {error}", {
501
+ logger.warn("Failed to dereference {url}: {error}", {
491
502
  url: lookupUrl,
492
503
  error
493
504
  });
@@ -496,7 +507,7 @@ async function dereferencePortableIri(url, options) {
496
507
  throw error;
497
508
  };
498
509
  const verify = options.verifyPortableObject;
499
- if (verify == null) return fail(/* @__PURE__ */ new TypeError("Dereferencing the portable object " + lookupUrl + " requires the verifyPortableObject option, e.g., verifyPortableObjectProof() from @fedify/fedify."));
510
+ if (verify == null) return fail(/* @__PURE__ */ new TypeError("Dereferencing the portable object " + lookupUrl + " requires the verifyPortableObject option, e.g., verifyPortableObject() from @fedify/fedify. Passing a Fedify Context as the options gives it, and objects parsed with the option use it by default."));
500
511
  const requestUrls = [];
501
512
  let expectedId;
502
513
  try {
@@ -517,8 +528,9 @@ async function dereferencePortableIri(url, options) {
517
528
  url: lookupUrl,
518
529
  gateway: null
519
530
  });
520
- const snapshot = createSnapshotContextLoader(options.contextLoader);
531
+ const snapshot = createSnapshotContextLoader(options.contextLoader, options.suppressError);
521
532
  const contextLoader = snapshot.loader;
533
+ const scopedDocument = require_internal_jsonld_cache.createScopedContextLoader(options.documentLoader, options.suppressError);
522
534
  const attempts = [];
523
535
  const { signal } = options;
524
536
  const gatewayHints = explicitGateways == null && inferredGateways.length > 0 ? inferredGateways : void 0;
@@ -528,7 +540,10 @@ async function dereferencePortableIri(url, options) {
528
540
  signal?.throwIfAborted();
529
541
  let remoteDocument;
530
542
  try {
531
- remoteDocument = response ?? await options.documentLoader(requestUrl, signal == null ? void 0 : { signal });
543
+ remoteDocument = response ?? await options.documentLoader(requestUrl, {
544
+ signal,
545
+ suppressError: options.suppressError
546
+ });
532
547
  } catch (error) {
533
548
  signal?.throwIfAborted();
534
549
  logger.debug("Failed to fetch {url} from {requestUrl}: {error}", {
@@ -554,7 +569,7 @@ async function dereferencePortableIri(url, options) {
554
569
  let result;
555
570
  try {
556
571
  result = await verify(document, {
557
- documentLoader: options.documentLoader,
572
+ documentLoader: scopedDocument.loader,
558
573
  contextLoader,
559
574
  tracerProvider: options.tracerProvider,
560
575
  ...documentUrl == null ? {} : { documentUrl },
@@ -604,6 +619,7 @@ async function dereferencePortableIri(url, options) {
604
619
  }
605
620
  }
606
621
  } finally {
622
+ scopedDocument.release();
607
623
  snapshot.release();
608
624
  }
609
625
  const rejected = attempts.filter((a) => a.type === "rejected");
@@ -1,6 +1,6 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as DocumentLoader, s as RemoteDocument } from "../docloader-Dr8wEkif.cjs";
3
- import { r as PortableObjectVerifier } from "../portable-comBI05Y.cjs";
2
+ import { n as DocumentLoader, s as RemoteDocument } from "../docloader-oRpq1nQ8.cjs";
3
+ import { r as PortableObjectVerifier } from "../portable-Drfl02vZ.cjs";
4
4
  import { Span, TracerProvider } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/internal/portable-dereference.d.ts
@@ -16,7 +16,15 @@ interface PortableReferrerLink {
16
16
  }
17
17
  /**
18
18
  * Checks whether a vocabulary object is part of a chain of portable objects,
19
- * i.e., whether it has a portable ID or was obtained from a portable object.
19
+ * i.e., whether it has a portable ID, has an FEP-ef61 compatible identifier
20
+ * as its ID (even a malformed one, so that it fails closed), or was obtained
21
+ * from a portable object. Accessors of such objects dereference references
22
+ * as portable objects.
23
+ *
24
+ * Being part of a chain does not mean that the object itself is verified:
25
+ * an object parsed from arbitrary JSON-LD is in a chain just because of its
26
+ * ID. Only {@link dereferencePortableIri} records that an object was
27
+ * accepted by a verifier.
20
28
  *
21
29
  * @internal Technically exported for generated vocabulary classes, but not
22
30
  * part of the public API contract. This is not considered public API for
@@ -236,7 +244,7 @@ declare function getPortableGatewayCandidates(url: URL, gateways?: readonly (str
236
244
  * part of the public API contract. This is not considered public API for
237
245
  * Semantic Versioning decisions.
238
246
  */
239
- declare function createSnapshotContextLoader(contextLoader: DocumentLoader): {
247
+ declare function createSnapshotContextLoader(contextLoader: DocumentLoader, suppressError?: boolean): {
240
248
  loader: DocumentLoader;
241
249
  release: () => void;
242
250
  };
@@ -1,6 +1,6 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as DocumentLoader, s as RemoteDocument } from "../docloader-Dr8wEkif.js";
3
- import { r as PortableObjectVerifier } from "../portable-DH3947GK.js";
2
+ import { n as DocumentLoader, s as RemoteDocument } from "../docloader-oRpq1nQ8.js";
3
+ import { r as PortableObjectVerifier } from "../portable-rwhiyMvY.js";
4
4
  import { Span, TracerProvider } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/internal/portable-dereference.d.ts
@@ -16,7 +16,15 @@ interface PortableReferrerLink {
16
16
  }
17
17
  /**
18
18
  * Checks whether a vocabulary object is part of a chain of portable objects,
19
- * i.e., whether it has a portable ID or was obtained from a portable object.
19
+ * i.e., whether it has a portable ID, has an FEP-ef61 compatible identifier
20
+ * as its ID (even a malformed one, so that it fails closed), or was obtained
21
+ * from a portable object. Accessors of such objects dereference references
22
+ * as portable objects.
23
+ *
24
+ * Being part of a chain does not mean that the object itself is verified:
25
+ * an object parsed from arbitrary JSON-LD is in a chain just because of its
26
+ * ID. Only {@link dereferencePortableIri} records that an object was
27
+ * accepted by a verifier.
20
28
  *
21
29
  * @internal Technically exported for generated vocabulary classes, but not
22
30
  * part of the public API contract. This is not considered public API for
@@ -236,7 +244,7 @@ declare function getPortableGatewayCandidates(url: URL, gateways?: readonly (str
236
244
  * part of the public API contract. This is not considered public API for
237
245
  * Semantic Versioning decisions.
238
246
  */
239
- declare function createSnapshotContextLoader(contextLoader: DocumentLoader): {
247
+ declare function createSnapshotContextLoader(contextLoader: DocumentLoader, suppressError?: boolean): {
240
248
  loader: DocumentLoader;
241
249
  release: () => void;
242
250
  };
@@ -2,6 +2,7 @@
2
2
  import { t as preloadedContexts } from "../contexts-DoZUIW7y.js";
3
3
  import { a as formatIri, c as haveSameFe34Origin, g as toCompatibleEf61Id, m as parseIri, o as fromCompatibleEf61Id, r as canonicalizePortableUri } from "../url-CEhi4hb4.js";
4
4
  import jsonld_default from "../jsonld.js";
5
+ import { createScopedContextLoader, registerDocumentLoaderWrapper, unwrapReleasedDocumentLoader } from "./jsonld-cache.js";
5
6
  import { getLogger } from "@logtape/logtape";
6
7
  import { SpanStatusCode } from "@opentelemetry/api";
7
8
  //#region src/internal/portable-dereference.ts
@@ -37,7 +38,15 @@ function getObjectId(object) {
37
38
  }
38
39
  /**
39
40
  * Checks whether a vocabulary object is part of a chain of portable objects,
40
- * i.e., whether it has a portable ID or was obtained from a portable object.
41
+ * i.e., whether it has a portable ID, has an FEP-ef61 compatible identifier
42
+ * as its ID (even a malformed one, so that it fails closed), or was obtained
43
+ * from a portable object. Accessors of such objects dereference references
44
+ * as portable objects.
45
+ *
46
+ * Being part of a chain does not mean that the object itself is verified:
47
+ * an object parsed from arbitrary JSON-LD is in a chain just because of its
48
+ * ID. Only {@link dereferencePortableIri} records that an object was
49
+ * accepted by a verifier.
41
50
  *
42
51
  * @internal Technically exported for generated vocabulary classes, but not
43
52
  * part of the public API contract. This is not considered public API for
@@ -46,7 +55,7 @@ function getObjectId(object) {
46
55
  function isInPortableChain(object) {
47
56
  if (provenances.has(object)) return true;
48
57
  const id = getObjectId(object);
49
- return id != null && isPortableIri(id);
58
+ return id != null && (isPortableIri(id) || isCompatibleEf61Iri(id));
50
59
  }
51
60
  /**
52
61
  * Checks whether a vocabulary object was accepted without an integrity
@@ -392,8 +401,8 @@ function parseGatewayOrigin(gateway) {
392
401
  * part of the public API contract. This is not considered public API for
393
402
  * Semantic Versioning decisions.
394
403
  */
395
- function createSnapshotContextLoader(contextLoader) {
396
- for (let wrapped = snapshotLoaders.get(contextLoader); wrapped?.released; wrapped = snapshotLoaders.get(contextLoader)) contextLoader = wrapped.base;
404
+ function createSnapshotContextLoader(contextLoader, suppressError) {
405
+ contextLoader = unwrapReleasedDocumentLoader(contextLoader);
397
406
  const cache = /* @__PURE__ */ new Map();
398
407
  let released = false;
399
408
  const release = () => {
@@ -411,7 +420,10 @@ function createSnapshotContextLoader(contextLoader) {
411
420
  };
412
421
  let promise = cache.get(key);
413
422
  if (promise == null) {
414
- const loading = contextLoader(url, options).then((document) => structuredClone(document));
423
+ const loading = contextLoader(url, suppressError ? {
424
+ ...options,
425
+ suppressError: true
426
+ } : options).then((document) => structuredClone(document));
415
427
  promise = loading;
416
428
  cache.set(key, loading);
417
429
  loading.catch(() => {
@@ -424,13 +436,12 @@ function createSnapshotContextLoader(contextLoader) {
424
436
  base: contextLoader,
425
437
  released: false
426
438
  };
427
- snapshotLoaders.set(loader, state);
439
+ registerDocumentLoaderWrapper(loader, state);
428
440
  return {
429
441
  loader,
430
442
  release
431
443
  };
432
444
  }
433
- const snapshotLoaders = /* @__PURE__ */ new WeakMap();
434
445
  /**
435
446
  * The error thrown by {@link dereferencePortableIri} under
436
447
  * `crossOrigin: "throw"` when gateways returned objects but none of them
@@ -486,7 +497,7 @@ async function dereferencePortableIri(url, options) {
486
497
  message: String(error)
487
498
  });
488
499
  if (options.suppressError) {
489
- logger.error("Failed to dereference {url}: {error}", {
500
+ logger.warn("Failed to dereference {url}: {error}", {
490
501
  url: lookupUrl,
491
502
  error
492
503
  });
@@ -495,7 +506,7 @@ async function dereferencePortableIri(url, options) {
495
506
  throw error;
496
507
  };
497
508
  const verify = options.verifyPortableObject;
498
- if (verify == null) return fail(/* @__PURE__ */ new TypeError("Dereferencing the portable object " + lookupUrl + " requires the verifyPortableObject option, e.g., verifyPortableObjectProof() from @fedify/fedify."));
509
+ if (verify == null) return fail(/* @__PURE__ */ new TypeError("Dereferencing the portable object " + lookupUrl + " requires the verifyPortableObject option, e.g., verifyPortableObject() from @fedify/fedify. Passing a Fedify Context as the options gives it, and objects parsed with the option use it by default."));
499
510
  const requestUrls = [];
500
511
  let expectedId;
501
512
  try {
@@ -516,8 +527,9 @@ async function dereferencePortableIri(url, options) {
516
527
  url: lookupUrl,
517
528
  gateway: null
518
529
  });
519
- const snapshot = createSnapshotContextLoader(options.contextLoader);
530
+ const snapshot = createSnapshotContextLoader(options.contextLoader, options.suppressError);
520
531
  const contextLoader = snapshot.loader;
532
+ const scopedDocument = createScopedContextLoader(options.documentLoader, options.suppressError);
521
533
  const attempts = [];
522
534
  const { signal } = options;
523
535
  const gatewayHints = explicitGateways == null && inferredGateways.length > 0 ? inferredGateways : void 0;
@@ -527,7 +539,10 @@ async function dereferencePortableIri(url, options) {
527
539
  signal?.throwIfAborted();
528
540
  let remoteDocument;
529
541
  try {
530
- remoteDocument = response ?? await options.documentLoader(requestUrl, signal == null ? void 0 : { signal });
542
+ remoteDocument = response ?? await options.documentLoader(requestUrl, {
543
+ signal,
544
+ suppressError: options.suppressError
545
+ });
531
546
  } catch (error) {
532
547
  signal?.throwIfAborted();
533
548
  logger.debug("Failed to fetch {url} from {requestUrl}: {error}", {
@@ -553,7 +568,7 @@ async function dereferencePortableIri(url, options) {
553
568
  let result;
554
569
  try {
555
570
  result = await verify(document, {
556
- documentLoader: options.documentLoader,
571
+ documentLoader: scopedDocument.loader,
557
572
  contextLoader,
558
573
  tracerProvider: options.tracerProvider,
559
574
  ...documentUrl == null ? {} : { documentUrl },
@@ -603,6 +618,7 @@ async function dereferencePortableIri(url, options) {
603
618
  }
604
619
  }
605
620
  } finally {
621
+ scopedDocument.release();
606
622
  snapshot.release();
607
623
  }
608
624
  const rejected = attempts.filter((a) => a.type === "rejected");