@fedify/vocab 2.5.0-dev.2446 → 2.5.0-dev.2492

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.
@@ -1,13 +1,13 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { A as Object$1 } from "./vocab-jHKm_LJ6.mjs";
4
- import { i as isActor, o as name, s as version } from "./actor-C89Bex4F.mjs";
3
+ import { i as isActor, o as name, s as version } from "./actor-BjUFWXfi.mjs";
5
4
  import { t as getTypeId } from "./type-BMdjm4Eg.mjs";
5
+ import { A as Object$1 } from "./vocab-BMEyHiOV.mjs";
6
6
  import { canonicalizePortableUri, formatIri, getDocumentLoader, haveSameFe34Origin, haveSameIriOrigin, parseIri } from "@fedify/vocab-runtime";
7
7
  import { lookupWebFinger } from "@fedify/webfinger";
8
8
  import { SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { getLogger } from "@logtape/logtape";
10
- import { PortableObjectRejectedError, createSnapshotContextLoader, dereferencePortableIri, getPortableGatewayCandidates, getPortableResponseClaim, isPortableIri, parseCompatibleEf61Reference } from "@fedify/vocab-runtime/internal/portable-dereference";
10
+ import { PortableObjectRejectedError, acceptCandidate, createSnapshotContextLoader, dereferencePortableIri, getPortableGatewayCandidates, getPortableResponseClaim, isPortableIri, parseCompatibleEf61Reference } from "@fedify/vocab-runtime/internal/portable-dereference";
11
11
  import { delay } from "es-toolkit";
12
12
  //#region src/handle.ts
13
13
  /**
@@ -107,6 +107,20 @@ const logger = getLogger([
107
107
  "lookup"
108
108
  ]);
109
109
  /**
110
+ * Options for the {@link lookupObject} function.
111
+ *
112
+ * @since 0.2.0
113
+ */
114
+ /**
115
+ * The key of the {@link LookupObjectOptions} property that observes how
116
+ * {@link lookupObject} selects the object it returns.
117
+ *
118
+ * @internal Technically exported for other Fedify packages, but not part of
119
+ * the public API contract. This is not considered public API for Semantic
120
+ * Versioning decisions.
121
+ */
122
+ const lookupObserver = Symbol.for("@fedify/vocab/lookupObserver");
123
+ /**
110
124
  * The maximum number of requests to FEP-ef61 gateways that a single
111
125
  * {@link lookupObject} call makes for portable objects. Gateways come from
112
126
  * possibly untrusted WebFinger responses and location hints, so they are
@@ -226,8 +240,13 @@ async function lookupObjectInternal(identifier, options = {}) {
226
240
  remoteDoc = await documentLoader(identifier.href, { signal: options.signal });
227
241
  } catch (error) {
228
242
  logger.debug("Failed to fetch remote document:\n{error}", { error });
243
+ options[lookupObserver]?.failed?.({
244
+ operation: "fetch",
245
+ error
246
+ });
229
247
  }
230
248
  }
249
+ if (remoteDoc == null && options[lookupObserver]?.webFinger === false) return null;
231
250
  if (remoteDoc == null) {
232
251
  const jrd = await lookupWebFinger(identifier, {
233
252
  userAgent: options.userAgent,
@@ -272,7 +291,7 @@ async function lookupObjectInternal(identifier, options = {}) {
272
291
  }
273
292
  }
274
293
  if (remoteDoc == null) return null;
275
- const snapshot = options.verifyPortableObject == null ? null : createSnapshotContextLoader(options.contextLoader ?? getDocumentLoader({ userAgent: options.userAgent }));
294
+ const snapshot = options.verifyPortableObject == null && options[lookupObserver] == null ? null : createSnapshotContextLoader(options.contextLoader ?? getDocumentLoader({ userAgent: options.userAgent }));
276
295
  try {
277
296
  let object;
278
297
  let documentUrl;
@@ -286,6 +305,10 @@ async function lookupObjectInternal(identifier, options = {}) {
286
305
  baseUrl: documentUrl
287
306
  });
288
307
  } catch (error) {
308
+ options[lookupObserver]?.failed?.({
309
+ operation: "parse",
310
+ error
311
+ });
289
312
  if (error instanceof TypeError) {
290
313
  logger.debug("Failed to parse JSON-LD document: {error}\n{document}", {
291
314
  ...remoteDoc,
@@ -295,7 +318,7 @@ async function lookupObjectInternal(identifier, options = {}) {
295
318
  }
296
319
  throw error;
297
320
  }
298
- if (snapshot != null) {
321
+ if (options.verifyPortableObject != null && snapshot != null) {
299
322
  const claim = getPortableResponseClaim(remoteDoc.documentUrl, object.id);
300
323
  if (claim === null) {
301
324
  logger.debug("Refusing the document {documentUrl}, as it claims to be a portable object with a malformed compatible identifier.", { documentUrl: remoteDoc.documentUrl });
@@ -314,8 +337,16 @@ async function lookupObjectInternal(identifier, options = {}) {
314
337
  ...remoteDoc,
315
338
  objectId: object.id.href
316
339
  });
340
+ options[lookupObserver]?.failed?.({ operation: "origin" });
317
341
  return null;
318
342
  }
343
+ if (!await acceptCandidate(options[lookupObserver], {
344
+ document: remoteDoc.document,
345
+ documentUrl: remoteDoc.documentUrl,
346
+ baseUrl: documentUrl,
347
+ contextLoader: snapshot?.loader ?? options.contextLoader ?? getDocumentLoader({ userAgent: options.userAgent }),
348
+ object
349
+ })) return null;
319
350
  return object;
320
351
  } finally {
321
352
  snapshot?.release();
@@ -429,6 +460,7 @@ async function dereference({ options, documentLoader }, id, inferredGateways, ga
429
460
  verifyPortableObject: options.verifyPortableObject,
430
461
  crossOrigin: options.crossOrigin === "throw" ? "throw" : "ignore",
431
462
  signal: options.signal,
463
+ observer: options[lookupObserver],
432
464
  parse: (document, { contextLoader, baseUrl }) => Object$1.fromJsonLd(document, {
433
465
  documentLoader,
434
466
  contextLoader,
@@ -477,4 +509,4 @@ async function* traverseCollection(collection, options = {}) {
477
509
  }
478
510
  }
479
511
  //#endregion
480
- export { traverseCollection as n, lookupObject as t };
512
+ export { lookupObserver as n, traverseCollection as r, lookupObject as t };
@@ -1,16 +1,18 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { A as Object$1, F as Person, k as Note, s as Collection } from "./vocab-jHKm_LJ6.mjs";
4
- import { t as esm_default } from "./esm-DtAfYdqR.mjs";
5
- import { n as traverseCollection, t as lookupObject } from "./lookup-BehNGq4X.mjs";
3
+ import { t as esm_default } from "./esm-BIqRhjGA.mjs";
4
+ import { A as Object$1, F as Person, k as Note, s as Collection } from "./vocab-BMEyHiOV.mjs";
5
+ import { n as lookupObserver, r as traverseCollection, t as lookupObject } from "./lookup-BQqIkZ5j.mjs";
6
6
  import { t as assertInstanceOf } from "./utils-Df2odC27.mjs";
7
7
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
8
8
  import { deepStrictEqual, equal, ok, rejects } from "node:assert/strict";
9
9
  //#region src/lookup.test.ts
10
+ const allowPrivateAddress = { allowPrivateAddress: true };
10
11
  test("lookupObject()", {
11
12
  sanitizeResources: false,
12
13
  sanitizeOps: false
13
14
  }, async (t) => {
15
+ const responseTimers = [];
14
16
  esm_default.spyGlobal();
15
17
  esm_default.get("begin:https://example.com/.well-known/webfinger", {
16
18
  subject: "acct:johndoe@example.com",
@@ -34,7 +36,8 @@ test("lookupObject()", {
34
36
  });
35
37
  const options = {
36
38
  documentLoader: mockDocumentLoader,
37
- contextLoader: mockDocumentLoader
39
+ contextLoader: mockDocumentLoader,
40
+ ...allowPrivateAddress
38
41
  };
39
42
  await t.step("actor", async () => {
40
43
  const person = await lookupObject("@johndoe@example.com", options);
@@ -73,7 +76,7 @@ test("lookupObject()", {
73
76
  });
74
77
  esm_default.removeRoutes({ includeFallback: false });
75
78
  esm_default.get("begin:https://example.com/.well-known/webfinger", () => new Promise((resolve) => {
76
- setTimeout(() => {
79
+ responseTimers.push(setTimeout(() => {
77
80
  resolve({
78
81
  subject: "acct:johndoe@example.com",
79
82
  links: [{
@@ -82,7 +85,7 @@ test("lookupObject()", {
82
85
  type: "application/activity+json"
83
86
  }]
84
87
  });
85
- }, 1e3);
88
+ }, 1e3));
86
89
  }));
87
90
  await t.step("request cancellation", async () => {
88
91
  const controller = new AbortController();
@@ -113,7 +116,7 @@ test("lookupObject()", {
113
116
  });
114
117
  esm_default.removeRoutes({ includeFallback: false });
115
118
  esm_default.get("begin:https://example.com/.well-known/webfinger", () => new Promise((resolve) => {
116
- setTimeout(() => {
119
+ responseTimers.push(setTimeout(() => {
117
120
  resolve({
118
121
  subject: "acct:johndoe@example.com",
119
122
  links: [{
@@ -122,7 +125,7 @@ test("lookupObject()", {
122
125
  type: "application/activity+json"
123
126
  }]
124
127
  });
125
- }, 500);
128
+ }, 500));
126
129
  }));
127
130
  await t.step("cancellation with immediate abort", async () => {
128
131
  const controller = new AbortController();
@@ -134,7 +137,7 @@ test("lookupObject()", {
134
137
  });
135
138
  esm_default.removeRoutes({ includeFallback: false });
136
139
  esm_default.get("https://example.com/slow-object", () => new Promise((resolve) => {
137
- setTimeout(() => {
140
+ responseTimers.push(setTimeout(() => {
138
141
  resolve({
139
142
  status: 200,
140
143
  headers: { "Content-Type": "application/activity+json" },
@@ -144,7 +147,7 @@ test("lookupObject()", {
144
147
  content: "Slow response"
145
148
  }
146
149
  });
147
- }, 1e3);
150
+ }, 1e3));
148
151
  }));
149
152
  await t.step("direct object fetch cancellation", async () => {
150
153
  const controller = new AbortController();
@@ -155,6 +158,7 @@ test("lookupObject()", {
155
158
  controller.abort();
156
159
  deepStrictEqual(await promise, null);
157
160
  });
161
+ for (const timer of responseTimers) clearTimeout(timer);
158
162
  esm_default.hardReset();
159
163
  esm_default.removeRoutes();
160
164
  });
@@ -392,15 +396,18 @@ test("FEP-fe34: lookupObject() cross-origin security", {
392
396
  throw new Error(`Unexpected URL: ${url}`);
393
397
  };
394
398
  deepStrictEqual(await lookupObject("@user@example.com", {
399
+ ...allowPrivateAddress,
395
400
  documentLoader: webfingerDocumentLoader,
396
401
  contextLoader: mockDocumentLoader
397
402
  }), null);
398
403
  await rejects(() => lookupObject("@user@example.com", {
404
+ ...allowPrivateAddress,
399
405
  documentLoader: webfingerDocumentLoader,
400
406
  contextLoader: mockDocumentLoader,
401
407
  crossOrigin: "throw"
402
408
  }), Error, "The object's @id (https://malicious.com/fake-actor) has a different origin than the document URL (https://different-origin.com/actor)");
403
409
  const result2 = await lookupObject("@user@example.com", {
410
+ ...allowPrivateAddress,
404
411
  documentLoader: webfingerDocumentLoader,
405
412
  contextLoader: mockDocumentLoader,
406
413
  crossOrigin: "trust"
@@ -471,11 +478,20 @@ test("FEP-fe34: lookupObject() cross-origin security", {
471
478
  const errorDocumentLoader = async (_url) => {
472
479
  throw new Error("Network error");
473
480
  };
474
- deepStrictEqual(await lookupObject("https://example.com/note", {
475
- documentLoader: errorDocumentLoader,
476
- contextLoader: mockDocumentLoader,
477
- crossOrigin: "throw"
478
- }), null);
481
+ esm_default.spyGlobal();
482
+ esm_default.get("begin:https://example.com/.well-known/webfinger", 404);
483
+ let result;
484
+ try {
485
+ result = await lookupObject("https://example.com/note", {
486
+ ...allowPrivateAddress,
487
+ documentLoader: errorDocumentLoader,
488
+ contextLoader: mockDocumentLoader,
489
+ crossOrigin: "throw"
490
+ });
491
+ } finally {
492
+ esm_default.hardReset();
493
+ }
494
+ deepStrictEqual(result, null);
479
495
  });
480
496
  await t.step("malformed JSON handling with cross-origin policy", async () => {
481
497
  const malformedJsonDocumentLoader = async (url) => {
@@ -540,6 +556,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
540
556
  await t.step("records kind=actor for an actor result", async () => {
541
557
  const [meterProvider, recorder] = createTestMeterProvider();
542
558
  assertInstanceOf(await lookupObject("@johndoe@example.com", {
559
+ ...allowPrivateAddress,
543
560
  documentLoader: mockDocumentLoader,
544
561
  contextLoader: mockDocumentLoader,
545
562
  meterProvider
@@ -593,6 +610,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
593
610
  });
594
611
  const [meterProvider, recorder] = createTestMeterProvider();
595
612
  deepStrictEqual(await lookupObject("janedoe@example.com", {
613
+ ...allowPrivateAddress,
596
614
  documentLoader: mockDocumentLoader,
597
615
  contextLoader: mockDocumentLoader,
598
616
  meterProvider
@@ -622,6 +640,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
622
640
  });
623
641
  const [meterProvider, recorder] = createTestMeterProvider();
624
642
  await lookupObject("@johndoe@example.com", {
643
+ ...allowPrivateAddress,
625
644
  documentLoader: mockDocumentLoader,
626
645
  contextLoader: mockDocumentLoader,
627
646
  meterProvider
@@ -643,6 +662,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
643
662
  });
644
663
  const [meterProvider, recorder] = createTestMeterProvider();
645
664
  await lookupObject(new URL("acct:johndoe@example.com"), {
665
+ ...allowPrivateAddress,
646
666
  documentLoader: mockDocumentLoader,
647
667
  contextLoader: mockDocumentLoader,
648
668
  meterProvider
@@ -665,5 +685,104 @@ test("lookupObject() records activitypub.object.lookup counter", {
665
685
  esm_default.hardReset();
666
686
  }
667
687
  });
688
+ const OBSERVER_DID = "did:key:z6MkhVPuyvgG1RkMv67azDqDCDERPXVrUg1i3qchXY5EACE3";
689
+ test("lookupObject() offers each candidate to the observer", async () => {
690
+ const note = {
691
+ "@context": "https://www.w3.org/ns/activitystreams",
692
+ id: "https://example.com/notes/1",
693
+ type: "Note",
694
+ content: "Hello"
695
+ };
696
+ const fetched = [];
697
+ const documentLoader = (url) => {
698
+ fetched.push(url);
699
+ if (url === "https://example.com/notes/1") return Promise.resolve({
700
+ contextUrl: null,
701
+ document: note,
702
+ documentUrl: "https://example.com/notes/1?redirected"
703
+ });
704
+ return Promise.reject(/* @__PURE__ */ new Error(`Not found: ${url}`));
705
+ };
706
+ const candidates = [];
707
+ const failures = [];
708
+ const accepted = await lookupObject("https://example.com/notes/1", {
709
+ documentLoader,
710
+ contextLoader: mockDocumentLoader,
711
+ [lookupObserver]: {
712
+ accept: (candidate) => {
713
+ candidates.push(candidate);
714
+ return Promise.resolve(true);
715
+ },
716
+ failed: (failure) => failures.push(failure)
717
+ }
718
+ });
719
+ ok(accepted instanceof Note);
720
+ equal(candidates.length, 1);
721
+ deepStrictEqual(candidates[0].document, note);
722
+ equal(candidates[0].documentUrl, "https://example.com/notes/1?redirected");
723
+ equal(candidates[0].baseUrl.href, "https://example.com/notes/1?redirected");
724
+ equal(candidates[0].object, accepted);
725
+ deepStrictEqual(failures, []);
726
+ for (const accept of [() => Promise.resolve(false), () => Promise.reject(/* @__PURE__ */ new Error("Oops"))]) {
727
+ const refusals = [];
728
+ equal(await lookupObject("https://example.com/notes/1", {
729
+ documentLoader,
730
+ contextLoader: mockDocumentLoader,
731
+ [lookupObserver]: {
732
+ accept,
733
+ failed: (f) => refusals.push(f)
734
+ }
735
+ }), null);
736
+ deepStrictEqual(refusals.map((f) => f.operation), ["accept"]);
737
+ }
738
+ fetched.length = 0;
739
+ const missing = [];
740
+ equal(await lookupObject("https://example.com/notes/2", {
741
+ documentLoader,
742
+ contextLoader: mockDocumentLoader,
743
+ [lookupObserver]: {
744
+ webFinger: false,
745
+ failed: (f) => missing.push(f)
746
+ }
747
+ }), null);
748
+ deepStrictEqual(fetched, ["https://example.com/notes/2"]);
749
+ deepStrictEqual(missing.map((f) => f.operation), ["fetch"]);
750
+ });
751
+ test("lookupObject() keeps looking after the observer refuses a portable candidate", async () => {
752
+ const id = `ap://${OBSERVER_DID}/notes/1`;
753
+ const gateways = ["https://gw1.example", "https://gw2.example"];
754
+ const documentLoader = (url) => Promise.resolve({
755
+ contextUrl: null,
756
+ document: {
757
+ "@context": "https://www.w3.org/ns/activitystreams",
758
+ id,
759
+ type: "Note",
760
+ content: url.startsWith("https://gw1.example/") ? "first" : "second"
761
+ },
762
+ documentUrl: url
763
+ });
764
+ const verifier = () => Promise.resolve({ verified: true });
765
+ const offered = [];
766
+ const failures = [];
767
+ const object = await lookupObject(id, {
768
+ documentLoader,
769
+ contextLoader: mockDocumentLoader,
770
+ gateways,
771
+ verifyPortableObject: verifier,
772
+ [lookupObserver]: {
773
+ accept: (candidate) => {
774
+ offered.push(candidate.documentUrl);
775
+ return Promise.resolve(offered.length > 1);
776
+ },
777
+ failed: (failure) => failures.push(failure)
778
+ }
779
+ });
780
+ ok(object instanceof Note);
781
+ equal(object.content, "second");
782
+ equal(offered.length, 2);
783
+ ok(offered[0].startsWith("https://gw1.example/"));
784
+ ok(offered[1].startsWith("https://gw2.example/"));
785
+ deepStrictEqual(failures.map((f) => f.operation), ["accept"]);
786
+ });
668
787
  //#endregion
