@fedify/fedify 1.9.2-dev.1890 → 1.10.0-dev.11

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 (104) hide show
  1. package/README.md +3 -0
  2. package/dist/{actor-LJkP7iVc.js → actor-BrjBSlv8.js} +187 -187
  3. package/dist/{actor-C2kxp5Fl.cjs → actor-CdCyXIiy.cjs} +187 -187
  4. package/dist/{actor-DyfGDQJB.js → actor-CzhWrNYT.js} +1 -1
  5. package/dist/{authdocloader-DaFhFZWS.cjs → authdocloader-BJPbXGjs.cjs} +3 -3
  6. package/dist/{authdocloader-8jtTmnjn.js → authdocloader-DWc5tH1y.js} +3 -3
  7. package/dist/{authdocloader-Djn6Z8TB.js → authdocloader-Y9lwp2q3.js} +3 -3
  8. package/dist/{builder-DG1srBKu.js → builder-D9HmXe-c.js} +4 -4
  9. package/dist/{client-Dq-zkC8Y.js → client-DPYh54yM.js} +1 -1
  10. package/dist/compat/transformers.test.js +16 -16
  11. package/dist/{docloader-Uh0ciwr4.cjs → docloader-Cgy1RCqb.cjs} +67 -29
  12. package/dist/{docloader-B_A2nB2W.js → docloader-Crf5jJS0.js} +67 -29
  13. package/dist/{esm-D-py171v.js → esm-D6gwWBFZ.js} +1 -1
  14. package/dist/federation/builder.test.js +5 -5
  15. package/dist/federation/collection.test.js +3 -3
  16. package/dist/federation/handler.test.js +104 -17
  17. package/dist/federation/idempotency.test.js +17 -17
  18. package/dist/federation/inbox.test.js +4 -4
  19. package/dist/federation/keycache.test.js +4 -4
  20. package/dist/federation/kv.test.js +3 -3
  21. package/dist/federation/middleware.test.js +18 -18
  22. package/dist/federation/mod.cjs +10 -10
  23. package/dist/federation/mod.js +10 -10
  24. package/dist/federation/mq.test.js +5 -5
  25. package/dist/federation/retry.test.js +3 -3
  26. package/dist/federation/router.test.js +3 -3
  27. package/dist/federation/send.test.js +53 -10
  28. package/dist/{http-jrUnvC1R.js → http-BqvHtYhP.js} +2 -2
  29. package/dist/{http-CJ7SfCok.js → http-CSJ1EReB.js} +3 -3
  30. package/dist/{http-DNoRdF3N.cjs → http-DBJHuWVd.cjs} +3 -3
  31. package/dist/{inbox-C3N4s1QJ.js → inbox-BuzNfn3x.js} +1 -1
  32. package/dist/{key-CAH7GCWj.js → key-1YPBM8c7.js} +2 -2
  33. package/dist/{key-CtByaj7Q.js → key-B5Hkq3o6.js} +4 -4
  34. package/dist/key-BgW3veKX.cjs +10 -0
  35. package/dist/{key-CkxzRYsV.cjs → key-CHl3R_Y6.cjs} +2 -2
  36. package/dist/{key-D-Vs5Xls.js → key-CJW3qlT7.js} +3 -3
  37. package/dist/{key-Ci7FKLpn.js → key-DZXdhUze.js} +2 -2
  38. package/dist/{keycache-CEs327f0.js → keycache-CGSAu6vs.js} +1 -1
  39. package/dist/{keys-BgYAMY7I.js → keys-CfLhGOby.js} +1 -1
  40. package/dist/{ld-CF-_Iv3N.js → ld-CmJQd-xc.js} +2 -2
  41. package/dist/{lookup-DqmSkJVj.js → lookup--mgANXmv.js} +1 -1
  42. package/dist/{lookup-BqEeMRXW.cjs → lookup-BQeZoGI4.cjs} +1 -1
  43. package/dist/{lookup-BA3bNgf4.js → lookup-pw97bxAu.js} +6 -1
  44. package/dist/{middleware-BhU7xqzl.cjs → middleware-Bh5EE6vq.cjs} +24 -12
  45. package/dist/middleware-DATy40bZ.cjs +17 -0
  46. package/dist/{middleware-DFDGXfT5.js → middleware-DfeWQSw-.js} +24 -12
  47. package/dist/middleware-V-6KSCRG.js +17 -0
  48. package/dist/{middleware-8Utrfm2B.js → middleware-_hA7WuDf.js} +20 -13
  49. package/dist/middleware-qKLKzVpT.js +26 -0
  50. package/dist/mod.cjs +10 -10
  51. package/dist/mod.js +10 -10
  52. package/dist/nodeinfo/client.test.js +5 -5
  53. package/dist/nodeinfo/handler.test.js +16 -16
  54. package/dist/nodeinfo/mod.cjs +2 -2
  55. package/dist/nodeinfo/mod.js +2 -2
  56. package/dist/nodeinfo/semver.test.js +3 -3
  57. package/dist/nodeinfo/types.test.js +3 -3
  58. package/dist/otel-Chy5T2Xh.js +64 -0
  59. package/dist/{owner-D2N6v5Gm.js → owner-B7WLWS8V.js} +44 -8
  60. package/dist/{proof-XCcYDcHk.js → proof-BSHkn7FC.js} +45 -9
  61. package/dist/{proof-GwNAN3ln.js → proof-BSpRVVLc.js} +2 -2
  62. package/dist/{proof-CbitzfgJ.cjs → proof-Dkb2_kGH.cjs} +44 -8
  63. package/dist/runtime/authdocloader.test.js +9 -9
  64. package/dist/runtime/docloader.test.js +82 -5
  65. package/dist/runtime/key.test.js +5 -5
  66. package/dist/runtime/langstr.test.js +3 -3
  67. package/dist/runtime/link.test.js +3 -3
  68. package/dist/runtime/mod.cjs +6 -6
  69. package/dist/runtime/mod.js +6 -6
  70. package/dist/runtime/multibase/multibase.test.js +3 -3
  71. package/dist/runtime/url.test.js +3 -3
  72. package/dist/{send-D_f3mgyD.js → send-CKzTk_tF.js} +9 -4
  73. package/dist/sig/http.test.js +8 -8
  74. package/dist/sig/key.test.js +6 -6
  75. package/dist/sig/ld.test.js +7 -7
  76. package/dist/sig/mod.cjs +6 -6
  77. package/dist/sig/mod.js +6 -6
  78. package/dist/sig/owner.test.js +31 -7
  79. package/dist/sig/proof.test.js +7 -7
  80. package/dist/testing/docloader.test.js +3 -3
  81. package/dist/testing/mod.js +3 -3
  82. package/dist/{testing-hVeFvsZ9.js → testing-DiHxoGZd.js} +2 -2
  83. package/dist/{type-CfrcT6D9.js → type-Bjc-_Rom.js} +253 -216
  84. package/dist/{types-apcavnI7.js → types-B5V7vlb3.js} +1 -1
  85. package/dist/{types-DvsdrWOg.cjs → types-DWiBkfCv.cjs} +1 -1
  86. package/dist/vocab/actor.test.js +5 -5
  87. package/dist/vocab/lookup.test.js +27 -5
  88. package/dist/vocab/mod.cjs +4 -4
  89. package/dist/vocab/mod.js +4 -4
  90. package/dist/vocab/type.test.js +3 -3
  91. package/dist/vocab/vocab.test.js +4 -4
  92. package/dist/{vocab-0FCIW9qL.cjs → vocab-BdU947qD.cjs} +8 -3
  93. package/dist/{vocab-DGzlpjfi.js → vocab-ChCCqvR3.js} +8 -3
  94. package/dist/webfinger/handler.test.js +16 -16
  95. package/dist/webfinger/lookup.test.js +4 -4
  96. package/dist/webfinger/mod.cjs +2 -2
  97. package/dist/webfinger/mod.js +2 -2
  98. package/dist/x/cfworkers.test.js +3 -3
  99. package/package.json +5 -3
  100. package/dist/key-CEK-2eTr.cjs +0 -10
  101. package/dist/middleware-BQ3VcPQj.js +0 -17
  102. package/dist/middleware-BxBgtIG4.js +0 -26
  103. package/dist/middleware-UJYNu-kk.cjs +0 -17
  104. /package/dist/{denokv-Bv33Xxea.js → denokv-D0nfNQ1x.js} +0 -0
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Application, Group, Organization, Person, Service, deno_default, getTypeId, lookupWebFinger } from "./type-CfrcT6D9.js";
6
+ import { Application, Group, Organization, Person, Service, deno_default, getTypeId, lookupWebFinger } from "./type-Bjc-_Rom.js";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { domainToASCII, domainToUnicode } from "node:url";
9
9
 
