@fedify/fedify 2.1.12 → 2.1.14

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 (96) hide show
  1. package/dist/{builder-D9hlyCx5.mjs → builder-BBifZZ5G.mjs} +3 -3
  2. package/dist/{chunk-nlSIicah.js → chunk-CRNNMoPX.js} +2 -2
  3. package/dist/{client-z-8dc-e1.d.cts → client-CAM_bQXx.d.cts} +1 -0
  4. package/dist/{client-AtlibPOU.d.ts → client-CSddvgWN.d.ts} +1 -2
  5. package/dist/compat/mod.d.cts +2 -1
  6. package/dist/compat/mod.d.ts +2 -3
  7. package/dist/compat/mod.js +3 -3
  8. package/dist/compat/transformers.test.mjs +1 -1
  9. package/dist/{context-C0fssarc.d.ts → context-_l9t359k.d.ts} +53 -12
  10. package/dist/{context-LmrZPwti.d.cts → context-o22vjzS2.d.cts} +53 -10
  11. package/dist/{deno-Ddb3P7G7.mjs → deno-bqnW1QlD.mjs} +1 -1
  12. package/dist/{docloader-CK8tewt1.mjs → docloader-D-Fu0kBF.mjs} +2 -2
  13. package/dist/federation/builder.test.mjs +1 -1
  14. package/dist/federation/handler.test.mjs +1361 -41
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/inbox.test.mjs +1 -1
  17. package/dist/federation/middleware.test.mjs +1588 -84
  18. package/dist/federation/mod.cjs +1 -1
  19. package/dist/federation/mod.d.cts +4 -3
  20. package/dist/federation/mod.d.ts +4 -5
  21. package/dist/federation/mod.js +2 -2
  22. package/dist/federation/retry.test.mjs +1 -1
  23. package/dist/federation/send.test.mjs +3 -3
  24. package/dist/federation/temporal.test.d.mts +2 -0
  25. package/dist/federation/temporal.test.mjs +71 -0
  26. package/dist/federation/webfinger.test.mjs +1 -1
  27. package/dist/{http-CrGuipxe.d.cts → http-BDZeS5om.d.ts} +2 -1
  28. package/dist/{http-aQzN9Ayi.d.ts → http-C87EWkO0.d.cts} +2 -3
  29. package/dist/{http-CmDErAnD.cjs → http-CEXtUHix.cjs} +57 -9
  30. package/dist/{http-qKyJKSnF.js → http-Cw1EorUA.js} +58 -10
  31. package/dist/{http-DRDpStn2.mjs → http-DvhFwy2E.mjs} +58 -10
  32. package/dist/{inbox-DTuPJEma.mjs → inbox-7b3VYnec.mjs} +7 -4
  33. package/dist/{key-WSedbAA-.mjs → key-B3OBz6A_.mjs} +1 -1
  34. package/dist/{kv-CbLNp3zQ.d.cts → kv-D6hNiMTK.d.ts} +1 -0
  35. package/dist/{kv-cache-9cdQDeT0.cjs → kv-cache-BIapFiSV.cjs} +2 -2
  36. package/dist/{kv-cache-DNNRFY8u.js → kv-cache-C6nynGhh.js} +2 -2
  37. package/dist/{kv-cache-B01V7s3h.mjs → kv-cache-FsT1ljhs.mjs} +1 -1
  38. package/dist/{kv-GFYnFoOl.d.ts → kv-gJ8LYbxX.d.cts} +1 -3
  39. package/dist/ld-DTxYKZTT.mjs +550 -0
  40. package/dist/{middleware-UThUK30x.js → middleware-0vceVN10.js} +407 -82
  41. package/dist/{middleware-DFcgN1cH.cjs → middleware-BcbU5lKS.cjs} +406 -80
  42. package/dist/{middleware-8P6Z15Wq.cjs → middleware-DUT--Qen.cjs} +1 -1
  43. package/dist/{middleware-DDsnRvFC.mjs → middleware-DmT9t0BJ.mjs} +317 -84
  44. package/dist/{middleware-C2c1rlmE.mjs → middleware-Li_g_vqz.mjs} +1 -1
  45. package/dist/{mod-CnwZoDzx.d.ts → mod-0dF0OeGw.d.cts} +2 -3
  46. package/dist/{mod-B505FZBC.d.cts → mod-BTWFtZwa.d.ts} +4 -3
  47. package/dist/{mod-Cgpc49fA.d.cts → mod-Bv1elC-b.d.ts} +2 -1
  48. package/dist/{mod-DoJBjjnO.d.cts → mod-CjiK2zrW.d.ts} +3 -2
  49. package/dist/{mod-DvxszxXC.d.ts → mod-D5YlzzP3.d.cts} +3 -4
  50. package/dist/{mod-D7PAuO6k.d.ts → mod-dxOnKp2Y.d.cts} +4 -5
  51. package/dist/mod.cjs +4 -4
  52. package/dist/mod.d.cts +9 -8
  53. package/dist/mod.d.ts +9 -10
  54. package/dist/mod.js +9 -9
  55. package/dist/nodeinfo/handler.test.mjs +1 -1
  56. package/dist/nodeinfo/mod.d.cts +2 -1
  57. package/dist/nodeinfo/mod.d.ts +2 -3
  58. package/dist/nodeinfo/mod.js +3 -3
  59. package/dist/otel/mod.d.cts +2 -1
  60. package/dist/otel/mod.d.ts +2 -3
  61. package/dist/otel/mod.js +2 -2
  62. package/dist/{owner-CptqhsOy.d.cts → owner-CnngXDNJ.d.ts} +2 -1
  63. package/dist/{owner-74ARJ5TL.d.ts → owner-DEvZuyOE.d.cts} +2 -3
  64. package/dist/{owner-BceqCVOs.mjs → owner-DzcnuWYo.mjs} +2 -2
  65. package/dist/{proof-4NUQlbQV.js → proof-CtTT8A7y.js} +299 -5
  66. package/dist/{proof-BojC8L94.mjs → proof-DmVGi7mI.mjs} +2 -2
  67. package/dist/{proof-kuTIVfyZ.cjs → proof-JEoW3ODq.cjs} +345 -3
  68. package/dist/runtime/mod.d.cts +1 -0
  69. package/dist/runtime/mod.d.ts +1 -2
  70. package/dist/runtime/mod.js +3 -3
  71. package/dist/{send-Buz5Gy8x.mjs → send-5ulOKVCW.mjs} +2 -2
  72. package/dist/sig/http.test.mjs +120 -2
  73. package/dist/sig/key.test.mjs +1 -1
  74. package/dist/sig/ld.test.mjs +558 -2
  75. package/dist/sig/mod.cjs +2 -2
  76. package/dist/sig/mod.d.cts +4 -3
  77. package/dist/sig/mod.d.ts +4 -5
  78. package/dist/sig/mod.js +4 -4
  79. package/dist/sig/owner.test.mjs +1 -1
  80. package/dist/sig/proof.test.mjs +1 -1
  81. package/dist/temporal-CmJkd-25.mjs +95 -0
  82. package/dist/testing/mod.d.mts +48 -6
  83. package/dist/{transformers-ve6e2xcg.js → transformers-BGMIq1cs.js} +2 -2
  84. package/dist/{types-hvL8ElAs.js → types-CAY3OdLq.js} +2 -2
  85. package/dist/utils/docloader.test.mjs +2 -2
  86. package/dist/utils/kv-cache.test.mjs +1 -1
  87. package/dist/utils/mod.cjs +1 -1
  88. package/dist/utils/mod.d.cts +2 -1
  89. package/dist/utils/mod.d.ts +2 -3
  90. package/dist/utils/mod.js +3 -3
  91. package/dist/vocab/mod.d.cts +1 -0
  92. package/dist/vocab/mod.d.ts +1 -2
  93. package/dist/vocab/mod.js +2 -2
  94. package/package.json +7 -7
  95. package/dist/ld-OBpaLfHR.mjs +0 -256
  96. /package/dist/{retry-B_E3V_Dx.mjs → retry-CJL0poaU.mjs} +0 -0
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-CmDErAnD.cjs");
4
+ const require_http = require("./http-CEXtUHix.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let _fedify_vocab = require("@fedify/vocab");
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -18,6 +18,288 @@ const logger$1 = (0, _logtape_logtape.getLogger)([
18
18
  "sig",
19
19
  "ld"
20
20
  ]);
21
+ const localContext = [
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
+ const localContextUrls = new Set(localContext);
28
+ const builtInContextLoader = (0, _fedify_vocab_runtime.getDocumentLoader)();
29
+ const disallowedJsonLdKeywords = new Set([
30
+ "@graph",
31
+ "@included",
32
+ "@reverse"
33
+ ]);
34
+ /** @internal */
35
+ var UnsafeJsonLdError = class extends TypeError {
36
+ constructor(keyword) {
37
+ super(`Unsupported JSON-LD keyword: ${keyword}.`);
38
+ this.keyword = keyword;
39
+ this.name = "UnsafeJsonLdError";
40
+ }
41
+ };
42
+ /** @internal */
43
+ var InvalidContextReferenceError = class extends TypeError {
44
+ constructor(reference) {
45
+ super(`Invalid JSON-LD context reference: ${reference}.`);
46
+ this.reference = reference;
47
+ this.name = "InvalidContextReferenceError";
48
+ }
49
+ };
50
+ function createLoadingRemoteContextFailedError(reference, cause) {
51
+ const message = cause instanceof Error ? cause.message : String(cause);
52
+ const error = /* @__PURE__ */ new Error(`Dereferencing a URL did not result in a valid JSON-LD context: ${reference}. ${message}`);
53
+ error.name = "jsonld.InvalidUrl";
54
+ error.details = {
55
+ code: "loading remote context failed",
56
+ url: reference
57
+ };
58
+ error.cause = cause;
59
+ return error;
60
+ }
61
+ /** @internal */
62
+ function isClearlyMalformedContextReference(reference) {
63
+ for (const char of reference) {
64
+ const code = char.charCodeAt(0);
65
+ if (code <= 32 || code === 127) return true;
66
+ }
67
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(reference) && !URL.canParse(reference)) return true;
68
+ for (let i = 0; i < reference.length; i++) {
69
+ if (reference[i] !== "%") continue;
70
+ if (i + 2 >= reference.length || !/[0-9A-Fa-f]/.test(reference[i + 1]) || !/[0-9A-Fa-f]/.test(reference[i + 2])) return true;
71
+ i += 2;
72
+ }
73
+ if (reference.startsWith("./") || reference.startsWith("../") || reference.startsWith("/") || reference.startsWith("//")) {
74
+ for (const char of reference) if ("[]<>\"\\^`{|}".includes(char)) return true;
75
+ }
76
+ return false;
77
+ }
78
+ function cloneRemoteDocument(remoteDocument) {
79
+ return structuredClone(remoteDocument);
80
+ }
81
+ function createMemoizedDocumentLoader(documentLoader) {
82
+ const cache = /* @__PURE__ */ new Map();
83
+ return async (url, options) => {
84
+ const cacheKey = URL.canParse(url) ? new URL(url).href : url;
85
+ let remoteDocument = cache.get(cacheKey);
86
+ if (remoteDocument == null) {
87
+ remoteDocument = Promise.resolve(documentLoader(url, options)).then(cloneRemoteDocument);
88
+ remoteDocument.catch(() => {
89
+ if (cache.get(cacheKey) === remoteDocument) cache.delete(cacheKey);
90
+ });
91
+ cache.set(cacheKey, remoteDocument);
92
+ }
93
+ return cloneRemoteDocument(await remoteDocument);
94
+ };
95
+ }
96
+ /** @internal */
97
+ function wrapContextLoaderForJsonLd(contextLoader) {
98
+ const loader = contextLoader ?? builtInContextLoader;
99
+ return async (url, options) => {
100
+ try {
101
+ return await loader(url, options);
102
+ } catch (error) {
103
+ if (!isInvalidUrlTypeError(error)) throw error;
104
+ if (isClearlyMalformedContextReference(url)) throw new InvalidContextReferenceError(url);
105
+ throw createLoadingRemoteContextFailedError(url, error);
106
+ }
107
+ };
108
+ }
109
+ /** @internal */
110
+ function getNormalizationContextLoader(contextLoader) {
111
+ const loader = wrapContextLoaderForJsonLd(contextLoader);
112
+ return createMemoizedDocumentLoader(async (url, options) => {
113
+ if (URL.canParse(url)) {
114
+ const normalizedUrl = new URL(url).href;
115
+ if (localContextUrls.has(normalizedUrl)) return await builtInContextLoader(normalizedUrl, options);
116
+ }
117
+ return await loader(url, options);
118
+ });
119
+ }
120
+ /** @internal */
121
+ async function compactJsonLd(jsonLd, contextLoader) {
122
+ const hasLds = typeof jsonLd === "object" && jsonLd != null && "signature" in jsonLd;
123
+ const signature = hasLds ? jsonLd.signature : void 0;
124
+ const normalizationContextLoader = getNormalizationContextLoader(contextLoader);
125
+ const document = hasLds ? detachSignature(jsonLd) : jsonLd;
126
+ await assertNoGraphBeforeCompaction(document, normalizationContextLoader);
127
+ const compacted = await _fedify_vocab_runtime_jsonld.default.compact(document, localContext, { documentLoader: normalizationContextLoader });
128
+ if (hasLds && typeof compacted === "object" && compacted != null) compacted.signature = signature;
129
+ assertSafeJsonLd(compacted);
130
+ return compacted;
131
+ }
132
+ function createInvalidRemoteContextError(reference) {
133
+ const error = /* @__PURE__ */ new Error(`Dereferencing a URL did not result in a JSON object. The response was valid JSON, but it was not a JSON object. URL: "${reference}".`);
134
+ error.name = "jsonld.InvalidUrl";
135
+ error.details = {
136
+ code: "invalid remote context",
137
+ url: reference
138
+ };
139
+ return error;
140
+ }
141
+ function getRemoteContext(remoteDocument, reference) {
142
+ const { contextUrl, documentUrl } = remoteDocument;
143
+ let { document } = remoteDocument;
144
+ if (typeof document === "string") document = JSON.parse(document);
145
+ if (typeof document !== "object" || document == null || Array.isArray(document)) throw createInvalidRemoteContextError(reference);
146
+ let context = "@context" in document ? document["@context"] : {};
147
+ if (contextUrl != null) context = Array.isArray(context) ? [...context, contextUrl] : [context, contextUrl];
148
+ return {
149
+ context,
150
+ baseUrl: documentUrl ?? reference
151
+ };
152
+ }
153
+ function createGraphAliasContextState() {
154
+ return {
155
+ graphTerms: /* @__PURE__ */ new Set(),
156
+ jsonTerms: /* @__PURE__ */ new Set(),
157
+ propertyContexts: /* @__PURE__ */ new Map(),
158
+ termTargets: /* @__PURE__ */ new Map()
159
+ };
160
+ }
161
+ function cloneGraphAliasContextState(state) {
162
+ return {
163
+ graphTerms: new Set(state.graphTerms),
164
+ jsonTerms: new Set(state.jsonTerms),
165
+ propertyContexts: new Map(state.propertyContexts),
166
+ termTargets: new Map(state.termTargets)
167
+ };
168
+ }
169
+ function resolveContextTarget(target, state) {
170
+ if (target === "@graph") return target;
171
+ const mapped = state.termTargets.get(target);
172
+ if (mapped == null) return target;
173
+ return mapped;
174
+ }
175
+ function getDirectContextTarget(definition) {
176
+ if (definition === null) return null;
177
+ if (typeof definition === "string") return definition;
178
+ if (typeof definition === "object" && definition != null && "@id" in definition) {
179
+ const id = definition["@id"];
180
+ if (id === null) return null;
181
+ if (typeof id === "string") return id;
182
+ }
183
+ }
184
+ function isJsonTypedDefinition(definition) {
185
+ return typeof definition === "object" && definition != null && "@type" in definition && definition["@type"] === "@json";
186
+ }
187
+ function resolveLocalContextTarget(target, state, localTargets, seen = /* @__PURE__ */ new Set()) {
188
+ if (target === "@graph") return target;
189
+ if (seen.has(target)) return target;
190
+ seen.add(target);
191
+ if (localTargets.has(target)) {
192
+ const localTarget = localTargets.get(target);
193
+ return localTarget == null ? target : resolveLocalContextTarget(localTarget, state, localTargets, seen);
194
+ }
195
+ return resolveContextTarget(target, state);
196
+ }
197
+ function refreshGraphAliases(state) {
198
+ state.graphTerms.clear();
199
+ for (const [term, target] of state.termTargets) if (target === "@graph") state.graphTerms.add(term);
200
+ }
201
+ function normalizeContextReference(reference, baseUrl) {
202
+ if (baseUrl != null) return new URL(reference, baseUrl).href;
203
+ return URL.canParse(reference) ? new URL(reference).href : reference;
204
+ }
205
+ /** @internal */
206
+ function isInvalidUrlTypeError(error) {
207
+ const code = error.code;
208
+ return error instanceof TypeError && (code === "ERR_INVALID_URL" || /^Invalid URL(?::|$)/.test(error.message) || / cannot be parsed as a URL\.?$/.test(error.message));
209
+ }
210
+ async function applyGraphAliasContext(state, context, documentLoader, remoteContextCache, baseUrl = null, processingContexts = /* @__PURE__ */ new Set()) {
211
+ if (context === null) return createGraphAliasContextState();
212
+ let nextState = cloneGraphAliasContextState(state);
213
+ if (Array.isArray(context)) {
214
+ for (const item of context) nextState = await applyGraphAliasContext(nextState, item, documentLoader, remoteContextCache, baseUrl, processingContexts);
215
+ return nextState;
216
+ }
217
+ if (typeof context === "string") {
218
+ const reference = normalizeContextReference(context, baseUrl);
219
+ const cacheKey = `${baseUrl ?? ""}\n${reference}`;
220
+ if (processingContexts.has(cacheKey)) return nextState;
221
+ processingContexts.add(cacheKey);
222
+ try {
223
+ let remoteContext = remoteContextCache.get(cacheKey);
224
+ if (remoteContext == null) {
225
+ remoteContext = (async () => {
226
+ try {
227
+ return getRemoteContext(await documentLoader(reference), reference);
228
+ } catch (error) {
229
+ if (reference === context && isInvalidUrlTypeError(error) && isClearlyMalformedContextReference(context)) throw new InvalidContextReferenceError(context);
230
+ throw error;
231
+ }
232
+ })();
233
+ remoteContextCache.set(cacheKey, remoteContext);
234
+ }
235
+ const loadedRemoteContext = await remoteContext;
236
+ return await applyGraphAliasContext(nextState, loadedRemoteContext.context, documentLoader, remoteContextCache, loadedRemoteContext.baseUrl, processingContexts);
237
+ } finally {
238
+ processingContexts.delete(cacheKey);
239
+ }
240
+ }
241
+ if (typeof context === "object" && context != null) {
242
+ if ("@import" in context && typeof context["@import"] === "string") nextState = await applyGraphAliasContext(nextState, context["@import"], documentLoader, remoteContextCache, baseUrl, processingContexts);
243
+ const localTargets = /* @__PURE__ */ new Map();
244
+ for (const [term, definition] of globalThis.Object.entries(context)) {
245
+ if (term.startsWith("@")) continue;
246
+ const target = getDirectContextTarget(definition);
247
+ if (target == null) localTargets.set(term, null);
248
+ else if (typeof target === "string") localTargets.set(term, target);
249
+ else localTargets.delete(term);
250
+ }
251
+ for (const [term, definition] of globalThis.Object.entries(context)) {
252
+ if (term.startsWith("@")) continue;
253
+ if (localTargets.has(term)) {
254
+ const directTarget = localTargets.get(term);
255
+ if (directTarget == null) nextState.termTargets.set(term, null);
256
+ else nextState.termTargets.set(term, resolveLocalContextTarget(directTarget, nextState, localTargets));
257
+ } else nextState.termTargets.delete(term);
258
+ if (typeof definition === "object" && definition != null && "@context" in definition) nextState.propertyContexts.set(term, {
259
+ context: definition["@context"],
260
+ baseUrl
261
+ });
262
+ else nextState.propertyContexts.delete(term);
263
+ if (isJsonTypedDefinition(definition)) nextState.jsonTerms.add(term);
264
+ else nextState.jsonTerms.delete(term);
265
+ }
266
+ refreshGraphAliases(nextState);
267
+ }
268
+ return nextState;
269
+ }
270
+ async function assertNoGraphBeforeCompaction(jsonLd, documentLoader, inheritedState = createGraphAliasContextState(), propertyContext, remoteContextCache = /* @__PURE__ */ new Map()) {
271
+ if (Array.isArray(jsonLd)) {
272
+ for (const item of jsonLd) await assertNoGraphBeforeCompaction(item, documentLoader, inheritedState, propertyContext, remoteContextCache);
273
+ return;
274
+ }
275
+ if (typeof jsonLd !== "object" || jsonLd == null) return;
276
+ const jsonLiteralWrapper = isJsonLiteralWrapper(jsonLd);
277
+ let state = inheritedState;
278
+ if (propertyContext !== void 0) state = await applyGraphAliasContext(state, propertyContext.context, documentLoader, remoteContextCache, propertyContext.baseUrl);
279
+ if ("@context" in jsonLd) state = await applyGraphAliasContext(state, jsonLd["@context"], documentLoader, remoteContextCache);
280
+ for (const [key, value] of globalThis.Object.entries(jsonLd)) {
281
+ if (key === "@context") continue;
282
+ if (jsonLiteralWrapper && key === "@value") continue;
283
+ if (key === "@graph" || state.graphTerms.has(key)) throw new UnsafeJsonLdError("@graph");
284
+ if (state.jsonTerms.has(key)) continue;
285
+ await assertNoGraphBeforeCompaction(value, documentLoader, state, state.propertyContexts.get(key), remoteContextCache);
286
+ }
287
+ }
288
+ function isJsonLiteralWrapper(value) {
289
+ return "@value" in value && (value["@type"] === "@json" || value.type === "@json");
290
+ }
291
+ /** @internal */
292
+ function assertSafeJsonLd(jsonLd) {
293
+ if (Array.isArray(jsonLd)) for (const item of jsonLd) assertSafeJsonLd(item);
294
+ else if (typeof jsonLd === "object" && jsonLd != null) {
295
+ const jsonLiteralWrapper = isJsonLiteralWrapper(jsonLd);
296
+ for (const [key, value] of globalThis.Object.entries(jsonLd)) {
297
+ if (disallowedJsonLdKeywords.has(key)) throw new UnsafeJsonLdError(key);
298
+ if (jsonLiteralWrapper && key === "@value") continue;
299
+ assertSafeJsonLd(value);
300
+ }
301
+ }
302
+ }
21
303
  /**
22
304
  * Attaches a LD signature to the given JSON-LD document.
23
305
  * @param jsonLd The JSON-LD document to attach the signature to. It is not
@@ -211,9 +493,21 @@ async function verifySignature(jsonLd, options = {}) {
211
493
  * @returns `true` if the document is authentic; `false` otherwise.
212
494
  */
213
495
  async function verifyJsonLd(jsonLd, options = {}) {
496
+ return await verifyJsonLdInternal(jsonLd, options, true);
497
+ }
498
+ /** @internal */
499
+ async function verifyCompactJsonLd(jsonLd, options = {}) {
500
+ return await verifyJsonLdInternal(jsonLd, options, false);
501
+ }
502
+ async function verifyJsonLdInternal(jsonLd, options, compact) {
214
503
  return await (options.tracerProvider ?? _opentelemetry_api.trace.getTracerProvider()).getTracer(require_http.name, require_http.version).startActiveSpan("ld_signatures.verify", async (span) => {
215
504
  try {
216
- const object = await _fedify_vocab.Object.fromJsonLd(jsonLd, options);
505
+ const verificationOptions = hasSignature(jsonLd) ? {
506
+ ...options,
507
+ contextLoader: getNormalizationContextLoader(options.contextLoader)
508
+ } : options;
509
+ const compacted = compact ? hasSignature(jsonLd) ? await compactJsonLd(jsonLd, options.contextLoader) : jsonLd : jsonLd;
510
+ const object = await _fedify_vocab.Object.fromJsonLd(compacted, verificationOptions);
217
511
  if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
218
512
  span.setAttribute("activitypub.object.type", (0, _fedify_vocab.getTypeId)(object).href);
219
513
  if (typeof jsonLd === "object" && jsonLd != null && "signature" in jsonLd && typeof jsonLd.signature === "object" && jsonLd.signature != null) {
@@ -223,7 +517,7 @@ async function verifyJsonLd(jsonLd, options = {}) {
223
517
  }
224
518
  const attributions = new Set(object.attributionIds.map((uri) => uri.href));
225
519
  if (object instanceof _fedify_vocab.Activity) for (const uri of object.actorIds) attributions.add(uri.href);
226
- const key = await verifySignature(jsonLd, options);
520
+ const key = await verifySignature(compacted, verificationOptions);
227
521
  if (key == null) return false;
228
522
  if (key.ownerId == null) {
229
523
  logger$1.debug("Key {keyId} has no owner.", { keyId: key.id?.href });
@@ -605,12 +899,30 @@ async function verifyObject(cls, jsonLd, options = {}) {
605
899
  return object;
606
900
  }
607
901
  //#endregion
902
+ Object.defineProperty(exports, "InvalidContextReferenceError", {
903
+ enumerable: true,
904
+ get: function() {
905
+ return InvalidContextReferenceError;
906
+ }
907
+ });
908
+ Object.defineProperty(exports, "assertSafeJsonLd", {
909
+ enumerable: true,
910
+ get: function() {
911
+ return assertSafeJsonLd;
912
+ }
913
+ });
608
914
  Object.defineProperty(exports, "attachSignature", {
609
915
  enumerable: true,
610
916
  get: function() {
611
917
  return attachSignature;
612
918
  }
613
919
  });
920
+ Object.defineProperty(exports, "compactJsonLd", {
921
+ enumerable: true,
922
+ get: function() {
923
+ return compactJsonLd;
924
+ }
925
+ });
614
926
  Object.defineProperty(exports, "createProof", {
615
927
  enumerable: true,
616
928
  get: function() {
@@ -641,12 +953,30 @@ Object.defineProperty(exports, "getKeyOwner", {
641
953
  return getKeyOwner;
642
954
  }
643
955
  });
956
+ Object.defineProperty(exports, "getNormalizationContextLoader", {
957
+ enumerable: true,
958
+ get: function() {
959
+ return getNormalizationContextLoader;
960
+ }
961
+ });
644
962
  Object.defineProperty(exports, "hasSignature", {
645
963
  enumerable: true,
646
964
  get: function() {
647
965
  return hasSignature;
648
966
  }
649
967
  });
968
+ Object.defineProperty(exports, "isClearlyMalformedContextReference", {
969
+ enumerable: true,
970
+ get: function() {
971
+ return isClearlyMalformedContextReference;
972
+ }
973
+ });
974
+ Object.defineProperty(exports, "isInvalidUrlTypeError", {
975
+ enumerable: true,
976
+ get: function() {
977
+ return isInvalidUrlTypeError;
978
+ }
979
+ });
650
980
  Object.defineProperty(exports, "signJsonLd", {
651
981
  enumerable: true,
652
982
  get: function() {
@@ -659,6 +989,12 @@ Object.defineProperty(exports, "signObject", {
659
989
  return signObject;
660
990
  }
661
991
  });
992
+ Object.defineProperty(exports, "verifyCompactJsonLd", {
993
+ enumerable: true,
994
+ get: function() {
995
+ return verifyCompactJsonLd;
996
+ }
997
+ });
662
998
  Object.defineProperty(exports, "verifyJsonLd", {
663
999
  enumerable: true,
664
1000
  get: function() {
@@ -683,3 +1019,9 @@ Object.defineProperty(exports, "verifySignature", {
683
1019
  return verifySignature;
684
1020
  }
685
1021
  });
1022
+ Object.defineProperty(exports, "wrapContextLoaderForJsonLd", {
1023
+ enumerable: true,
1024
+ get: function() {
1025
+ return wrapContextLoaderForJsonLd;
1026
+ }
1027
+ });
@@ -1,3 +1,4 @@
1
+ /// <reference lib="esnext.temporal" />
1
2
  export * from "@fedify/vocab-runtime";
2
3
 
3
4
  //#region \0rolldown/runtime.js
@@ -1,3 +1,2 @@
1
- import { Temporal } from "@js-temporal/polyfill";
2
- import { URLPattern } from "urlpattern-polyfill";
1
+ /// <reference lib="esnext.temporal" />
3
2
  export * from "@fedify/vocab-runtime";
@@ -1,4 +1,4 @@
1
- import "@js-temporal/polyfill";
2
- import "urlpattern-polyfill";
3
- import "../chunk-nlSIicah.js";
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";
3
+ import "../chunk-CRNNMoPX.js";
4
4
  export * from "@fedify/vocab-runtime";
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-Ddb3P7G7.mjs";
5
- import { n as doubleKnock } from "./http-DRDpStn2.mjs";
4
+ import { n as version, t as name } from "./deno-bqnW1QlD.mjs";
5
+ import { n as doubleKnock } from "./http-DvhFwy2E.mjs";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  //#region src/federation/send.ts
@@ -7,8 +7,8 @@ import { a as assertExists, t as assertStringIncludes } from "../std__assert-Dui
7
7
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
9
9
  import { t as assert } from "../assert-ddO5KLpe.mjs";
10
- import { t as exportJwk } from "../key-WSedbAA-.mjs";
11
- import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase, u as verifyRequestDetailed } from "../http-DRDpStn2.mjs";
10
+ import { t as exportJwk } from "../key-B3OBz6A_.mjs";
11
+ import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase, u as verifyRequestDetailed } from "../http-DvhFwy2E.mjs";
12
12
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-BAK-tUlf.mjs";
13
13
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { FetchError, exportSpki } from "@fedify/vocab-runtime";
@@ -959,6 +959,124 @@ test("doubleKnock() detects redirect loops", async () => {
959
959
  assertEquals(requestCount, 2);
960
960
  esm_default.hardReset();
961
961
  });
962
+ test("doubleKnock() retries idempotent request transport errors", async () => {
963
+ esm_default.spyGlobal();
964
+ try {
965
+ let requestCount = 0;
966
+ esm_default.get("https://example.com/flaky-document", () => {
967
+ requestCount++;
968
+ if (requestCount === 1) throw new TypeError("temporary DNS failure");
969
+ return new Response("Success", { status: 200 });
970
+ });
971
+ const response = await doubleKnock(new Request("https://example.com/flaky-document"), {
972
+ keyId: rsaPublicKey2.id,
973
+ privateKey: rsaPrivateKey2
974
+ });
975
+ assertEquals(response.status, 200);
976
+ assertEquals(await response.text(), "Success");
977
+ assertEquals(requestCount, 2);
978
+ } finally {
979
+ esm_default.hardReset();
980
+ }
981
+ });
982
+ test("doubleKnock() wraps repeated transport errors", async () => {
983
+ esm_default.spyGlobal();
984
+ try {
985
+ let requestCount = 0;
986
+ const failure = /* @__PURE__ */ new TypeError("DNS lookup failed");
987
+ esm_default.get("https://example.com/unreachable-document", () => {
988
+ requestCount++;
989
+ throw failure;
990
+ });
991
+ const request = new Request("https://example.com/unreachable-document");
992
+ const error = await assertRejects(() => doubleKnock(request, {
993
+ keyId: rsaPublicKey2.id,
994
+ privateKey: rsaPrivateKey2
995
+ }), FetchError, "DNS lookup failed");
996
+ assertEquals(error.url.href, "https://example.com/unreachable-document");
997
+ assertEquals(error.cause, failure);
998
+ assertEquals(requestCount, 2);
999
+ } finally {
1000
+ esm_default.hardReset();
1001
+ }
1002
+ });
1003
+ test("doubleKnock() does not retry non-idempotent transport errors", async () => {
1004
+ esm_default.spyGlobal();
1005
+ try {
1006
+ let requestCount = 0;
1007
+ const failure = /* @__PURE__ */ new TypeError("connection reset");
1008
+ esm_default.post("https://example.com/flaky-inbox", () => {
1009
+ requestCount++;
1010
+ throw failure;
1011
+ });
1012
+ const request = new Request("https://example.com/flaky-inbox", {
1013
+ method: "POST",
1014
+ body: "Test activity content",
1015
+ headers: { "Content-Type": "application/activity+json" }
1016
+ });
1017
+ const error = await assertRejects(() => doubleKnock(request, {
1018
+ keyId: rsaPublicKey2.id,
1019
+ privateKey: rsaPrivateKey2
1020
+ }), FetchError, "connection reset");
1021
+ assertEquals(error.url.href, "https://example.com/flaky-inbox");
1022
+ assertEquals(error.cause, failure);
1023
+ assertEquals(requestCount, 1);
1024
+ } finally {
1025
+ esm_default.hardReset();
1026
+ }
1027
+ });
1028
+ test("doubleKnock() preserves Request signal abort reasons", async () => {
1029
+ const controller = new AbortController();
1030
+ const abortReason = "request aborted";
1031
+ controller.abort(abortReason);
1032
+ const request = new Request("https://example.com/request-abort", { signal: controller.signal });
1033
+ assertEquals(await assertRejects(() => doubleKnock(request, {
1034
+ keyId: rsaPublicKey2.id,
1035
+ privateKey: rsaPrivateKey2
1036
+ })), abortReason);
1037
+ });
1038
+ test("doubleKnock() preserves Request signal aborts during retry delay", async () => {
1039
+ esm_default.spyGlobal();
1040
+ try {
1041
+ let requestCount = 0;
1042
+ const controller = new AbortController();
1043
+ const abortReason = "retry aborted";
1044
+ esm_default.get("https://example.com/aborted-retry", () => {
1045
+ requestCount++;
1046
+ setTimeout(() => controller.abort(abortReason));
1047
+ throw new TypeError("temporary DNS failure");
1048
+ });
1049
+ const request = new Request("https://example.com/aborted-retry", { signal: controller.signal });
1050
+ assertEquals(await assertRejects(() => doubleKnock(request, {
1051
+ keyId: rsaPublicKey2.id,
1052
+ privateKey: rsaPrivateKey2
1053
+ })), abortReason);
1054
+ assertEquals(requestCount, 1);
1055
+ } finally {
1056
+ esm_default.hardReset();
1057
+ }
1058
+ });
1059
+ test("doubleKnock() prefers Request aborts over transport errors", async () => {
1060
+ esm_default.spyGlobal();
1061
+ try {
1062
+ let requestCount = 0;
1063
+ const controller = new AbortController();
1064
+ const abortReason = "transport aborted";
1065
+ esm_default.get("https://example.com/abort-with-transport-error", () => {
1066
+ requestCount++;
1067
+ controller.abort(abortReason);
1068
+ throw new TypeError("temporary DNS failure");
1069
+ });
1070
+ const request = new Request("https://example.com/abort-with-transport-error", { signal: controller.signal });
1071
+ assertEquals(await assertRejects(() => doubleKnock(request, {
1072
+ keyId: rsaPublicKey2.id,
1073
+ privateKey: rsaPrivateKey2
1074
+ })), abortReason);
1075
+ assertEquals(requestCount, 1);
1076
+ } finally {
1077
+ esm_default.hardReset();
1078
+ }
1079
+ });
962
1080
  test("doubleKnock() async specDeterminer test", async () => {
963
1081
  esm_default.spyGlobal();
964
1082
  let requestCount = 0;
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
8
- import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-WSedbAA-.mjs";
8
+ import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-B3OBz6A_.mjs";
9
9
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";