@fedify/fedify 2.4.0-dev.1988 → 2.4.0-dev.1995

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 (62) hide show
  1. package/dist/{builder-Cts78G9N.mjs → builder-D0DxgOV5.mjs} +2 -2
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/compound-proof-CJnWc6c-.mjs +495 -0
  4. package/dist/{deno-BgMEefEr.mjs → deno-CABhzCb_.mjs} +1 -1
  5. package/dist/{docloader-DEYs99FZ.mjs → docloader-BbGSL0Xq.mjs} +2 -2
  6. package/dist/federation/builder.test.mjs +1 -1
  7. package/dist/federation/handler-compound-proof.test.d.mts +2 -0
  8. package/dist/federation/handler-compound-proof.test.mjs +152 -0
  9. package/dist/federation/handler.test.mjs +5 -5
  10. package/dist/federation/idempotency.test.mjs +2 -2
  11. package/dist/federation/metrics.test.mjs +1 -1
  12. package/dist/federation/middleware.test.mjs +7 -7
  13. package/dist/federation/mod.cjs +1 -1
  14. package/dist/federation/mod.js +1 -1
  15. package/dist/federation/send.test.mjs +3 -3
  16. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  17. package/dist/federation/tasks/tasks.test.mjs +2 -2
  18. package/dist/federation/temporal.test.mjs +1 -1
  19. package/dist/federation/webfinger.test.mjs +1 -1
  20. package/dist/{federation-DzPUG_AP.cjs → federation-DCEHQk4G.cjs} +542 -43
  21. package/dist/{http-CgwqtxAy.js → http-9WyuldYh.js} +2 -2
  22. package/dist/{http-Z3anvCd-.cjs → http-CRFns-UE.cjs} +2 -2
  23. package/dist/{http-CtidZS_t.mjs → http-D9urSO2D.mjs} +3 -3
  24. package/dist/{key-Cwbg5ggV.mjs → key-Ccs8cnd7.mjs} +2 -2
  25. package/dist/{kv-cache-BM2-w-Wq.cjs → kv-cache-DXT9vmIg.cjs} +1 -1
  26. package/dist/{kv-cache-CykuL0ya.js → kv-cache-DtmXhPXG.js} +1 -1
  27. package/dist/{kv-cache-DHiR8yTf.mjs → kv-cache-lKyFn_Dn.mjs} +1 -1
  28. package/dist/{ld-CzhdWyTt.mjs → ld-qup__MAW.mjs} +3 -3
  29. package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
  30. package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
  31. package/dist/{metrics-CrqsHP0l.mjs → metrics-CISXCvB1.mjs} +1 -1
  32. package/dist/{middleware-DCpiAsZi.mjs → middleware-CzvJvPHK.mjs} +52 -20
  33. package/dist/{middleware-CZpYxSKD.mjs → middleware-DkrU2WhY.mjs} +1 -1
  34. package/dist/{middleware-CeCj5caM.js → middleware-DsfWajaD.js} +511 -12
  35. package/dist/mod.cjs +19 -19
  36. package/dist/mod.js +4 -4
  37. package/dist/nodeinfo/handler.test.mjs +1 -1
  38. package/dist/{proof-CUghqhAf.js → owner-BIPEZGiU.js} +1239 -1139
  39. package/dist/{owner-BqVXJLW8.mjs → owner-CRoq8Spb.mjs} +2 -2
  40. package/dist/{proof-DHu5zI0Z.cjs → owner-CVA7L9MA.cjs} +1252 -1140
  41. package/dist/{proof-DL8Iid3a.mjs → proof-BDxNVZ3E.mjs} +176 -76
  42. package/dist/{send-6jS4xFsX.mjs → send-BzM5GLyn.mjs} +3 -3
  43. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  44. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  45. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  46. package/dist/sig/compound-proof-verification.test.mjs +465 -0
  47. package/dist/sig/compound-proof.test.d.mts +2 -0
  48. package/dist/sig/compound-proof.test.mjs +324 -0
  49. package/dist/sig/http.test.mjs +2 -2
  50. package/dist/sig/key.test.mjs +1 -1
  51. package/dist/sig/ld.test.mjs +2 -2
  52. package/dist/sig/mod.cjs +17 -17
  53. package/dist/sig/mod.js +2 -2
  54. package/dist/sig/owner.test.mjs +1 -1
  55. package/dist/sig/proof.test.mjs +1 -1
  56. package/dist/{temporal-DcyzeytP.mjs → temporal-Dv6Qv-8k.mjs} +1 -1
  57. package/dist/testing/kv.test.mjs +1 -1
  58. package/dist/utils/docloader.test.mjs +2 -2
  59. package/dist/utils/kv-cache.test.mjs +1 -1
  60. package/dist/utils/mod.cjs +1 -1
  61. package/dist/utils/mod.js +1 -1
  62. package/package.json +6 -6