669
788
  export {};
@@ -1,14 +1,15 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { F as Person } from "./vocab-jHKm_LJ6.mjs";
4
- import { t as esm_default } from "./esm-DtAfYdqR.mjs";
5
- import { n as getActorHandle } from "./actor-C89Bex4F.mjs";
6
- import { t as lookupObject } from "./lookup-BehNGq4X.mjs";
3
+ import { t as esm_default } from "./esm-BIqRhjGA.mjs";
4
+ import { n as getActorHandle } from "./actor-BjUFWXfi.mjs";
5
+ import { F as Person } from "./vocab-BMEyHiOV.mjs";
6
+ import { t as lookupObject } from "./lookup-BQqIkZ5j.mjs";
7
7
  import { t as assertInstanceOf } from "./utils-Df2odC27.mjs";
8
8
  import { mockDocumentLoader, test } from "@fedify/fixture";
9
9
  import { deepStrictEqual, equal, rejects } from "node:assert/strict";
10
10
  import { FetchError, parseIri } from "@fedify/vocab-runtime";
11
11
  //#region src/portable-lookup.test.ts
12
+ const allowPrivateAddress = { allowPrivateAddress: true };
12
13
  const did = "did:key:z6Mkabc";
13
14
  const actorId = `ap+ef61://${did}/actor`;