@@ -3,9 +3,9 @@
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
5
  const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_docloader = require('./docloader-Uh0ciwr4.cjs');
7
- const require_key = require('./key-CkxzRYsV.cjs');
8
- const require_http = require('./http-DNoRdF3N.cjs');
6
+ const require_docloader = require('./docloader-Cgy1RCqb.cjs');
7
+ const require_key = require('./key-CHl3R_Y6.cjs');
8
+ const require_http = require('./http-DBJHuWVd.cjs');
9
9
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
10
10
 
11
11
  //#region src/runtime/authdocloader.ts
@@ -3,9 +3,9 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { UrlError, createRequest, getRemoteDocument, logRequest, validatePublicUrl } from "./type-CfrcT6D9.js";
7
- import { validateCryptoKey } from "./key-Ci7FKLpn.js";
8
- import { doubleKnock } from "./http-jrUnvC1R.js";
6
+ import { UrlError, createRequest, getRemoteDocument, logRequest, validatePublicUrl } from "./type-Bjc-_Rom.js";
7
+ import { validateCryptoKey } from "./key-DZXdhUze.js";
8
+ import { doubleKnock } from "./http-BqvHtYhP.js";
9
9
  import { getLogger } from "@logtape/logtape";
10
10
 
11
11
  //#region src/runtime/authdocloader.ts