@@ -1,7 +1,7 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BgMEefEr.mjs";
4
+ import { n as version, t as name } from "./deno-CABhzCb_.mjs";
5
5
  import { t as ActivityListenerSet } from "./activity-listener-C-BSbKI7.mjs";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  import { Router, RouterError, assertPath } from "@fedify/uri-template";
@@ -85,7 +85,7 @@ var FederationBuilderImpl = class {
85
85
  * specified.
86
86
  */
87
87
  async build(options) {
88
- const { FederationImpl } = await import("./middleware-CZpYxSKD.mjs");
88
+ const { FederationImpl } = await import("./middleware-DkrU2WhY.mjs");
89
89
  const f = new FederationImpl(options);
90
90
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
91
91
  f.router = this.router.clone();
@@ -5,7 +5,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
6
6
  import { t as assertInstanceOf } from "../assert_instance_of-g3WcyYNR.mjs";
7
7
  import { t as assert } from "../assert-CebeUf0C.mjs";
8
- import { b as autoIdAssigner, n as FederationImpl, y as actorDehydrator } from "../middleware-DCpiAsZi.mjs";
8
+ import { b as autoIdAssigner, n as FederationImpl, y as actorDehydrator } from "../middleware-CzvJvPHK.mjs";
9
9
  import { Follow, Person } from "@fedify/vocab";
10
10
  import { test } from "@fedify/fixture";
11
11
  //#region src/compat/transformers.test.ts
@@ -0,0 +1,495 @@
1
+ import "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { i as verifyMapLocalProof, s as verifyPortableObjectProofPolicy } from "./proof-BDxNVZ3E.mjs";
5
+ //#region src/sig/compound-proof.ts
6
+ const textEncoder = new TextEncoder();
7
+ const PORTABLE_OBJECT_ID_PATTERN = /^ap(?:\+ef61)?:\/\//i;
8
+ function isJsonMap(value) {
9
+ return typeof value === "object" && value != null && !Array.isArray(value);
10
+ }
11
+ function isCompoundProofJsonObject(value) {
12
+ return typeof value === "object" && value != null && !Array.isArray(value);
13
+ }
14
+ function hasOnlyDataProperties(value) {
15
+ try {
16
+ return Reflect.ownKeys(value).every((key) => {
17
+ if (typeof key !== "string") return false;
18
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
19
+ return descriptor != null && "value" in descriptor && descriptor.enumerable;
20
+ });
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+ function hasOnlyJsonArrayProperties(value) {
26
+ try {
27
+ const keys = Reflect.ownKeys(value);
28
+ if (keys.length !== value.length + 1) return false;
29
+ for (const key of keys) {
30
+ if (key === "length") continue;
31
+ if (typeof key !== "string") return false;
32
+ const index = Number(key);
33
+ if (!Number.isInteger(index) || index < 0 || index >= value.length || String(index) !== key) return false;
34
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
35
+ if (descriptor == null || !descriptor.enumerable || !("value" in descriptor)) return false;
36
+ }
37
+ return true;
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+ function escapeJsonPointerSegment(segment) {
43
+ return segment.replaceAll("~", "~0").replaceAll("/", "~1");
44
+ }
45
+ function childPath(path, segment) {
46
+ return `${path}/${escapeJsonPointerSegment(segment)}`;
47
+ }
48
+ function comparePaths(left, right) {
49
+ return left < right ? -1 : left > right ? 1 : 0;
50
+ }
51
+ function encodedLength(value) {
52
+ return textEncoder.encode(value).byteLength;
53
+ }
54
+ function validateLimits(limits) {
55
+ for (const [name, value] of Object.entries(limits)) if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name} must be a non-negative safe integer.`);
56
+ }
57
+ function limitExceeded(limit, maximum, actual, path) {
58
+ return {
59
+ status: "unsupported",
60
+ reason: {
61
+ type: "limitExceeded",
62
+ limit,
63
+ maximum,
64
+ actual,
65
+ path
66
+ }
67
+ };
68
+ }
69
+ function addBytes(statistics, bytes, limits, path) {
70
+ statistics.byteLength += bytes;
71
+ if (statistics.byteLength > limits.maxBytes) return limitExceeded("bytes", limits.maxBytes, statistics.byteLength, path);
72
+ }
73
+ function inspectJsonTree(root, limits) {
74
+ if (!isJsonMap(root)) return {
75
+ status: "unsupported",
76
+ reason: {
77
+ type: "invalidJsonTree",
78
+ path: ""
79
+ }
80
+ };
81
+ const statistics = {
82
+ byteLength: 0,
83
+ mapCount: 0,
84
+ proofCount: 0,
85
+ maxDepth: 0
86
+ };
87
+ const seen = /* @__PURE__ */ new Set();
88
+ const pending = [{
89
+ value: root,
90
+ path: "",
91
+ depth: 0,
92
+ insideProof: false,
93
+ insideContext: false
94
+ }];
95
+ while (pending.length > 0) {
96
+ const current = pending.pop();
97
+ statistics.maxDepth = Math.max(statistics.maxDepth, current.depth);
98
+ if (current.depth > limits.maxDepth) return limitExceeded("depth", limits.maxDepth, current.depth, current.path);
99
+ const value = current.value;
100
+ if (value === null) {
101
+ const failure = addBytes(statistics, 4, limits, current.path);
102
+ if (failure != null) return failure;
103
+ } else if (typeof value === "boolean") {
104
+ const failure = addBytes(statistics, value ? 4 : 5, limits, current.path);
105
+ if (failure != null) return failure;
106
+ } else if (typeof value === "string") {
107
+ const failure = addBytes(statistics, encodedLength(JSON.stringify(value)), limits, current.path);
108
+ if (failure != null) return failure;
109
+ } else if (typeof value === "number") {
110
+ if (!Number.isFinite(value)) return {
111
+ status: "unsupported",
112
+ reason: {
113
+ type: "invalidJsonTree",
114
+ path: current.path
115
+ }
116
+ };
117
+ const failure = addBytes(statistics, encodedLength(JSON.stringify(value)), limits, current.path);
118
+ if (failure != null) return failure;
119
+ } else if (Array.isArray(value)) {
120
+ if (seen.has(value) || !hasOnlyJsonArrayProperties(value)) return {
121
+ status: "unsupported",
122
+ reason: {
123
+ type: "invalidJsonTree",
124
+ path: current.path
125
+ }
126
+ };
127
+ seen.add(value);
128
+ const failure = addBytes(statistics, 2 + Math.max(0, value.length - 1), limits, current.path);
129
+ if (failure != null) return failure;
130
+ for (let index = value.length - 1; index >= 0; index--) pending.push({
131
+ value: value[index],
132
+ path: childPath(current.path, String(index)),
133
+ depth: current.depth + 1,
134
+ insideProof: current.insideProof,
135
+ insideContext: current.insideContext
136
+ });
137
+ } else if (isJsonMap(value)) {
138
+ const prototype = Object.getPrototypeOf(value);
139
+ if (seen.has(value) || !hasOnlyDataProperties(value) || prototype !== Object.prototype && prototype !== null) return {
140
+ status: "unsupported",
141
+ reason: {
142
+ type: "invalidJsonTree",
143
+ path: current.path
144
+ }
145
+ };
146
+ seen.add(value);
147
+ statistics.mapCount++;
148
+ if (statistics.mapCount > limits.maxMaps) return limitExceeded("maps", limits.maxMaps, statistics.mapCount, current.path);
149
+ const entries = Object.entries(value).sort(([left], [right]) => comparePaths(left, right));
150
+ let objectBytes = 2 + Math.max(0, entries.length - 1);
151
+ for (const [key] of entries) objectBytes += encodedLength(JSON.stringify(key)) + 1;
152
+ const failure = addBytes(statistics, objectBytes, limits, current.path);
153
+ if (failure != null) return failure;
154
+ const hasDirectProof = !current.insideProof && !current.insideContext && Object.hasOwn(value, "proof");
155
+ if (hasDirectProof) {
156
+ statistics.proofCount++;
157
+ if (statistics.proofCount > limits.maxProofs) return limitExceeded("proofs", limits.maxProofs, statistics.proofCount, childPath(current.path, "proof"));
158
+ if (!isJsonMap(value.proof)) return {
159
+ status: "unsupported",
160
+ reason: {
161
+ type: "unsupportedProofShape",
162
+ path: childPath(current.path, "proof")
163
+ }
164
+ };
165
+ }
166
+ for (let index = entries.length - 1; index >= 0; index--) {
167
+ const [key, child] = entries[index];
168
+ pending.push({
169
+ value: child,
170
+ path: childPath(current.path, key),
171
+ depth: current.depth + 1,
172
+ insideProof: current.insideProof || hasDirectProof && key === "proof",
173
+ insideContext: current.insideContext || key === "@context"
174
+ });
175
+ }
176
+ } else return {
177
+ status: "unsupported",
178
+ reason: {
179
+ type: "invalidJsonTree",
180
+ path: current.path
181
+ }
182
+ };
183
+ }
184
+ return statistics;
185
+ }
186
+ function freezeJsonTree(root) {
187
+ const pending = [root];
188
+ while (pending.length > 0) {
189
+ const value = pending.pop();
190
+ if (typeof value !== "object" || value == null) continue;
191
+ if (Array.isArray(value)) for (const child of value) pending.push(child);
192
+ else for (const child of Object.values(value)) pending.push(child);
193
+ Object.freeze(value);
194
+ }
195
+ }
196
+ function collectDocuments(snapshot) {
197
+ const documents = [];
198
+ const pending = [{
199
+ value: snapshot,
200
+ path: "",
201
+ depth: 0
202
+ }];
203
+ while (pending.length > 0) {
204
+ const current = pending.pop();
205
+ if (Array.isArray(current.value)) {
206
+ for (let index = current.value.length - 1; index >= 0; index--) pending.push({
207
+ value: current.value[index],
208
+ path: childPath(current.path, String(index)),
209
+ depth: current.depth + 1
210
+ });
211
+ continue;
212
+ }
213
+ if (!isCompoundProofJsonObject(current.value)) continue;
214
+ const document = current.value;
215
+ if (Object.hasOwn(document, "proof")) {
216
+ const proof = document.proof;
217
+ const id = typeof document.id === "string" ? document.id : typeof document["@id"] === "string" ? document["@id"] : void 0;
218
+ documents.push(Object.freeze({
219
+ path: current.path,
220
+ id,
221
+ depth: current.depth,
222
+ securedDocument: document,
223
+ proof
224
+ }));
225
+ }
226
+ const entries = Object.entries(document).sort(([left], [right]) => comparePaths(left, right));
227
+ for (let index = entries.length - 1; index >= 0; index--) {
228
+ const [key, value] = entries[index];
229
+ if (key === "proof" || key === "@context") continue;
230
+ pending.push({
231
+ value,
232
+ path: childPath(current.path, key),
233
+ depth: current.depth + 1
234
+ });
235
+ }
236
+ }
237
+ documents.sort((left, right) => right.depth - left.depth || comparePaths(left.path, right.path));
238
+ return documents;
239
+ }
240
+ function collectPortableObjects(snapshot) {
241
+ const objects = [];
242
+ const pending = [{
243
+ value: snapshot,
244
+ path: "",
245
+ depth: 0
246
+ }];
247
+ while (pending.length > 0) {
248
+ const current = pending.pop();
249
+ if (Array.isArray(current.value)) {
250
+ for (let index = current.value.length - 1; index >= 0; index--) pending.push({
251
+ value: current.value[index],
252
+ path: childPath(current.path, String(index)),
253
+ depth: current.depth + 1
254
+ });
255
+ continue;
256
+ }
257
+ if (!isCompoundProofJsonObject(current.value)) continue;
258
+ const document = current.value;
259
+ const id = [document.id, document["@id"]].find((value) => typeof value === "string" && PORTABLE_OBJECT_ID_PATTERN.test(value));
260
+ if (typeof id === "string") objects.push(Object.freeze({
261
+ path: current.path,
262
+ id,
263
+ depth: current.depth,
264
+ document
265
+ }));
266
+ const entries = Object.entries(document).sort(([left], [right]) => comparePaths(left, right));
267
+ for (let index = entries.length - 1; index >= 0; index--) {
268
+ const [key, value] = entries[index];
269
+ if (key === "proof" || key === "@context") continue;
270
+ pending.push({
271
+ value,
272
+ path: childPath(current.path, key),
273
+ depth: current.depth + 1
274
+ });
275
+ }
276
+ }
277
+ objects.sort((left, right) => right.depth - left.depth || comparePaths(left.path, right.path));
278
+ return objects;
279
+ }
280
+ /**
281
+ * Determines whether a received JSON tree contains a portable object ID
282
+ * outside a proof or context definition, without exceeding discovery limits.
283
+ *
284
+ * This is only an applicability check. It does not authenticate the input;
285
+ * callers must still use {@link verifyCompoundPortableObjectProofs} to obtain
286
+ * an atomic result from an immutable snapshot. `indeterminate` means the
287
+ * applicability scan itself reached a limit, so a caller must not treat the
288
+ * document as outside the compound profile.
289
+ *
290
+ * @internal
291
+ */
292
+ function inspectCompoundPortableObjectApplicability(json, limits) {
293
+ validateLimits(limits);
294
+ let byteLength = 0;
295
+ let mapCount = 0;
296
+ const pending = [{
297
+ iterator: [json].values(),
298
+ depth: 0
299
+ }];
300
+ const addByteLength = (length) => {
301
+ byteLength += length;
302
+ return byteLength <= limits.maxBytes;
303
+ };
304
+ while (pending.length > 0) {
305
+ const frame = pending[pending.length - 1];
306
+ const next = frame.iterator.next();
307
+ if (next.done) {
308
+ pending.pop();
309
+ if (byteLength > limits.maxBytes) return "indeterminate";
310
+ continue;
311
+ }
312
+ const value = next.value;
313
+ if (frame.depth > limits.maxDepth) return "indeterminate";
314
+ if (value === null) {
315
+ if (!addByteLength(4)) return "indeterminate";
316
+ } else if (typeof value === "boolean") {
317
+ if (!addByteLength(value ? 4 : 5)) return "indeterminate";
318
+ } else if (typeof value === "string" || typeof value === "number") {
319
+ if (!addByteLength(encodedLength(JSON.stringify(value)))) return "indeterminate";
320
+ } else if (Array.isArray(value)) {
321
+ if (!addByteLength(2 + Math.max(0, value.length - 1))) return "indeterminate";
322
+ pending.push({
323
+ iterator: value.values(),
324
+ depth: frame.depth + 1
325
+ });
326
+ } else if (isJsonMap(value)) {
327
+ mapCount++;
328
+ if (mapCount > limits.maxMaps) return "indeterminate";
329
+ if ([value.id, value["@id"]].some((id) => typeof id === "string" && PORTABLE_OBJECT_ID_PATTERN.test(id))) return "present";
330
+ if (!addByteLength(2)) return "indeterminate";
331
+ const children = function* () {
332
+ let first = true;
333
+ for (const key in value) {
334
+ if (!Object.hasOwn(value, key)) continue;
335
+ if (key === "proof" || key === "@context") continue;
336
+ if (!first && !addByteLength(1)) return;
337
+ first = false;
338
+ if (!addByteLength(encodedLength(JSON.stringify(key)) + 1)) return;
339
+ yield value[key];
340
+ }
341
+ }();
342
+ pending.push({
343
+ iterator: children,
344
+ depth: frame.depth + 1
345
+ });
346
+ }
347
+ if (byteLength > limits.maxBytes) return "indeterminate";
348
+ }
349
+ return "absent";
350
+ }
351
+ /**
352
+ * Discovers direct literal proof-bearing maps in an immutable JSON snapshot.
353
+ *
354
+ * Discovery is bounded and atomic. Unsupported proof shapes, non-JSON input,
355
+ * or a resource-limit failure return no partial candidate list. Proof
356
+ * configuration subtrees are validated and counted as JSON, but are not
357
+ * themselves searched for secured documents.
358
+ */
359
+ function discoverCompoundProofDocuments(json, limits) {
360
+ validateLimits(limits);
361
+ let inspected;
362
+ try {
363
+ inspected = inspectJsonTree(json, limits);
364
+ } catch {
365
+ return {
366
+ status: "unsupported",
367
+ reason: {
368
+ type: "invalidJsonTree",
369
+ path: ""
370
+ }
371
+ };
372
+ }
373
+ if ("status" in inspected) return inspected;
374
+ let snapshot;
375
+ try {
376
+ snapshot = structuredClone(json);
377
+ } catch {
378
+ return {
379
+ status: "unsupported",
380
+ reason: {
381
+ type: "invalidJsonTree",
382
+ path: ""
383
+ }
384
+ };
385
+ }
386
+ freezeJsonTree(snapshot);
387
+ return {
388
+ status: "ok",
389
+ snapshot,
390
+ documents: Object.freeze(collectDocuments(snapshot)),
391
+ statistics: Object.freeze({ ...inspected })
392
+ };
393
+ }
394
+ /**
395
+ * Verifies every direct literal proof found in one immutable JSON snapshot.
396
+ *
397
+ * Each current map is verified independently. Only its literal `proof`
398
+ * member is removed from its JCS input, so descendant proofs and proof aliases
399
+ * remain unchanged. This is the lower-level compound-document mechanism; it
400
+ * does not apply portable-object policy or authenticate an inbox activity.
401
+ *
402
+ * @internal
403
+ */
404
+ async function verifyCompoundProofDocuments(json, limits, options = {}) {
405
+ const discovered = discoverCompoundProofDocuments(json, limits);
406
+ if (discovered.status !== "ok") return discovered;
407
+ const documents = await verifyDiscoveredProofDocuments(discovered, options);
408
+ return {
409
+ status: "ok",
410
+ verified: documents.length > 0 && documents.every((document) => document.verified),
411
+ snapshot: discovered.snapshot,
412
+ documents,
413
+ statistics: discovered.statistics
414
+ };
415
+ }
416
+ async function verifyDiscoveredProofDocuments(discovered, options) {
417
+ const documents = await Promise.all(discovered.documents.map(async (document) => {
418
+ const metadata = {
419
+ path: document.path,
420
+ ...document.id == null ? {} : { id: document.id },
421
+ depth: document.depth
422
+ };
423
+ if (document.depth > 0 && !Object.hasOwn(document.securedDocument, "@context")) return Object.freeze({
424
+ ...metadata,
425
+ verified: false,
426
+ reason: { type: "missingContext" }
427
+ });
428
+ const key = await verifyMapLocalProof(document.securedDocument, options);
429
+ return key == null ? Object.freeze({
430
+ ...metadata,
431
+ verified: false,
432
+ reason: { type: "invalidProof" }
433
+ }) : Object.freeze({
434
+ ...metadata,
435
+ verified: true,
436
+ key
437
+ });
438
+ }));
439
+ return Object.freeze(documents);
440
+ }
441
+ /**
442
+ * Applies FEP-ef61 portable-object policy to every portable map in a compound
443
+ * snapshot without changing the map-local cryptographic inputs.
444
+ *
445
+ * @internal
446
+ */
447
+ async function verifyCompoundPortableObjectProofs(json, limits, options = {}) {
448
+ const discovered = discoverCompoundProofDocuments(json, limits);
449
+ if (discovered.status !== "ok") return discovered;
450
+ const proofs = await verifyDiscoveredProofDocuments(discovered, options);
451
+ const proofByPath = new Map(proofs.map((proof) => [proof.path, proof]));
452
+ const portableObjects = await Promise.all(collectPortableObjects(discovered.snapshot).map(async (object) => {
453
+ const metadata = {
454
+ path: object.path,
455
+ id: object.id,
456
+ depth: object.depth
457
+ };
458
+ if (object.depth > 0 && !Object.hasOwn(object.document, "@context")) return Object.freeze({
459
+ ...metadata,
460
+ verified: false,
461
+ reason: { type: "missingContext" }
462
+ });
463
+ const proof = proofByPath.get(object.path);
464
+ const key = proof?.verified === true ? proof.key : null;
465
+ try {
466
+ const policy = await verifyPortableObjectProofPolicy(object.document, key, options);
467
+ return policy.verified ? Object.freeze({
468
+ ...metadata,
469
+ id: policy.objectId,
470
+ verified: true,
471
+ keys: policy.keys
472
+ }) : Object.freeze({
473
+ ...metadata,
474
+ verified: false,
475
+ reason: policy.reason
476
+ });
477
+ } catch {
478
+ return Object.freeze({
479
+ ...metadata,
480
+ verified: false,
481
+ reason: { type: "invalidPortableObject" }
482
+ });
483
+ }
484
+ }));
485
+ return {
486
+ status: "ok",
487
+ verified: portableObjects.length > 0 && proofs.every((proof) => proof.verified) && portableObjects.every((object) => object.verified),
488
+ snapshot: discovered.snapshot,
489
+ proofs,
490
+ portableObjects: Object.freeze(portableObjects),
491
+ statistics: discovered.statistics
492
+ };
493
+ }
494
+ //#endregion
495
+ export { verifyCompoundProofDocuments as i, inspectCompoundPortableObjectApplicability as n, verifyCompoundPortableObjectProofs as r, discoverCompoundProofDocuments as t };
@@ -3,6 +3,6 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  //#region deno.json
5
5
  var name = "@fedify/fedify";
6
- var version = "2.4.0-dev.1988+c5c9d617";
6
+ var version = "2.4.0-dev.1995+618fd4e7";
7
7
  //#endregion
8
8
  export { version as n, name as t };
@@ -1,8 +1,8 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { s as validateCryptoKey } from "./key-Cwbg5ggV.mjs";
5
- import { n as doubleKnock } from "./http-CtidZS_t.mjs";
4
+ import { s as validateCryptoKey } from "./key-Ccs8cnd7.mjs";
5
+ import { n as doubleKnock } from "./http-D9urSO2D.mjs";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  import { curry } from "es-toolkit";
8
8
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -6,7 +6,7 @@ import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
6
6
  import { t as assertExists } from "../assert_exists-DtzkXC47.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-BJ5wuvR2.mjs";
8
8
  import "../std__assert-CxFT0MNt.mjs";
9
- import { r as createFederationBuilder } from "../builder-Cts78G9N.mjs";
9
+ import { r as createFederationBuilder } from "../builder-D0DxgOV5.mjs";
10
10
  import { DisallowedOperatorError, DisallowedVarSpecModifierError, DuplicateRouteVariableError, RouteTemplateOptionsNotMatchedError, RouterError } from "@fedify/uri-template";
11
11
  import { Activity, Note, Person } from "@fedify/vocab";
12
12
  import { test } from "@fedify/fixture";
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";