14
15
  const gatewayPath = `/.well-known/apgateway/${did}/actor`;
@@ -72,6 +73,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
72
73
  const actor = await lookupObject("@alice@example.com", {
73
74
  documentLoader,
74
75
  contextLoader: mockDocumentLoader,
76
+ ...allowPrivateAddress,
75
77
  verifyPortableObject
76
78
  });
77
79
  assertInstanceOf(actor, Person);
@@ -94,6 +96,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
94
96
  assertInstanceOf(await lookupObject("@alice@example.com", {
95
97
  documentLoader,
96
98
  contextLoader: mockDocumentLoader,
99
+ ...allowPrivateAddress,
97
100
  verifyPortableObject: createVerifier()
98
101
  }), Person);
99
102
  deepStrictEqual(documentLoader.fetched, [compatibleId, hinted]);
@@ -106,6 +109,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
106
109
  assertInstanceOf(await lookupObject("@alice@example.com", {
107
110
  documentLoader,
108
111
  contextLoader: mockDocumentLoader,
112
+ ...allowPrivateAddress,
109
113
  verifyPortableObject: createVerifier(),
110
114
  gateways: ["https://second.example"]
111
115
  }), Person);
@@ -118,6 +122,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
118
122
  equal(await lookupObject("@alice@example.com", {
119
123
  documentLoader,
120
124
  contextLoader: mockDocumentLoader,
125
+ ...allowPrivateAddress,
121
126
  verifyPortableObject: createVerifier(),
122
127
  gateways: Array.from({ length: 6 }, (_, i) => `https://g${i}.example`)
123
128
  }), null);