@@ -2,9 +2,9 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { UrlError, createRequest, getRemoteDocument, logRequest, validatePublicUrl } from "./docloader-B_A2nB2W.js";
6
- import { validateCryptoKey } from "./key-CAH7GCWj.js";
7
- import { doubleKnock } from "./http-CJ7SfCok.js";
5
+ import { UrlError, createRequest, getRemoteDocument, logRequest, validatePublicUrl } from "./docloader-Crf5jJS0.js";
6
+ import { validateCryptoKey } from "./key-1YPBM8c7.js";
7
+ import { doubleKnock } from "./http-CSJ1EReB.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
 
10
10
  //#region src/runtime/authdocloader.ts
@@ -3,9 +3,9 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { deno_default, getTypeId } from "./type-CfrcT6D9.js";
7
- import { Router, RouterError } from "./lookup-BA3bNgf4.js";
8
- import { InboxListenerSet } from "./inbox-C3N4s1QJ.js";
6
+ import { deno_default, getTypeId } from "./type-Bjc-_Rom.js";
7
+ import { Router, RouterError } from "./lookup-pw97bxAu.js";
8
+ import { InboxListenerSet } from "./inbox-BuzNfn3x.js";
9
9
  import { getLogger } from "@logtape/logtape";
10
10
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
11
11
 
@@ -43,7 +43,7 @@ var FederationBuilderImpl = class {
43
43
  this.collectionTypeIds = {};
44
44
  }
45
45
  async build(options) {
46
- const { FederationImpl } = await import("./middleware-BxBgtIG4.js");
46
+ const { FederationImpl } = await import("./middleware-qKLKzVpT.js");
47
47
  const f = new FederationImpl(options);
48
48
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
49
49
  f.router = this.router.clone();
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { getUserAgent } from "./type-CfrcT6D9.js";
6
+ import { getUserAgent } from "./type-Bjc-_Rom.js";
7
7
  import { parseSemVer } from "./semver-dArNLkR9.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
 
@@ -3,30 +3,30 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Follow, Person } from "../type-CfrcT6D9.js";
6
+ import { Follow, Person } from "../type-Bjc-_Rom.js";
7
7
  import { assertEquals } from "../assert_equals-DSbWqCm3.js";
8
8
  import { assert } from "../assert-MZs1qjMx.js";
9
9
  import { assertInstanceOf } from "../assert_instance_of-DHz7EHNU.js";
10
10
  import { MemoryKvStore } from "../kv-CRZrzyXm.js";
11
- import { FederationImpl, actorDehydrator, autoIdAssigner } from "../middleware-8Utrfm2B.js";
11
+ import { FederationImpl, actorDehydrator, autoIdAssigner } from "../middleware-_hA7WuDf.js";
12
12
  import "../semver-dArNLkR9.js";
13
- import "../client-Dq-zkC8Y.js";
14
- import "../lookup-BA3bNgf4.js";
13
+ import "../client-DPYh54yM.js";
14
+ import "../lookup-pw97bxAu.js";
15
15
  import "../types-BIgY6c-l.js";
16
- import "../actor-DyfGDQJB.js";
17
- import "../key-Ci7FKLpn.js";
18
- import "../http-jrUnvC1R.js";
19
- import "../authdocloader-8jtTmnjn.js";
20
- import "../ld-CF-_Iv3N.js";
21
- import "../owner-D2N6v5Gm.js";
22
- import "../proof-GwNAN3ln.js";
23
- import "../inbox-C3N4s1QJ.js";
24
- import "../builder-DG1srBKu.js";
16
+ import "../actor-CzhWrNYT.js";
17
+ import "../key-DZXdhUze.js";
18
+ import "../http-BqvHtYhP.js";
19
+ import "../authdocloader-DWc5tH1y.js";
20
+ import "../ld-CmJQd-xc.js";
21
+ import "../owner-B7WLWS8V.js";
22
+ import "../proof-BSpRVVLc.js";
23
+ import "../inbox-BuzNfn3x.js";
24
+ import "../builder-D9HmXe-c.js";
25
25
  import "../collection-CSzG2j1P.js";
26
- import "../keycache-CEs327f0.js";
26
+ import "../keycache-CGSAu6vs.js";
27
27
  import "../retry-D4GJ670a.js";
28
- import "../send-D_f3mgyD.js";
29
- import { test } from "../testing-hVeFvsZ9.js";
28
+ import "../send-CKzTk_tF.js";
29
+ import { test } from "../testing-DiHxoGZd.js";
30
30
 
31
31
  //#region src/compat/transformers.test.ts
32
32
  const federation = new FederationImpl({ kv: new MemoryKvStore() });
@@ -4,13 +4,14 @@
4
4
 