@@ -136,6 +141,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
136
141
  assertInstanceOf(await lookupObject("@alice@example.com", {
137
142
  documentLoader,
138
143
  contextLoader: mockDocumentLoader,
144
+ ...allowPrivateAddress,
139
145
  verifyPortableObject: createVerifier()
140
146
  }), Person);
141
147
  deepStrictEqual(documentLoader.fetched, [compatibleId, other]);
@@ -149,6 +155,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
149
155
  const actor = await lookupObject("@alice@example.com", {
150
156
  documentLoader,
151
157
  contextLoader: mockDocumentLoader,
158
+ ...allowPrivateAddress,
152
159
  verifyPortableObject
153
160
  });
154
161
  assertInstanceOf(actor, Person);
@@ -169,18 +176,21 @@ test("lookupObject() with FEP-ef61 portable actors", {
169
176
  equal(await lookupObject("@alice@example.com", {
170
177
  documentLoader,
171
178
  contextLoader: mockDocumentLoader,
179
+ ...allowPrivateAddress,
172
180
  verifyPortableObject
173
181
  }), null);
174
182
  deepStrictEqual(documentLoader.fetched, [compatibleId]);
175
183
  await rejects(() => lookupObject("@alice@example.com", {
176
184
  documentLoader,
177
185
  contextLoader: mockDocumentLoader,
186
+ ...allowPrivateAddress,
178
187
  verifyPortableObject,
179
188
  crossOrigin: "throw"
180
189
  }), { name: "PortableObjectRejectedError" });
181
190
  equal(await lookupObject("@alice@example.com", {
182
191
  documentLoader,
183
192
  contextLoader: mockDocumentLoader,
193
+ ...allowPrivateAddress,
184
194
  verifyPortableObject,
185
195
  crossOrigin: "trust"
186
196
  }), null);
@@ -193,17 +203,20 @@ test("lookupObject() with FEP-ef61 portable actors", {
193
203
  for (const crossOrigin of ["ignore", "trust"]) equal(await lookupObject("@alice@example.com", {
194
204
  documentLoader,
195
205
  contextLoader: mockDocumentLoader,
206
+ ...allowPrivateAddress,
196
207
  crossOrigin
197
208
  }), null);
198
209
  deepStrictEqual(documentLoader.fetched, [compatibleId, compatibleId]);
199
210
  await rejects(() => lookupObject("@alice@example.com", {
200
211
  documentLoader,
201
212
  contextLoader: mockDocumentLoader,
213
+ ...allowPrivateAddress,
202
214
  crossOrigin: "throw"
203
215
  }), /has a different origin than the document URL/);
204
216
  const actor = await lookupObject("@alice@example.com", {
205
217
  documentLoader: createLoader({ [compatibleId]: person(compatibleId) }),
206
- contextLoader: mockDocumentLoader
218
+ contextLoader: mockDocumentLoader,
219
+ ...allowPrivateAddress
207
220
  });
208
221
  assertInstanceOf(actor, Person);
209
222
  deepStrictEqual(actor.id, new URL(compatibleId));
@@ -211,7 +224,8 @@ test("lookupObject() with FEP-ef61 portable actors", {
211
224
  const ordinaryLoader = createLoader({ [malformed]: person(malformed) });
212
225
  assertInstanceOf(await lookupObject(malformed, {
213
226
  documentLoader: ordinaryLoader,
214
- contextLoader: mockDocumentLoader
227
+ contextLoader: mockDocumentLoader,
228
+ ...allowPrivateAddress
215
229
  }), Person);
216
230
  deepStrictEqual(ordinaryLoader.fetched, [malformed]);
217
231
  });
@@ -222,6 +236,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
222
236
  const options = {
223
237
  documentLoader,
224
238
  contextLoader: mockDocumentLoader,
239
+ ...allowPrivateAddress,
225
240
  verifyPortableObject: createVerifier()
226
241
  };
227
242
  equal(await lookupObject("@alice@example.com", options), null);
@@ -235,6 +250,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
235
250
  const options = {
236
251
  documentLoader,
237
252
  contextLoader: mockDocumentLoader,
253
+ ...allowPrivateAddress,
238
254
  verifyPortableObject: createVerifier()
239
255
  };
240
256
  equal(await lookupObject(dotted, options), null);
@@ -250,6 +266,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
250
266
  equal(await lookupObject("@alice@example.com", {
251
267
  documentLoader,
252
268
  contextLoader: mockDocumentLoader,
269
+ ...allowPrivateAddress,
253
270
  verifyPortableObject: createVerifier()
254
271
  }), null);
255
272
  deepStrictEqual(documentLoader.fetched, [compatibleId, ...[
@@ -271,6 +288,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
271
288
  equal(await lookupObject("@alice@example.com", {
272
289
  documentLoader,
273
290
  contextLoader: mockDocumentLoader,
291
+ ...allowPrivateAddress,
274
292
  verifyPortableObject,
275
293
  signal: controller.signal
276
294
  }), null);
@@ -405,12 +423,18 @@ test("getActorHandle() with FEP-ef61 portable actors", {
405
423
  await t.step("verified through the first gateway", async () => {
406
424
  esm_default.removeRoutes();
407
425
  esm_default.get("https://example.com/.well-known/webfinger?resource=acct%3Aalice%40example.com", selfLinks(compatibleId));
408
- deepStrictEqual(await getActorHandle(actor), "@alice@example.com");
426
+ deepStrictEqual(await getActorHandle(actor, {
427
+ ...allowPrivateAddress,
428
+ userAgent: void 0
429
+ }), "@alice@example.com");
409
430
  });
410
431
  await t.step("canonical self link", async () => {
411
432
  esm_default.removeRoutes();
412
433
  esm_default.get(webFingerPrefix, selfLinks(`ap://${did}/actor`));
413
- deepStrictEqual(await getActorHandle(actor), "@alice@example.com");
434
+ deepStrictEqual(await getActorHandle(actor, {
435
+ ...allowPrivateAddress,
436
+ userAgent: void 0
437
+ }), "@alice@example.com");
414
438
  });
415
439
  await t.step("follows a verified subject", async () => {
416
440
  esm_default.removeRoutes();
@@ -422,14 +446,20 @@ test("getActorHandle() with FEP-ef61 portable actors", {
422
446
  ...selfLinks(compatibleId),
423
447
  subject: "acct:alice@example.org"
424
448
  });
425
- deepStrictEqual(await getActorHandle(actor), "@alice@example.org");
449
+ deepStrictEqual(await getActorHandle(actor, {
450
+ ...allowPrivateAddress,
451
+ userAgent: void 0
452
+ }), "@alice@example.org");
426
453
  esm_default.removeRoutes();
427
454
  esm_default.get(webFingerPrefix, {
428
455
  ...selfLinks(compatibleId),
429
456
  subject: "acct:alice@example.org"
430
457
  });
431
458
  esm_default.get("begin:https://example.org/.well-known/webfinger", selfLinks(`ap://${did}/other`));
432
- deepStrictEqual(await getActorHandle(actor), "@alice@example.com");
459
+ deepStrictEqual(await getActorHandle(actor, {
460
+ ...allowPrivateAddress,
461
+ userAgent: void 0
462
+ }), "@alice@example.com");
433
463
  });
434
464
  await t.step("rejects a WebFinger response for another actor", async () => {
435
465
  for (const jrd of [
@@ -442,13 +472,19 @@ test("getActorHandle() with FEP-ef61 portable actors", {
442
472
  ]) {
443
473
  esm_default.removeRoutes();
444
474
  esm_default.get(webFingerPrefix, jrd);
445
- await rejects(() => getActorHandle(actor), TypeError);
475
+ await rejects(() => getActorHandle(actor, {
476
+ ...allowPrivateAddress,
477
+ userAgent: void 0
478
+ }), TypeError);
446
479
  }
447
480
  });
448
481
  await t.step("does not fall back when WebFinger fails", async () => {
449
482
  esm_default.removeRoutes();
450
483
  esm_default.get(webFingerPrefix, 404);
451
- await rejects(() => getActorHandle(actor), TypeError);
484
+ await rejects(() => getActorHandle(actor, {
485
+ ...allowPrivateAddress,
486
+ userAgent: void 0
487
+ }), TypeError);
452
488
  });
453
489
  await t.step("not enough information", async () => {
454
490
  esm_default.removeRoutes();
@@ -463,7 +499,10 @@ test("getActorHandle() with FEP-ef61 portable actors", {
463
499
  id: parseIri(actorId),
464
500
  gateways: [new URL("https://example.com")]
465
501
  })
466
- ]) await rejects(() => getActorHandle(target), TypeError);
502
+ ]) await rejects(() => getActorHandle(target, {
503
+ ...allowPrivateAddress,
504
+ userAgent: void 0
505
+ }), TypeError);
467
506
  deepStrictEqual(esm_default.callHistory.calls().length, 0);
468
507
  });
469
508
  } finally {
@@ -0,0 +1,37 @@
1
+ import "temporal-polyfill";
2
+ globalThis.addEventListener = () => {};
3
+ import { createRequire } from "node:module";
4
+ //#region \0rolldown/runtime.js
5
+ var __create = Object.create;
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
12
+ var __exportAll = (all, no_symbols) => {
13
+ let target = {};
14
+ for (var name in all) __defProp(target, name, {
15
+ get: all[name],
16
+ enumerable: true
17
+ });
18
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
19
+ return target;
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
23
+ key = keys[i];
24
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
25
+ get: ((k) => from[k]).bind(null, key),
26
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
27
+ });
28
+ }
29
+ return to;
30
+ };
31
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
32
+ value: mod,
33
+ enumerable: true
34
+ }) : target, mod));
35
+ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
36
+ //#endregion
37
+ export { __toESM as i, __exportAll as n, __require as r, __commonJSMin as t };
@@ -1,6 +1,6 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { M as OrderedCollection, Z as vocab_exports, i as Announce, k as Note, u as Create, z as Question } from "./vocab-jHKm_LJ6.mjs";
3
+ import { M as OrderedCollection, Z as vocab_exports, i as Announce, k as Note, u as Create, z as Question } from "./vocab-BMEyHiOV.mjs";
4
4
  import { mockDocumentLoader, test } from "@fedify/fixture";
5
5
  import { deepStrictEqual, ok } from "node:assert/strict";
6
6
  import { isMarkerSafeContext, retainSignedRepresentation } from "@fedify/vocab-runtime/internal/signed-representation";
@@ -1,8 +1,8 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import "./vocab-jHKm_LJ6.mjs";
4
- import "./actor-C89Bex4F.mjs";
5
- import "./lookup-BehNGq4X.mjs";
3
+ import "./actor-BjUFWXfi.mjs";
4
+ import "./vocab-BMEyHiOV.mjs";
5
+ import "./lookup-BQqIkZ5j.mjs";
6
6
  import { LanguageString as LanguageString$1 } from "@fedify/vocab-runtime";
7
7
  new URL("https://www.w3.org/ns/activitystreams#Public");
8
8
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { A as Object$1, E as Link, F as Person, K as Translation, L as PropertyValue, P as Organization, U as Service, a as Application, b as Group, k as Note, o as Article, q as Update, s as Collection, u as Create } from "./vocab-jHKm_LJ6.mjs";
4
- import { t as LanguageString$1 } from "./src-fpZm9WyF.mjs";
3
+ import { A as Object$1, E as Link, F as Person, K as Translation, L as PropertyValue, P as Organization, U as Service, a as Application, b as Group, k as Note, o as Article, q as Update, s as Collection, u as Create } from "./vocab-BMEyHiOV.mjs";
4
+ import { t as LanguageString$1 } from "./src-DQiQQv6h.mjs";
5
5
  import { test } from "@fedify/fixture";
6
6
  import { deepStrictEqual, ok, rejects } from "node:assert/strict";
7
7
  import { getDocumentLoader, preloadedContexts } from "@fedify/vocab-runtime";