5
5
  const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
6
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
7
+ const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
7
8
  const node_process = require_chunk.__toESM(require("node:process"));
8
9
  const node_dns_promises = require_chunk.__toESM(require("node:dns/promises"));
9
10
  const node_net = require_chunk.__toESM(require("node:net"));
10
11
 
11
12
  //#region deno.json
12
13
  var name = "@fedify/fedify";
13
- var version = "1.9.2-dev.1890+4be74434";
14
+ var version = "1.10.0-dev.11+d74bbbd7";
14
15
  var license = "MIT";
15
16
  var exports$1 = {
16
17
  ".": "./src/mod.ts",
@@ -32,6 +33,8 @@ var imports = {
32
33
  "@cfworker/json-schema": "npm:@cfworker/json-schema@^4.1.1",
33
34
  "@multiformats/base-x": "npm:@multiformats/base-x@^4.0.1",
34
35
  "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0",
36
+ "@opentelemetry/core": "npm:@opentelemetry/core@^1.30.1",
37
+ "@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@^1.30.1",
35
38
  "@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@^1.27.0",
36
39
  "@phensley/language-tag": "npm:@phensley/language-tag@^1.9.0",
37
40
  "@std/assert": "jsr:@std/assert@^0.226.0",
@@ -43,7 +46,7 @@ var imports = {
43
46
  "fast-check": "npm:fast-check@^3.22.0",
44
47
  "fetch-mock": "npm:fetch-mock@^12.5.2",
45
48
  "json-canon": "npm:json-canon@^1.0.1",
46
- "jsonld": "npm:jsonld@^8.3.2",
49
+ "jsonld": "npm:jsonld@^9.0.0",
47
50
  "multicodec": "npm:multicodec@^3.2.1",
48
51
  "pkijs": "npm:pkijs@^3.2.4",
49
52
  "structured-field-values": "npm:structured-field-values@^2.0.4",
@@ -4627,29 +4630,38 @@ async function getRemoteDocument(url, response, fetch$1) {
4627
4630
  }
4628
4631
  let document;
4629
4632
  if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
4630
- const p = /<(a|link)((\s+[a-z][a-z:_-]*=("[^"]*"|'[^']*'|[^\s>]+))+)\s*\/?>/gi;
4631
- const p2 = /\s+([a-z][a-z:_-]*)=("([^"]*)"|'([^']*)'|([^\s>]+))/gi;
4633
+ const MAX_HTML_SIZE = 1024 * 1024;
4632
4634
  const html = await response.text();
4633
- let m;
4634
- const rawAttribs = [];
4635
- while ((m = p.exec(html)) !== null) rawAttribs.push(m[2]);
4636
- for (const rawAttrs of rawAttribs) {
4637
- let m2;
4638
- const attribs = {};
4639
- while ((m2 = p2.exec(rawAttrs)) !== null) {
4640
- const key = m2[1].toLowerCase();
4641
- const value = m2[3] ?? m2[4] ?? m2[5] ?? "";
4642
- attribs[key] = value;
4643
- }
4644
- if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
4645
- logger.debug("Found alternate document: {alternateUrl} from {url}", {
4646
- alternateUrl: attribs.href,
4647
- url: documentUrl
4648
- });
4649
- return await fetch$1(new URL(attribs.href, docUrl).href);
4635
+ if (html.length > MAX_HTML_SIZE) {
4636
+ logger.warn("HTML response too large, skipping alternate link discovery: {url}", {
4637
+ url: documentUrl,
4638
+ size: html.length
4639
+ });
4640
+ document = JSON.parse(html);
4641
+ } else {
4642
+ const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
4643
+ const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
4644
+ let tagMatch;
4645
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
4646
+ const tagContent = tagMatch[2];
4647
+ let attrMatch;
4648
+ const attribs = {};
4649
+ attrPattern.lastIndex = 0;
4650
+ while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
4651
+ const key = attrMatch[1].toLowerCase();
4652
+ const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
4653
+ attribs[key] = value;
4654
+ }
4655
+ if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
4656
+ logger.debug("Found alternate document: {alternateUrl} from {url}", {
4657
+ alternateUrl: attribs.href,
4658
+ url: documentUrl
4659
+ });
4660
+ return await fetch$1(new URL(attribs.href, docUrl).href);
4661
+ }
4650
4662
  }
4663
+ document = JSON.parse(html);
4651
4664
  }
4652
- document = JSON.parse(html);
4653
4665
  } else document = await response.json();
4654
4666
  logger.debug("Fetched document: {status} {url} {headers}", {
4655
4667
  status: response.status,
@@ -4680,6 +4692,8 @@ async function getRemoteDocument(url, response, fetch$1) {
4680
4692
  * @since 1.3.0
4681
4693
  */
4682
4694
  function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAgent } = {}) {
4695
+ const tracerProvider = __opentelemetry_api.trace.getTracerProvider();
4696
+ const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
4683
4697
  async function load(url, options) {
4684
4698
  options?.signal?.throwIfAborted();
4685
4699
  if (!skipPreloadedContexts && url in contexts_default) {
@@ -4699,14 +4713,38 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
4699
4713
  });
4700
4714
  throw error;
4701
4715
  }
4702
- const request = createRequest(url, { userAgent });
4703
- logRequest(request);
4704
- const response = await fetch(request, {
4705
- redirect: "manual",
4706
- signal: options?.signal
4716
+ return await tracer.startActiveSpan("activitypub.fetch_document", {
4717
+ kind: __opentelemetry_api.SpanKind.CLIENT,
4718
+ attributes: { "url.full": url }
4719
+ }, async (span) => {
4720
+ try {
4721
+ const request = createRequest(url, { userAgent });
4722
+ logRequest(request);
4723
+ const response = await fetch(request, {
4724
+ redirect: "manual",
4725
+ signal: options?.signal
4726
+ });
4727
+ span.setAttribute("http.response.status_code", response.status);
4728
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
4729
+ const redirectUrl = response.headers.get("Location");
4730
+ span.setAttribute("http.redirect.url", redirectUrl);
4731
+ return await load(redirectUrl, options);
4732
+ }
4733
+ const result = await getRemoteDocument(url, response, load);
4734
+ span.setAttribute("docloader.document_url", result.documentUrl);
4735
+ if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
4736
+ return result;
4737
+ } catch (error) {
4738
+ span.recordException(error);
4739
+ span.setStatus({
4740
+ code: __opentelemetry_api.SpanStatusCode.ERROR,
4741
+ message: String(error)
4742
+ });
4743
+ throw error;
4744
+ } finally {
4745
+ span.end();
4746
+ }
4707
4747
  });
4708
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return load(response.headers.get("Location"), options);
4709
- return getRemoteDocument(url, response, load);
4710
4748
  }
4711
4749
  return load;
4712
4750
  }
@@ -3,13 +3,14 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
5
  import { getLogger } from "@logtape/logtape";
6
+ import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
6
7
  import process from "node:process";
7
8
  import { lookup } from "node:dns/promises";
8
9
  import { isIP } from "node:net";
9
10
 
10
11
  //#region deno.json
11
12
  var name = "@fedify/fedify";
12
- var version = "1.9.2-dev.1890+4be74434";
13
+ var version = "1.10.0-dev.11+d74bbbd7";
13
14
  var license = "MIT";
14
15
  var exports = {
15
16
  ".": "./src/mod.ts",
@@ -31,6 +32,8 @@ var imports = {
31
32
  "@cfworker/json-schema": "npm:@cfworker/json-schema@^4.1.1",
32
33
  "@multiformats/base-x": "npm:@multiformats/base-x@^4.0.1",
33
34
  "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0",
35
+ "@opentelemetry/core": "npm:@opentelemetry/core@^1.30.1",
36
+ "@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@^1.30.1",
34
37
  "@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@^1.27.0",
35
38
  "@phensley/language-tag": "npm:@phensley/language-tag@^1.9.0",
36
39
  "@std/assert": "jsr:@std/assert@^0.226.0",
@@ -42,7 +45,7 @@ var imports = {
42
45
  "fast-check": "npm:fast-check@^3.22.0",
43
46
  "fetch-mock": "npm:fetch-mock@^12.5.2",
44
47
  "json-canon": "npm:json-canon@^1.0.1",
45
- "jsonld": "npm:jsonld@^8.3.2",
48
+ "jsonld": "npm:jsonld@^9.0.0",
46
49
  "multicodec": "npm:multicodec@^3.2.1",
47
50
  "pkijs": "npm:pkijs@^3.2.4",
48
51
  "structured-field-values": "npm:structured-field-values@^2.0.4",
@@ -4626,29 +4629,38 @@ async function getRemoteDocument(url, response, fetch$1) {
4626
4629
  }
4627
4630
  let document;
4628
4631
  if (!jsonLd && (contentType === "text/html" || contentType?.startsWith("text/html;") || contentType === "application/xhtml+xml" || contentType?.startsWith("application/xhtml+xml;"))) {
4629
- const p = /<(a|link)((\s+[a-z][a-z:_-]*=("[^"]*"|'[^']*'|[^\s>]+))+)\s*\/?>/gi;
4630
- const p2 = /\s+([a-z][a-z:_-]*)=("([^"]*)"|'([^']*)'|([^\s>]+))/gi;
4632
+ const MAX_HTML_SIZE = 1024 * 1024;
4631
4633
  const html = await response.text();
4632
- let m;
4633
- const rawAttribs = [];
4634
- while ((m = p.exec(html)) !== null) rawAttribs.push(m[2]);
4635
- for (const rawAttrs of rawAttribs) {
4636
- let m2;
4637
- const attribs = {};
4638
- while ((m2 = p2.exec(rawAttrs)) !== null) {
4639
- const key = m2[1].toLowerCase();
4640
- const value = m2[3] ?? m2[4] ?? m2[5] ?? "";
4641
- attribs[key] = value;
4642
- }
4643
- if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
4644
- logger.debug("Found alternate document: {alternateUrl} from {url}", {
4645
- alternateUrl: attribs.href,
4646
- url: documentUrl
4647
- });
4648
- return await fetch$1(new URL(attribs.href, docUrl).href);
4634
+ if (html.length > MAX_HTML_SIZE) {
4635
+ logger.warn("HTML response too large, skipping alternate link discovery: {url}", {
4636
+ url: documentUrl,
4637
+ size: html.length
4638
+ });
4639
+ document = JSON.parse(html);
4640
+ } else {
4641
+ const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
4642
+ const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
4643
+ let tagMatch;
4644
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
4645
+ const tagContent = tagMatch[2];
4646
+ let attrMatch;
4647
+ const attribs = {};
4648
+ attrPattern.lastIndex = 0;
4649
+ while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
4650
+ const key = attrMatch[1].toLowerCase();
4651
+ const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
4652
+ attribs[key] = value;
4653
+ }
4654
+ if (attribs.rel === "alternate" && "type" in attribs && (attribs.type === "application/activity+json" || attribs.type === "application/ld+json" || attribs.type.startsWith("application/ld+json;")) && "href" in attribs && new URL(attribs.href, docUrl).href !== docUrl.href) {
4655
+ logger.debug("Found alternate document: {alternateUrl} from {url}", {
4656
+ alternateUrl: attribs.href,
4657
+ url: documentUrl
4658
+ });
4659
+ return await fetch$1(new URL(attribs.href, docUrl).href);
4660
+ }
4649
4661
  }
4662
+ document = JSON.parse(html);
4650
4663
  }
4651
- document = JSON.parse(html);
4652
4664
  } else document = await response.json();
4653
4665
  logger.debug("Fetched document: {status} {url} {headers}", {
4654
4666
  status: response.status,
@@ -4679,6 +4691,8 @@ async function getRemoteDocument(url, response, fetch$1) {
4679
4691
  * @since 1.3.0
4680
4692
  */
4681
4693
  function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAgent } = {}) {
4694
+ const tracerProvider = trace.getTracerProvider();
4695
+ const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
4682
4696
  async function load(url, options) {
4683
4697
  options?.signal?.throwIfAborted();
4684
4698
  if (!skipPreloadedContexts && url in contexts_default) {
@@ -4698,14 +4712,38 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
4698
4712
  });
4699
4713
  throw error;
4700
4714
  }
4701
- const request = createRequest(url, { userAgent });
4702
- logRequest(request);
4703
- const response = await fetch(request, {
4704
- redirect: "manual",
4705
- signal: options?.signal
4715
+ return await tracer.startActiveSpan("activitypub.fetch_document", {
4716
+ kind: SpanKind.CLIENT,
4717
+ attributes: { "url.full": url }
4718
+ }, async (span) => {
4719
+ try {
4720
+ const request = createRequest(url, { userAgent });
4721
+ logRequest(request);
4722
+ const response = await fetch(request, {
4723
+ redirect: "manual",
4724
+ signal: options?.signal
4725
+ });
4726
+ span.setAttribute("http.response.status_code", response.status);
4727
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
4728
+ const redirectUrl = response.headers.get("Location");
4729
+ span.setAttribute("http.redirect.url", redirectUrl);
4730
+ return await load(redirectUrl, options);
4731
+ }
4732
+ const result = await getRemoteDocument(url, response, load);
4733
+ span.setAttribute("docloader.document_url", result.documentUrl);
4734
+ if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
4735
+ return result;
4736
+ } catch (error) {
4737
+ span.recordException(error);
4738
+ span.setStatus({
4739
+ code: SpanStatusCode.ERROR,
4740
+ message: String(error)
4741
+ });
4742
+ throw error;
4743
+ } finally {
4744
+ span.end();
4745
+ }
4706
4746
  });
4707
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return load(response.headers.get("Location"), options);
4708
- return getRemoteDocument(url, response, load);
4709
4747
  }
4710
4748
  return load;
4711
4749
  }
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { __commonJS, __toESM } from "./type-CfrcT6D9.js";
6
+ import { __commonJS, __toESM } from "./type-Bjc-_Rom.js";
7
7
 
8
8
  //#region ../../node_modules/.pnpm/glob-to-regexp@0.4.1/node_modules/glob-to-regexp/index.js
9
9
  var require_glob_to_regexp = __commonJS({ "../../node_modules/.pnpm/glob-to-regexp@0.4.1/node_modules/glob-to-regexp/index.js"(exports, module) {
@@ -3,16 +3,16 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Activity, Note, Person } from "../type-CfrcT6D9.js";
6
+ import { Activity, Note, Person } from "../type-Bjc-_Rom.js";
7
7
  import { assertEquals } from "../assert_equals-DSbWqCm3.js";
8
8
  import "../assert-MZs1qjMx.js";
9
9
  import "../assert_instance_of-DHz7EHNU.js";
10
10
  import { MemoryKvStore } from "../kv-CRZrzyXm.js";
11
11
  import { parseSemVer } from "../semver-dArNLkR9.js";
12
- import "../lookup-BA3bNgf4.js";
13
- import "../inbox-C3N4s1QJ.js";
14
- import { createFederationBuilder } from "../builder-DG1srBKu.js";
15
- import { test } from "../testing-hVeFvsZ9.js";
12
+ import "../lookup-pw97bxAu.js";
13
+ import "../inbox-BuzNfn3x.js";
14
+ import { createFederationBuilder } from "../builder-D9HmXe-c.js";
15
+ import { test } from "../testing-DiHxoGZd.js";
16
16
  import { assertExists } from "../std__assert-X-_kMxKM.js";
17
17
  import "../assert_rejects-DiIiJbZn.js";
18
18
  import "../assert_is_error-BPGph1Jx.js";
@@ -3,13 +3,13 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import "../type-CfrcT6D9.js";
6
+ import "../type-Bjc-_Rom.js";
7
7
  import { assertEquals } from "../assert_equals-DSbWqCm3.js";
8
8
  import "../assert-MZs1qjMx.js";
9
9
  import "../assert_instance_of-DHz7EHNU.js";
10
- import "../lookup-BA3bNgf4.js";
10
+ import "../lookup-pw97bxAu.js";
11
11
  import { buildCollectionSynchronizationHeader, digest } from "../collection-CSzG2j1P.js";
12
- import { test } from "../testing-hVeFvsZ9.js";
12
+ import { test } from "../testing-DiHxoGZd.js";
13
13
  import "../std__assert-X-_kMxKM.js";
14
14
  import "../assert_rejects-DiIiJbZn.js";
15
15
  import "../assert_is_error-BPGph1Jx.js";
@@ -3,36 +3,37 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Create, Note, Person } from "../type-CfrcT6D9.js";
6
+ import { Create, Note, Person } from "../type-Bjc-_Rom.js";
7
7
  import { assertEquals } from "../assert_equals-DSbWqCm3.js";
8
8
  import { assert } from "../assert-MZs1qjMx.js";
9
9
  import "../assert_instance_of-DHz7EHNU.js";
10
10
  import { MemoryKvStore } from "../kv-CRZrzyXm.js";
11
- import { acceptsJsonLd, createFederation, handleActor, handleCollection, handleCustomCollection, handleInbox, handleObject, respondWithObject, respondWithObjectIfAcceptable } from "../middleware-8Utrfm2B.js";
11
+ import { acceptsJsonLd, createFederation, handleActor, handleCollection, handleCustomCollection, handleInbox, handleObject, respondWithObject, respondWithObjectIfAcceptable } from "../middleware-_hA7WuDf.js";
12
12
  import "../semver-dArNLkR9.js";
13
- import "../client-Dq-zkC8Y.js";
14
- import "../lookup-BA3bNgf4.js";
13
+ import "../client-DPYh54yM.js";
14
+ import "../lookup-pw97bxAu.js";
15
15
  import "../types-BIgY6c-l.js";
16
- import "../actor-DyfGDQJB.js";
17
- import "../key-Ci7FKLpn.js";
18
- import { signRequest } from "../http-jrUnvC1R.js";
19
- import "../authdocloader-8jtTmnjn.js";
20
- import "../ld-CF-_Iv3N.js";
21
- import "../owner-D2N6v5Gm.js";
22
- import "../proof-GwNAN3ln.js";
23
- import { InboxListenerSet } from "../inbox-C3N4s1QJ.js";
24
- import "../builder-DG1srBKu.js";
16
+ import "../actor-CzhWrNYT.js";
17
+ import "../key-DZXdhUze.js";
18
+ import { signRequest } from "../http-BqvHtYhP.js";
19
+ import "../authdocloader-DWc5tH1y.js";
20
+ import "../ld-CmJQd-xc.js";
21
+ import "../owner-B7WLWS8V.js";
22
+ import "../proof-BSpRVVLc.js";
23
+ import { InboxListenerSet } from "../inbox-BuzNfn3x.js";
24
+ import "../builder-D9HmXe-c.js";
25
25
  import "../collection-CSzG2j1P.js";
26
- import "../keycache-CEs327f0.js";
26
+ import "../keycache-CGSAu6vs.js";
27
27
  import "../retry-D4GJ670a.js";
28
- import "../send-D_f3mgyD.js";
29
- import { createInboxContext, createRequestContext, mockDocumentLoader, test } from "../testing-hVeFvsZ9.js";
28
+ import "../send-CKzTk_tF.js";
29
+ import { createInboxContext, createRequestContext, mockDocumentLoader, test } from "../testing-DiHxoGZd.js";
30
30
  import "../std__assert-X-_kMxKM.js";
31
31
  import { assertFalse } from "../assert_rejects-DiIiJbZn.js";
32
32
  import "../assert_is_error-BPGph1Jx.js";
33
33
  import "../assert_not_equals-f3m3epl3.js";
34
34
  import "../assert_throws-BOO88avQ.js";
35
- import { rsaPrivateKey3, rsaPublicKey2, rsaPublicKey3 } from "../keys-BgYAMY7I.js";
35
+ import { rsaPrivateKey3, rsaPublicKey2, rsaPublicKey3 } from "../keys-CfLhGOby.js";
36
+ import { createTestTracerProvider } from "../otel-Chy5T2Xh.js";
36
37
 
37
38
  //#region src/federation/handler.test.ts
38
39
  test("acceptsJsonLd()", () => {
@@ -1602,5 +1603,91 @@ test("handleCustomCollection()", async () => {
1602
1603
  assertEquals(onNotAcceptableCalled, null);
1603
1604
  assertEquals(onUnauthorizedCalled, null);
1604
1605
  });
1606
+ test("handleInbox() records OpenTelemetry span events", async () => {
1607
+ const [tracerProvider, exporter] = createTestTracerProvider();
1608
+ const kv = new MemoryKvStore();
1609
+ const federation = createFederation({
1610
+ kv,
1611
+ tracerProvider
1612
+ });
1613
+ const activity = new Create({
1614
+ id: new URL("https://example.com/activity"),
1615
+ actor: new URL("https://example.com/users/someone"),
1616
+ object: new Note({
1617
+ id: new URL("https://example.com/note"),
1618
+ content: "Hello, world!"
1619
+ })
1620
+ });
1621
+ const request = new Request("https://example.com/users/someone/inbox", {
1622
+ method: "POST",
1623
+ headers: { "Content-Type": "application/activity+json" },
1624
+ body: JSON.stringify(await activity.toJsonLd())
1625
+ });
1626
+ const signed = await signRequest(request, rsaPrivateKey3, new URL("https://example.com/users/someone#main-key"));
1627
+ const context = createRequestContext({
1628
+ federation,
1629
+ request: signed,
1630
+ url: new URL(signed.url),
1631
+ data: void 0,
1632
+ documentLoader: mockDocumentLoader,
1633
+ contextLoader: mockDocumentLoader,
1634
+ getActorUri(identifier) {
1635
+ return new URL(`https://example.com/users/${identifier}`);
1636
+ }
1637
+ });
1638
+ const actorDispatcher = (ctx, handle) => {
1639
+ if (handle !== "someone") return null;
1640
+ return new Person({
1641
+ id: ctx.getActorUri(handle),
1642
+ name: "Someone",
1643
+ inbox: new URL("https://example.com/users/someone/inbox"),
1644
+ publicKey: rsaPublicKey2
1645
+ });
1646
+ };
1647
+ const listeners = new InboxListenerSet();
1648
+ let receivedActivity = null;
1649
+ listeners.add(Create, (_ctx, activity$1) => {
1650
+ receivedActivity = activity$1;
1651
+ });
1652
+ const response = await handleInbox(signed, {
1653
+ recipient: "someone",
1654
+ context,
1655
+ inboxContextFactory(_activity) {
1656
+ return createInboxContext({
1657
+ ...context,
1658
+ clone: void 0
1659
+ });
1660
+ },
1661
+ kv,
1662
+ kvPrefixes: {
1663
+ activityIdempotence: ["activityIdempotence"],
1664
+ publicKey: ["publicKey"]
1665
+ },
1666
+ actorDispatcher,
1667
+ inboxListeners: listeners,
1668
+ inboxErrorHandler: void 0,
1669
+ onNotFound: (_request) => new Response("Not found", { status: 404 }),
1670
+ signatureTimeWindow: false,
1671
+ skipSignatureVerification: true,
1672
+ tracerProvider
1673
+ });
1674
+ assertEquals(response.status, 202);
1675
+ assert(receivedActivity != null);
1676
+ const spans = exporter.getSpans("activitypub.inbox");
1677
+ assertEquals(spans.length, 1);
1678
+ const span = spans[0];
1679
+ assertEquals(span.attributes["fedify.inbox.recipient"], "someone");
1680
+ assertEquals(span.attributes["activitypub.activity.id"], "https://example.com/activity");
1681
+ const events = exporter.getEvents("activitypub.inbox", "activitypub.activity.received");
1682
+ assertEquals(events.length, 1);
1683
+ const event = events[0];
1684
+ assert(event.attributes != null);
1685
+ assertEquals(event.attributes["activitypub.activity.verified"], true);
1686
+ assertEquals(event.attributes["http_signatures.verified"], false);
1687
+ assert(typeof event.attributes["activitypub.activity.json"] === "string");
1688
+ const recordedActivity = JSON.parse(event.attributes["activitypub.activity.json"]);
1689
+ assertEquals(recordedActivity.id, "https://example.com/activity");
1690
+ assertEquals(recordedActivity.type, "Create");
1691
+ });
1605
1692
 
1606
1693
  //#endregion