@fedify/fedify 2.0.0-dev.1908 → 2.0.0-dev.196
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.
- package/LICENSE +1 -1
- package/README.md +68 -35
- package/dist/{builder-GG0LDRaK.js → builder-R1Sfe-tb.js} +5 -3
- package/dist/{client-BsGzbnV-.d.ts → client-CUTUGgvJ.d.ts} +18 -18
- package/dist/{client-pY7-3icS.js → client-Dg7OfUDA.js} +28 -23
- package/dist/{client-94iWEfQa.d.cts → client-by-PEGAJ.d.cts} +18 -18
- package/dist/compat/mod.cjs +1 -1
- package/dist/compat/mod.d.cts +6 -10
- package/dist/compat/mod.d.ts +6 -10
- package/dist/compat/mod.js +1 -1
- package/dist/compat/transformers.test.js +22 -21
- package/dist/context-Bns6uTJq.js +109 -0
- package/dist/{context-V-XS2_6O.d.ts → context-C7vzWilY.d.ts} +63 -65
- package/dist/{context-PxGADCsD.d.cts → context-CrB9RFy5.d.cts} +63 -65
- package/dist/deno-i60L3ZJW.js +117 -0
- package/dist/{testing-bgnt5CjE.js → dist-B5f6a8Tt.js} +90 -110
- package/dist/{docloader-Buj0Y50A.js → docloader-BuOglEYx.js} +3 -3
- package/dist/{esm-vPU_GxaY.js → esm-DGl7uK1r.js} +32 -17
- package/dist/federation/builder.test.js +7 -5
- package/dist/federation/collection.test.js +2 -3
- package/dist/federation/handler.test.js +110 -22
- package/dist/federation/idempotency.test.js +23 -22
- package/dist/federation/inbox.test.js +4 -3
- package/dist/federation/keycache.test.js +4 -4
- package/dist/federation/kv.test.js +56 -3
- package/dist/federation/middleware.test.js +95 -93
- package/dist/federation/mod.cjs +8 -10
- package/dist/federation/mod.d.cts +7 -11
- package/dist/federation/mod.d.ts +7 -11
- package/dist/federation/mod.js +8 -11
- package/dist/federation/mq.test.js +5 -6
- package/dist/federation/negotiation.test.js +2 -3
- package/dist/federation/retry.test.js +2 -3
- package/dist/federation/router.test.js +2 -2
- package/dist/federation/send.test.js +51 -9
- package/dist/{webfinger/handler.test.js → federation/webfinger.test.js} +24 -22
- package/dist/{federation-CRpdnOMS.cjs → federation-B431K2gm.cjs} +22 -0
- package/dist/{federation-jcR8-ZxP.js → federation-BbZwNNWj.js} +28 -6
- package/dist/{http-ByZmUHwe.js → http-B5BgMxiO.js} +119 -9
- package/dist/{http-CTi-owaL.cjs → http-B_jtB30-.cjs} +132 -16
- package/dist/{http-M8k5mKc0.d.cts → http-ClB3pLcL.d.cts} +1 -1
- package/dist/{http-BbO0ejuk.d.ts → http-DLBDPal9.d.ts} +1 -1
- package/dist/{http-DO88HCOK.js → http-uzkhnm0W.js} +3 -2
- package/dist/{inbox-BwIgnk8R.js → inbox-CxrUTds4.js} +2 -1
- package/dist/{key-CrKmngwF.js → key-DBHCloAO.js} +3 -3
- package/dist/{keycache-CFv8xdnH.js → keycache-DRxpZ5r9.js} +1 -1
- package/dist/{keys-B2yaEG79.js → keys-ZbcByPg9.js} +1 -1
- package/dist/{kv-Bxr0Q87_.d.cts → kv-B4vFhIYL.d.cts} +30 -1
- package/dist/{kv-BKNZ-Tb-.d.ts → kv-CYySNrsn.d.ts} +30 -1
- package/dist/{kv-CRZrzyXm.js → kv-QzKcOQgP.js} +22 -0
- package/dist/{kv-cache-DN9pfMBe.js → kv-cache-BEeqyGER.js} +14 -1
- package/dist/{kv-cache-CykGg2IP.js → kv-cache-BqWqxam4.js} +2 -2
- package/dist/{kv-cache-BbklA4EG.cjs → kv-cache-DY6hQ8Rf.cjs} +2 -2
- package/dist/{ld-Ckl2k3lF.js → ld-CZgNIUGN.js} +4 -3
- package/dist/{middleware-X0RaVmfv.cjs → middleware-BaoVtoMl.cjs} +210 -194
- package/dist/{middleware-Dv90Gwc-.js → middleware-BqPcChYv.js} +164 -154
- package/dist/middleware-CnrWiFJI.cjs +12 -0
- package/dist/{middleware-CdPISvYD.js → middleware-CxwWsgSo.js} +162 -165
- package/dist/middleware-DoFisLae.js +26 -0
- package/dist/middleware-ZN9cd_L8.js +12 -0
- package/dist/{mod-DMpuiKXi.d.cts → mod-0p9zUdzg.d.cts} +6 -6
- package/dist/mod-0qnPv4EC.d.cts +62 -0
- package/dist/{mod-DgxG-byT.d.cts → mod-BrS8tiad.d.cts} +2 -2
- package/dist/mod-C3SOvTD1.d.ts +64 -0
- package/dist/{mod-BoRKfJPE.d.cts → mod-D6pS5_xJ.d.cts} +4 -4
- package/dist/{mod-D5Z2tISD.d.ts → mod-jOa7W503.d.ts} +2 -2
- package/dist/{mod-Cdo6SYlJ.d.ts → mod-waqu-BL_.d.ts} +4 -4
- package/dist/{mod-aAE2wOWV.d.ts → mod-xc20HhMD.d.ts} +6 -6
- package/dist/mod.cjs +11 -93
- package/dist/mod.d.cts +11 -15
- package/dist/mod.d.ts +11 -15
- package/dist/mod.js +11 -15
- package/dist/nodeinfo/client.test.js +3 -4
- package/dist/nodeinfo/handler.test.js +22 -21
- package/dist/nodeinfo/mod.cjs +2 -2
- package/dist/nodeinfo/mod.d.cts +2 -2
- package/dist/nodeinfo/mod.d.ts +2 -2
- package/dist/nodeinfo/mod.js +2 -2
- package/dist/nodeinfo/types.test.js +2 -3
- package/dist/otel/exporter.test.js +893 -0
- package/dist/otel/mod.cjs +256 -0
- package/dist/otel/mod.d.cts +230 -0
- package/dist/otel/mod.d.ts +232 -0
- package/dist/otel/mod.js +255 -0
- package/dist/{owner-C8UEs7je.js → owner-BDvRiO5T.js} +44 -8
- package/dist/{owner-kQRGVXG1.d.ts → owner-BgI8C-VY.d.ts} +1 -2
- package/dist/{owner-B4HbyP8s.d.cts → owner-C-zfmVAD.d.cts} +1 -2
- package/dist/{proof-CDW6KgLA.js → proof-DzFse-Bn.js} +46 -11
- package/dist/{proof-CWKgvgzL.js → proof-XEPY5YKg.js} +3 -2
- package/dist/{proof-yc6sVqKg.cjs → proof-vmNsq1AQ.cjs} +63 -28
- package/dist/router-D9eI0s4b.js +118 -0
- package/dist/{send-z5jueBCW.js → send-BdhhZ2MN.js} +9 -4
- package/dist/sig/http.test.js +6 -7
- package/dist/sig/key.test.js +5 -5
- package/dist/sig/ld.test.js +6 -6
- package/dist/sig/mod.cjs +3 -5
- package/dist/sig/mod.d.cts +3 -5
- package/dist/sig/mod.d.ts +3 -5
- package/dist/sig/mod.js +3 -5
- package/dist/sig/owner.test.js +29 -6
- package/dist/sig/proof.test.js +6 -6
- package/dist/testing/mod.d.ts +70 -6999
- package/dist/testing/mod.js +4 -3
- package/dist/{transformers-CoBS-oFG.cjs → transformers-BjBg6Lag.cjs} +2 -2
- package/dist/{transformers-BFT6d7J5.js → transformers-N_ip_y4P.js} +2 -2
- package/dist/{types-BtUjyi5y.js → types-8l28uC8o.js} +30 -25
- package/dist/{types-CWgzGaqk.cjs → types-B6z6CqIz.cjs} +30 -25
- package/dist/{types-C2XVl6gj.js → types-CPz01LGH.js} +3 -3
- package/dist/utils/docloader.test.js +7 -8
- package/dist/utils/kv-cache.test.js +5 -3
- package/dist/utils/mod.cjs +3 -5
- package/dist/utils/mod.d.cts +3 -4
- package/dist/utils/mod.d.ts +3 -4
- package/dist/utils/mod.js +3 -5
- package/package.json +25 -36
- package/dist/actor-C6x8UgbE.cjs +0 -42079
- package/dist/actor-C76CDThG.js +0 -41647
- package/dist/actor-DqFajh9s.d.ts +0 -130
- package/dist/actor-DrFLTQdj.js +0 -146
- package/dist/actor-f2NtjyCg.d.cts +0 -128
- package/dist/fixtures/activitypub.academy/users/brauca_darradiul.json +0 -83
- package/dist/fixtures/example.com/announce.json +0 -6
- package/dist/fixtures/example.com/collection.json +0 -19
- package/dist/fixtures/example.com/create.json +0 -6
- package/dist/fixtures/example.com/cross-origin-actor.json +0 -6
- package/dist/fixtures/example.com/hong-gildong.json +0 -11
- package/dist/fixtures/example.com/invite.json +0 -7
- package/dist/fixtures/example.com/key.json +0 -7
- package/dist/fixtures/example.com/key2.json +0 -6
- package/dist/fixtures/example.com/object.json +0 -6
- package/dist/fixtures/example.com/orderedcollectionpage.json +0 -24
- package/dist/fixtures/example.com/paged/a.json +0 -13
- package/dist/fixtures/example.com/paged/b.json +0 -16
- package/dist/fixtures/example.com/paged-collection.json +0 -6
- package/dist/fixtures/example.com/person.json +0 -22
- package/dist/fixtures/example.com/person2.json +0 -40
- package/dist/fixtures/example.com/test.json +0 -5
- package/dist/fixtures/example.com/users/handle.json +0 -16
- package/dist/fixtures/example.com/wrong-type.json +0 -3
- package/dist/fixtures/media.example.com/avatars/test-avatar.jpg.json +0 -6
- package/dist/fixtures/oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd.json +0 -24
- package/dist/fixtures/remote.domain/users/bob.json +0 -20
- package/dist/fixtures/server.example/users/alice.json +0 -20
- package/dist/fixtures/w3id.org/identity/v1.json +0 -152
- package/dist/fixtures/w3id.org/security/data-integrity/v1.json +0 -74
- package/dist/fixtures/w3id.org/security/multikey/v1.json +0 -35
- package/dist/fixtures/w3id.org/security/v1.json +0 -50
- package/dist/fixtures/wizard.casa/users/hongminhee.json +0 -69
- package/dist/fixtures/www.w3.org/ns/activitystreams.json +0 -379
- package/dist/fixtures/www.w3.org/ns/did/v1.json +0 -58
- package/dist/lookup-D17ydBQd.cjs +0 -265
- package/dist/lookup-DrCNfWHm.js +0 -253
- package/dist/lookup-yP6Lo5JV.js +0 -42178
- package/dist/middleware-BSCsvvh-.js +0 -26
- package/dist/middleware-GFpHLL1X.cjs +0 -15
- package/dist/middleware-pl3iXZpj.js +0 -15
- package/dist/mod-BlVovdcy.d.ts +0 -309
- package/dist/mod-BxRCHTz-.d.cts +0 -307
- package/dist/mod-C58MZ7Wx.d.cts +0 -113
- package/dist/mod-CcDPcLJW.d.cts +0 -1
- package/dist/mod-Ds0mpFZU.d.ts +0 -115
- package/dist/mod-bjzj5QIb.d.ts +0 -2
- package/dist/src/vocab/accept.yaml +0 -15
- package/dist/src/vocab/activity.yaml +0 -98
- package/dist/src/vocab/add.yaml +0 -16
- package/dist/src/vocab/announce.yaml +0 -30
- package/dist/src/vocab/application.yaml +0 -324
- package/dist/src/vocab/arrive.yaml +0 -15
- package/dist/src/vocab/article.yaml +0 -46
- package/dist/src/vocab/audio.yaml +0 -11
- package/dist/src/vocab/block.yaml +0 -16
- package/dist/src/vocab/chatmessage.yaml +0 -50
- package/dist/src/vocab/collection.yaml +0 -154
- package/dist/src/vocab/collectionpage.yaml +0 -55
- package/dist/src/vocab/create.yaml +0 -28
- package/dist/src/vocab/dataintegrityproof.yaml +0 -56
- package/dist/src/vocab/delete.yaml +0 -27
- package/dist/src/vocab/didservice.yaml +0 -22
- package/dist/src/vocab/dislike.yaml +0 -14
- package/dist/src/vocab/document.yaml +0 -31
- package/dist/src/vocab/emoji.yaml +0 -12
- package/dist/src/vocab/emojireact.yaml +0 -17
- package/dist/src/vocab/endpoints.yaml +0 -85
- package/dist/src/vocab/event.yaml +0 -11
- package/dist/src/vocab/export.yaml +0 -9
- package/dist/src/vocab/flag.yaml +0 -15
- package/dist/src/vocab/follow.yaml +0 -19
- package/dist/src/vocab/group.yaml +0 -324
- package/dist/src/vocab/hashtag.yaml +0 -14
- package/dist/src/vocab/ignore.yaml +0 -14
- package/dist/src/vocab/image.yaml +0 -9
- package/dist/src/vocab/intransitiveactivity.yaml +0 -15
- package/dist/src/vocab/invite.yaml +0 -14
- package/dist/src/vocab/join.yaml +0 -14
- package/dist/src/vocab/key.yaml +0 -28
- package/dist/src/vocab/leave.yaml +0 -14
- package/dist/src/vocab/like.yaml +0 -16
- package/dist/src/vocab/link.yaml +0 -101
- package/dist/src/vocab/listen.yaml +0 -12
- package/dist/src/vocab/mention.yaml +0 -9
- package/dist/src/vocab/move.yaml +0 -15
- package/dist/src/vocab/multikey.yaml +0 -36
- package/dist/src/vocab/note.yaml +0 -48
- package/dist/src/vocab/object.yaml +0 -404
- package/dist/src/vocab/offer.yaml +0 -15
- package/dist/src/vocab/orderedcollection.yaml +0 -39
- package/dist/src/vocab/orderedcollectionpage.yaml +0 -50
- package/dist/src/vocab/organization.yaml +0 -324
- package/dist/src/vocab/page.yaml +0 -11
- package/dist/src/vocab/person.yaml +0 -324
- package/dist/src/vocab/place.yaml +0 -75
- package/dist/src/vocab/profile.yaml +0 -26
- package/dist/src/vocab/propertyvalue.yaml +0 -32
- package/dist/src/vocab/question.yaml +0 -103
- package/dist/src/vocab/read.yaml +0 -13
- package/dist/src/vocab/reject.yaml +0 -14
- package/dist/src/vocab/relationship.yaml +0 -52
- package/dist/src/vocab/remove.yaml +0 -14
- package/dist/src/vocab/service.yaml +0 -324
- package/dist/src/vocab/source.yaml +0 -26
- package/dist/src/vocab/tentativeaccept.yaml +0 -14
- package/dist/src/vocab/tentativereject.yaml +0 -14
- package/dist/src/vocab/tombstone.yaml +0 -24
- package/dist/src/vocab/travel.yaml +0 -16
- package/dist/src/vocab/undo.yaml +0 -26
- package/dist/src/vocab/update.yaml +0 -58
- package/dist/src/vocab/video.yaml +0 -11
- package/dist/src/vocab/view.yaml +0 -13
- package/dist/testing/docloader.test.js +0 -22
- package/dist/vocab/actor.test.js +0 -5963
- package/dist/vocab/lookup.test.d.ts +0 -3
- package/dist/vocab/lookup.test.js +0 -454
- package/dist/vocab/mod.cjs +0 -86
- package/dist/vocab/mod.d.cts +0 -4
- package/dist/vocab/mod.d.ts +0 -6
- package/dist/vocab/mod.js +0 -9
- package/dist/vocab/type.test.d.ts +0 -3
- package/dist/vocab/type.test.js +0 -24
- package/dist/vocab/vocab.test.d.ts +0 -3
- package/dist/vocab/vocab.test.js +0 -9397
- package/dist/vocab-B4wXNBv8.js +0 -255
- package/dist/vocab-BCWe1Ih5.d.ts +0 -14905
- package/dist/vocab-CeDBzu-f.d.cts +0 -14903
- package/dist/vocab-Hqae4yux.cjs +0 -291
- package/dist/webfinger/handler.test.d.ts +0 -3
- package/dist/webfinger/lookup.test.d.ts +0 -3
- package/dist/webfinger/lookup.test.js +0 -193
- package/dist/webfinger/mod.cjs +0 -8
- package/dist/webfinger/mod.d.cts +0 -2
- package/dist/webfinger/mod.d.ts +0 -4
- package/dist/webfinger/mod.js +0 -8
- package/dist/webfinger-C72Y8lrh.js +0 -4
- package/dist/webfinger-vAtLmxOF.cjs +0 -4
- /package/dist/{collection-BzWsN9pB.js → collection-CcnIw1qY.js} +0 -0
- /package/dist/{testing/docloader.test.d.ts → federation/webfinger.test.d.ts} +0 -0
- /package/dist/{mod-CVgZgliM.d.ts → mod-1E3W847c.d.ts} +0 -0
- /package/dist/{mod-B-hUPT2N.d.cts → mod-C81L6_lQ.d.cts} +0 -0
- /package/dist/{negotiation-C4nFufNk.js → negotiation-5NPJL6zp.js} +0 -0
- /package/dist/{nodeinfo-BnthBobC.js → nodeinfo-BlLsRSiT.js} +0 -0
- /package/dist/{nodeinfo-CdN0rEnZ.cjs → nodeinfo-DuMYTpbZ.cjs} +0 -0
- /package/dist/{vocab/actor.test.d.ts → otel/exporter.test.d.ts} +0 -0
- /package/dist/{retry-CfF8Gn4d.js → retry-D4GJ670a.js} +0 -0
- /package/dist/{sig-C34-oHBl.js → sig-CwuONEzF.js} +0 -0
- /package/dist/{sig-YYj5tCnr.cjs → sig-DeXX2xnj.cjs} +0 -0
- /package/dist/{utils-DyRU1gdZ.cjs → utils-Db0ZmjcD.cjs} +0 -0
- /package/dist/{utils-D-Va7aXC.js → utils-Wranxuoe.js} +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
|
|
2
|
+
const { Temporal } = require("@js-temporal/polyfill");
|
|
3
|
+
const { URLPattern } = require("urlpattern-polyfill");
|
|
4
|
+
|
|
5
|
+
const require_chunk = require('../chunk-DqRYRqnO.cjs');
|
|
6
|
+
const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
|
|
7
|
+
const __opentelemetry_core = require_chunk.__toESM(require("@opentelemetry/core"));
|
|
8
|
+
|
|
9
|
+
//#region src/otel/exporter.ts
|
|
10
|
+
/**
|
|
11
|
+
* A SpanExporter that persists ActivityPub activity traces to a
|
|
12
|
+
* {@link KvStore}. This enables distributed tracing across multiple
|
|
13
|
+
* nodes in a Fedify deployment.
|
|
14
|
+
*
|
|
15
|
+
* The exporter captures activity data from OpenTelemetry span events
|
|
16
|
+
* (`activitypub.activity.received` and `activitypub.activity.sent`)
|
|
17
|
+
* and stores them in the KvStore with trace context preserved.
|
|
18
|
+
*
|
|
19
|
+
* @example Basic usage with MemoryKvStore
|
|
20
|
+
* ```typescript ignore
|
|
21
|
+
* import { MemoryKvStore } from "@fedify/fedify";
|
|
22
|
+
* import { FedifySpanExporter } from "@fedify/fedify/otel";
|
|
23
|
+
* import {
|
|
24
|
+
* BasicTracerProvider,
|
|
25
|
+
* SimpleSpanProcessor,
|
|
26
|
+
* } from "@opentelemetry/sdk-trace-base";
|
|
27
|
+
*
|
|
28
|
+
* const kv = new MemoryKvStore();
|
|
29
|
+
* const exporter = new FedifySpanExporter(kv, {
|
|
30
|
+
* ttl: Temporal.Duration.from({ hours: 1 }),
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* const provider = new BasicTracerProvider({
|
|
34
|
+
* spanProcessors: [new SimpleSpanProcessor(exporter)],
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Querying stored traces
|
|
39
|
+
* ```typescript ignore
|
|
40
|
+
* import { MemoryKvStore } from "@fedify/fedify";
|
|
41
|
+
* import { FedifySpanExporter } from "@fedify/fedify/otel";
|
|
42
|
+
*
|
|
43
|
+
* const kv = new MemoryKvStore();
|
|
44
|
+
* const exporter = new FedifySpanExporter(kv);
|
|
45
|
+
* const traceId = "abc123";
|
|
46
|
+
*
|
|
47
|
+
* // Get all activities for a specific trace
|
|
48
|
+
* const activities = await exporter.getActivitiesByTraceId(traceId);
|
|
49
|
+
*
|
|
50
|
+
* // Get recent traces
|
|
51
|
+
* const recentTraces = await exporter.getRecentTraces({ limit: 100 });
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @since 1.10.0
|
|
55
|
+
*/
|
|
56
|
+
var FedifySpanExporter = class {
|
|
57
|
+
#kv;
|
|
58
|
+
#ttl;
|
|
59
|
+
#keyPrefix;
|
|
60
|
+
/**
|
|
61
|
+
* Creates a new FedifySpanExporter.
|
|
62
|
+
*
|
|
63
|
+
* @param kv The KvStore to persist trace data to.
|
|
64
|
+
* @param options Configuration options.
|
|
65
|
+
*/
|
|
66
|
+
constructor(kv, options) {
|
|
67
|
+
this.#kv = kv;
|
|
68
|
+
this.#ttl = options?.ttl;
|
|
69
|
+
this.#keyPrefix = options?.keyPrefix ?? ["fedify", "traces"];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Exports spans to the KvStore.
|
|
73
|
+
*
|
|
74
|
+
* @param spans The spans to export.
|
|
75
|
+
* @param resultCallback Callback to invoke with the export result.
|
|
76
|
+
*/
|
|
77
|
+
export(spans, resultCallback) {
|
|
78
|
+
this.#exportAsync(spans).then(() => resultCallback({ code: __opentelemetry_core.ExportResultCode.SUCCESS })).catch((error) => {
|
|
79
|
+
(0, __logtape_logtape.getLogger)([
|
|
80
|
+
"fedify",
|
|
81
|
+
"otel",
|
|
82
|
+
"exporter"
|
|
83
|
+
]).error("Failed to export spans to KvStore: {error}", { error });
|
|
84
|
+
resultCallback({ code: __opentelemetry_core.ExportResultCode.FAILED });
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async #exportAsync(spans) {
|
|
88
|
+
const storeOperations = [];
|
|
89
|
+
for (const span of spans) {
|
|
90
|
+
const records = this.#extractRecords(span);
|
|
91
|
+
for (const record of records) storeOperations.push(this.#storeRecord(record));
|
|
92
|
+
}
|
|
93
|
+
const results = await Promise.allSettled(storeOperations);
|
|
94
|
+
const rejected = results.filter((r) => r.status === "rejected");
|
|
95
|
+
if (rejected.length > 0) throw new AggregateError(rejected.map((r) => r.reason), "Failed to store one or more trace activity records.");
|
|
96
|
+
}
|
|
97
|
+
#extractRecords(span) {
|
|
98
|
+
const records = [];
|
|
99
|
+
const spanContext = span.spanContext();
|
|
100
|
+
const traceId = spanContext.traceId;
|
|
101
|
+
const spanId = spanContext.spanId;
|
|
102
|
+
const parentSpanId = span.parentSpanContext?.spanId;
|
|
103
|
+
for (const event of span.events) if (event.name === "activitypub.activity.received") {
|
|
104
|
+
const record = this.#extractInboundRecord(event, traceId, spanId, parentSpanId);
|
|
105
|
+
if (record != null) records.push(record);
|
|
106
|
+
} else if (event.name === "activitypub.activity.sent") {
|
|
107
|
+
const record = this.#extractOutboundRecord(event, traceId, spanId, parentSpanId);
|
|
108
|
+
if (record != null) records.push(record);
|
|
109
|
+
}
|
|
110
|
+
return records;
|
|
111
|
+
}
|
|
112
|
+
#extractInboundRecord(event, traceId, spanId, parentSpanId) {
|
|
113
|
+
const attrs = event.attributes;
|
|
114
|
+
if (attrs == null) return null;
|
|
115
|
+
const activityJson = attrs["activitypub.activity.json"];
|
|
116
|
+
if (typeof activityJson !== "string") return null;
|
|
117
|
+
let activityType = "Unknown";
|
|
118
|
+
let activityId;
|
|
119
|
+
let actorId;
|
|
120
|
+
try {
|
|
121
|
+
const activity = JSON.parse(activityJson);
|
|
122
|
+
activityType = activity.type ?? "Unknown";
|
|
123
|
+
activityId = activity.id;
|
|
124
|
+
if (typeof activity.actor === "string") actorId = activity.actor;
|
|
125
|
+
else if (activity.actor != null && typeof activity.actor.id === "string") actorId = activity.actor.id;
|
|
126
|
+
} catch {}
|
|
127
|
+
const verified = attrs["activitypub.activity.verified"];
|
|
128
|
+
const httpSigVerified = attrs["http_signatures.verified"];
|
|
129
|
+
const httpSigKeyId = attrs["http_signatures.key_id"];
|
|
130
|
+
const ldSigVerified = attrs["ld_signatures.verified"];
|
|
131
|
+
let signatureDetails;
|
|
132
|
+
if (typeof httpSigVerified === "boolean" || typeof ldSigVerified === "boolean") signatureDetails = {
|
|
133
|
+
httpSignaturesVerified: httpSigVerified === true,
|
|
134
|
+
httpSignaturesKeyId: typeof httpSigKeyId === "string" && httpSigKeyId !== "" ? httpSigKeyId : void 0,
|
|
135
|
+
ldSignaturesVerified: ldSigVerified === true
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
traceId,
|
|
139
|
+
spanId,
|
|
140
|
+
parentSpanId,
|
|
141
|
+
direction: "inbound",
|
|
142
|
+
activityType,
|
|
143
|
+
activityId,
|
|
144
|
+
actorId,
|
|
145
|
+
activityJson,
|
|
146
|
+
verified: typeof verified === "boolean" ? verified : void 0,
|
|
147
|
+
signatureDetails,
|
|
148
|
+
timestamp: (/* @__PURE__ */ new Date(event.time[0] * 1e3 + event.time[1] / 1e6)).toISOString()
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
#extractOutboundRecord(event, traceId, spanId, parentSpanId) {
|
|
152
|
+
const attrs = event.attributes;
|
|
153
|
+
if (attrs == null) return null;
|
|
154
|
+
const activityJson = attrs["activitypub.activity.json"];
|
|
155
|
+
if (typeof activityJson !== "string") return null;
|
|
156
|
+
let activityType = "Unknown";
|
|
157
|
+
let activityId;
|
|
158
|
+
let actorId;
|
|
159
|
+
try {
|
|
160
|
+
const activity = JSON.parse(activityJson);
|
|
161
|
+
activityType = activity.type ?? "Unknown";
|
|
162
|
+
activityId = activity.id;
|
|
163
|
+
if (typeof activity.actor === "string") actorId = activity.actor;
|
|
164
|
+
else if (activity.actor != null && typeof activity.actor.id === "string") actorId = activity.actor.id;
|
|
165
|
+
} catch {}
|
|
166
|
+
const inboxUrl = attrs["activitypub.inbox.url"];
|
|
167
|
+
const explicitActivityId = attrs["activitypub.activity.id"];
|
|
168
|
+
return {
|
|
169
|
+
traceId,
|
|
170
|
+
spanId,
|
|
171
|
+
parentSpanId,
|
|
172
|
+
direction: "outbound",
|
|
173
|
+
activityType,
|
|
174
|
+
activityId: activityId ?? (typeof explicitActivityId === "string" && explicitActivityId !== "" ? explicitActivityId : void 0),
|
|
175
|
+
actorId,
|
|
176
|
+
activityJson,
|
|
177
|
+
timestamp: (/* @__PURE__ */ new Date(event.time[0] * 1e3 + event.time[1] / 1e6)).toISOString(),
|
|
178
|
+
inboxUrl: typeof inboxUrl === "string" ? inboxUrl : void 0
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async #storeRecord(record) {
|
|
182
|
+
const options = this.#ttl != null ? { ttl: this.#ttl } : void 0;
|
|
183
|
+
const key = [
|
|
184
|
+
...this.#keyPrefix,
|
|
185
|
+
record.traceId,
|
|
186
|
+
record.spanId
|
|
187
|
+
];
|
|
188
|
+
await this.#kv.set(key, record, options);
|
|
189
|
+
await this.#updateTraceSummary(record, options);
|
|
190
|
+
}
|
|
191
|
+
async #setWithCasRetry(key, transform, options) {
|
|
192
|
+
if (this.#kv.cas != null) for (let attempt = 0; attempt < 3; attempt++) {
|
|
193
|
+
const existing$1 = await this.#kv.get(key);
|
|
194
|
+
const newValue$1 = transform(existing$1);
|
|
195
|
+
if (await this.#kv.cas(key, existing$1, newValue$1, options)) return;
|
|
196
|
+
}
|
|
197
|
+
const existing = await this.#kv.get(key);
|
|
198
|
+
const newValue = transform(existing);
|
|
199
|
+
await this.#kv.set(key, newValue, options);
|
|
200
|
+
}
|
|
201
|
+
async #updateTraceSummary(record, options) {
|
|
202
|
+
const summaryKey = [
|
|
203
|
+
...this.#keyPrefix,
|
|
204
|
+
"_summaries",
|
|
205
|
+
record.traceId
|
|
206
|
+
];
|
|
207
|
+
await this.#setWithCasRetry(summaryKey, (existing) => {
|
|
208
|
+
const activityCount = existing != null ? existing.activityCount + 1 : 1;
|
|
209
|
+
const activityTypes = existing != null ? existing.activityTypes.includes(record.activityType) ? existing.activityTypes : [...existing.activityTypes, record.activityType] : [record.activityType];
|
|
210
|
+
return {
|
|
211
|
+
traceId: existing?.traceId ?? record.traceId,
|
|
212
|
+
timestamp: existing?.timestamp ?? record.timestamp,
|
|
213
|
+
activityCount,
|
|
214
|
+
activityTypes
|
|
215
|
+
};
|
|
216
|
+
}, options);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Gets all activity records for a specific trace ID.
|
|
220
|
+
*
|
|
221
|
+
* @param traceId The trace ID to query.
|
|
222
|
+
* @returns An array of activity records belonging to the trace.
|
|
223
|
+
*/
|
|
224
|
+
async getActivitiesByTraceId(traceId) {
|
|
225
|
+
const prefix = [...this.#keyPrefix, traceId];
|
|
226
|
+
const records = [];
|
|
227
|
+
for await (const entry of this.#kv.list(prefix)) records.push(entry.value);
|
|
228
|
+
return records;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Gets recent traces with summary information.
|
|
232
|
+
*
|
|
233
|
+
* @param options Options for the query.
|
|
234
|
+
* @returns An array of trace summaries.
|
|
235
|
+
*/
|
|
236
|
+
async getRecentTraces(options) {
|
|
237
|
+
const summaryPrefix = [...this.#keyPrefix, "_summaries"];
|
|
238
|
+
const summaries = [];
|
|
239
|
+
for await (const entry of this.#kv.list(summaryPrefix)) summaries.push(entry.value);
|
|
240
|
+
summaries.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
241
|
+
if (options?.limit != null) return summaries.slice(0, options.limit);
|
|
242
|
+
return summaries;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Forces the exporter to flush any buffered data.
|
|
246
|
+
* This is a no-op because we write directly to the KvStore without buffering.
|
|
247
|
+
*/
|
|
248
|
+
async forceFlush() {}
|
|
249
|
+
/**
|
|
250
|
+
* Shuts down the exporter.
|
|
251
|
+
*/
|
|
252
|
+
async shutdown() {}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
//#endregion
|
|
256
|
+
exports.FedifySpanExporter = FedifySpanExporter;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { KvKey, KvStore } from "../kv-B4vFhIYL.cjs";
|
|
2
|
+
import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
|
|
3
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
4
|
+
|
|
5
|
+
//#region src/otel/exporter.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The direction of an activity in the trace.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.10.0
|
|
10
|
+
*/
|
|
11
|
+
type ActivityDirection = "inbound" | "outbound";
|
|
12
|
+
/**
|
|
13
|
+
* Signature verification details for an inbound activity.
|
|
14
|
+
*
|
|
15
|
+
* @since 1.10.0
|
|
16
|
+
*/
|
|
17
|
+
interface SignatureVerificationDetails {
|
|
18
|
+
/**
|
|
19
|
+
* Whether HTTP Signatures were verified.
|
|
20
|
+
*/
|
|
21
|
+
readonly httpSignaturesVerified: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* The key ID used for HTTP signature verification, if available.
|
|
24
|
+
*/
|
|
25
|
+
readonly httpSignaturesKeyId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether Linked Data Signatures were verified.
|
|
28
|
+
*/
|
|
29
|
+
readonly ldSignaturesVerified: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A record of an activity captured from a trace span.
|
|
33
|
+
* This interface stores the activity data along with trace context
|
|
34
|
+
* for distributed tracing support.
|
|
35
|
+
*
|
|
36
|
+
* @since 1.10.0
|
|
37
|
+
*/
|
|
38
|
+
interface TraceActivityRecord {
|
|
39
|
+
/**
|
|
40
|
+
* The trace ID from OpenTelemetry.
|
|
41
|
+
*/
|
|
42
|
+
readonly traceId: string;
|
|
43
|
+
/**
|
|
44
|
+
* The span ID from OpenTelemetry.
|
|
45
|
+
*/
|
|
46
|
+
readonly spanId: string;
|
|
47
|
+
/**
|
|
48
|
+
* The parent span ID, if any.
|
|
49
|
+
*/
|
|
50
|
+
readonly parentSpanId?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Whether this is an inbound or outbound activity.
|
|
53
|
+
*/
|
|
54
|
+
readonly direction: ActivityDirection;
|
|
55
|
+
/**
|
|
56
|
+
* The ActivityPub activity type (e.g., "Create", "Follow", "Like").
|
|
57
|
+
*/
|
|
58
|
+
readonly activityType: string;
|
|
59
|
+
/**
|
|
60
|
+
* The activity's ID URL, if present.
|
|
61
|
+
*/
|
|
62
|
+
readonly activityId?: string;
|
|
63
|
+
/**
|
|
64
|
+
* The actor ID URL (sender of the activity).
|
|
65
|
+
*/
|
|
66
|
+
readonly actorId?: string;
|
|
67
|
+
/**
|
|
68
|
+
* The full JSON representation of the activity.
|
|
69
|
+
*/
|
|
70
|
+
readonly activityJson: string;
|
|
71
|
+
/**
|
|
72
|
+
* Whether the activity was verified (for inbound activities).
|
|
73
|
+
*/
|
|
74
|
+
readonly verified?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Detailed signature verification information (for inbound activities).
|
|
77
|
+
*/
|
|
78
|
+
readonly signatureDetails?: SignatureVerificationDetails;
|
|
79
|
+
/**
|
|
80
|
+
* The timestamp when this record was created (ISO 8601 format).
|
|
81
|
+
*/
|
|
82
|
+
readonly timestamp: string;
|
|
83
|
+
/**
|
|
84
|
+
* The target inbox URL (for outbound activities).
|
|
85
|
+
*/
|
|
86
|
+
readonly inboxUrl?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Summary information about a trace.
|
|
90
|
+
*
|
|
91
|
+
* @since 1.10.0
|
|
92
|
+
*/
|
|
93
|
+
interface TraceSummary {
|
|
94
|
+
/**
|
|
95
|
+
* The trace ID.
|
|
96
|
+
*/
|
|
97
|
+
readonly traceId: string;
|
|
98
|
+
/**
|
|
99
|
+
* The timestamp of the first activity in the trace.
|
|
100
|
+
*/
|
|
101
|
+
readonly timestamp: string;
|
|
102
|
+
/**
|
|
103
|
+
* The number of activities in the trace.
|
|
104
|
+
*/
|
|
105
|
+
readonly activityCount: number;
|
|
106
|
+
/**
|
|
107
|
+
* Activity types present in this trace.
|
|
108
|
+
*/
|
|
109
|
+
readonly activityTypes: readonly string[];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Options for configuring the {@link FedifySpanExporter}.
|
|
113
|
+
*
|
|
114
|
+
* @since 1.10.0
|
|
115
|
+
*/
|
|
116
|
+
interface FedifySpanExporterOptions {
|
|
117
|
+
/**
|
|
118
|
+
* The time-to-live for stored trace data.
|
|
119
|
+
* If not specified, data will be stored indefinitely
|
|
120
|
+
* (or until manually deleted).
|
|
121
|
+
*/
|
|
122
|
+
readonly ttl?: Temporal.Duration;
|
|
123
|
+
/**
|
|
124
|
+
* The key prefix for storing trace data in the KvStore.
|
|
125
|
+
* Defaults to `["fedify", "traces"]`.
|
|
126
|
+
*/
|
|
127
|
+
readonly keyPrefix?: KvKey;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Options for the {@link FedifySpanExporter.getRecentTraces} method.
|
|
131
|
+
*
|
|
132
|
+
* @since 1.10.0
|
|
133
|
+
*/
|
|
134
|
+
interface GetRecentTracesOptions {
|
|
135
|
+
/**
|
|
136
|
+
* Maximum number of traces to return.
|
|
137
|
+
* If not specified, returns all available traces.
|
|
138
|
+
*/
|
|
139
|
+
limit?: number;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A SpanExporter that persists ActivityPub activity traces to a
|
|
143
|
+
* {@link KvStore}. This enables distributed tracing across multiple
|
|
144
|
+
* nodes in a Fedify deployment.
|
|
145
|
+
*
|
|
146
|
+
* The exporter captures activity data from OpenTelemetry span events
|
|
147
|
+
* (`activitypub.activity.received` and `activitypub.activity.sent`)
|
|
148
|
+
* and stores them in the KvStore with trace context preserved.
|
|
149
|
+
*
|
|
150
|
+
* @example Basic usage with MemoryKvStore
|
|
151
|
+
* ```typescript ignore
|
|
152
|
+
* import { MemoryKvStore } from "@fedify/fedify";
|
|
153
|
+
* import { FedifySpanExporter } from "@fedify/fedify/otel";
|
|
154
|
+
* import {
|
|
155
|
+
* BasicTracerProvider,
|
|
156
|
+
* SimpleSpanProcessor,
|
|
157
|
+
* } from "@opentelemetry/sdk-trace-base";
|
|
158
|
+
*
|
|
159
|
+
* const kv = new MemoryKvStore();
|
|
160
|
+
* const exporter = new FedifySpanExporter(kv, {
|
|
161
|
+
* ttl: Temporal.Duration.from({ hours: 1 }),
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* const provider = new BasicTracerProvider({
|
|
165
|
+
* spanProcessors: [new SimpleSpanProcessor(exporter)],
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @example Querying stored traces
|
|
170
|
+
* ```typescript ignore
|
|
171
|
+
* import { MemoryKvStore } from "@fedify/fedify";
|
|
172
|
+
* import { FedifySpanExporter } from "@fedify/fedify/otel";
|
|
173
|
+
*
|
|
174
|
+
* const kv = new MemoryKvStore();
|
|
175
|
+
* const exporter = new FedifySpanExporter(kv);
|
|
176
|
+
* const traceId = "abc123";
|
|
177
|
+
*
|
|
178
|
+
* // Get all activities for a specific trace
|
|
179
|
+
* const activities = await exporter.getActivitiesByTraceId(traceId);
|
|
180
|
+
*
|
|
181
|
+
* // Get recent traces
|
|
182
|
+
* const recentTraces = await exporter.getRecentTraces({ limit: 100 });
|
|
183
|
+
* ```
|
|
184
|
+
*
|
|
185
|
+
* @since 1.10.0
|
|
186
|
+
*/
|
|
187
|
+
declare class FedifySpanExporter implements SpanExporter {
|
|
188
|
+
#private;
|
|
189
|
+
/**
|
|
190
|
+
* Creates a new FedifySpanExporter.
|
|
191
|
+
*
|
|
192
|
+
* @param kv The KvStore to persist trace data to.
|
|
193
|
+
* @param options Configuration options.
|
|
194
|
+
*/
|
|
195
|
+
constructor(kv: KvStore, options?: FedifySpanExporterOptions);
|
|
196
|
+
/**
|
|
197
|
+
* Exports spans to the KvStore.
|
|
198
|
+
*
|
|
199
|
+
* @param spans The spans to export.
|
|
200
|
+
* @param resultCallback Callback to invoke with the export result.
|
|
201
|
+
*/
|
|
202
|
+
export(spans: ReadableSpan[], resultCallback: (result: {
|
|
203
|
+
code: ExportResultCode;
|
|
204
|
+
}) => void): void;
|
|
205
|
+
/**
|
|
206
|
+
* Gets all activity records for a specific trace ID.
|
|
207
|
+
*
|
|
208
|
+
* @param traceId The trace ID to query.
|
|
209
|
+
* @returns An array of activity records belonging to the trace.
|
|
210
|
+
*/
|
|
211
|
+
getActivitiesByTraceId(traceId: string): Promise<TraceActivityRecord[]>;
|
|
212
|
+
/**
|
|
213
|
+
* Gets recent traces with summary information.
|
|
214
|
+
*
|
|
215
|
+
* @param options Options for the query.
|
|
216
|
+
* @returns An array of trace summaries.
|
|
217
|
+
*/
|
|
218
|
+
getRecentTraces(options?: GetRecentTracesOptions): Promise<TraceSummary[]>;
|
|
219
|
+
/**
|
|
220
|
+
* Forces the exporter to flush any buffered data.
|
|
221
|
+
* This is a no-op because we write directly to the KvStore without buffering.
|
|
222
|
+
*/
|
|
223
|
+
forceFlush(): Promise<void>;
|
|
224
|
+
/**
|
|
225
|
+
* Shuts down the exporter.
|
|
226
|
+
*/
|
|
227
|
+
shutdown(): Promise<void>;
|
|
228
|
+
}
|
|
229
|
+
//#endregion
|
|
230
|
+
export { ActivityDirection, FedifySpanExporter, FedifySpanExporterOptions, GetRecentTracesOptions, SignatureVerificationDetails, TraceActivityRecord, TraceSummary };
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
+
import { KvKey, KvStore } from "../kv-CYySNrsn.js";
|
|
4
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
5
|
+
import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
|
|
6
|
+
|
|
7
|
+
//#region src/otel/exporter.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* The direction of an activity in the trace.
|
|
10
|
+
*
|
|
11
|
+
* @since 1.10.0
|
|
12
|
+
*/
|
|
13
|
+
type ActivityDirection = "inbound" | "outbound";
|
|
14
|
+
/**
|
|
15
|
+
* Signature verification details for an inbound activity.
|
|
16
|
+
*
|
|
17
|
+
* @since 1.10.0
|
|
18
|
+
*/
|
|
19
|
+
interface SignatureVerificationDetails {
|
|
20
|
+
/**
|
|
21
|
+
* Whether HTTP Signatures were verified.
|
|
22
|
+
*/
|
|
23
|
+
readonly httpSignaturesVerified: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The key ID used for HTTP signature verification, if available.
|
|
26
|
+
*/
|
|
27
|
+
readonly httpSignaturesKeyId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Whether Linked Data Signatures were verified.
|
|
30
|
+
*/
|
|
31
|
+
readonly ldSignaturesVerified: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A record of an activity captured from a trace span.
|
|
35
|
+
* This interface stores the activity data along with trace context
|
|
36
|
+
* for distributed tracing support.
|
|
37
|
+
*
|
|
38
|
+
* @since 1.10.0
|
|
39
|
+
*/
|
|
40
|
+
interface TraceActivityRecord {
|
|
41
|
+
/**
|
|
42
|
+
* The trace ID from OpenTelemetry.
|
|
43
|
+
*/
|
|
44
|
+
readonly traceId: string;
|
|
45
|
+
/**
|
|
46
|
+
* The span ID from OpenTelemetry.
|
|
47
|
+
*/
|
|
48
|
+
readonly spanId: string;
|
|
49
|
+
/**
|
|
50
|
+
* The parent span ID, if any.
|
|
51
|
+
*/
|
|
52
|
+
readonly parentSpanId?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Whether this is an inbound or outbound activity.
|
|
55
|
+
*/
|
|
56
|
+
readonly direction: ActivityDirection;
|
|
57
|
+
/**
|
|
58
|
+
* The ActivityPub activity type (e.g., "Create", "Follow", "Like").
|
|
59
|
+
*/
|
|
60
|
+
readonly activityType: string;
|
|
61
|
+
/**
|
|
62
|
+
* The activity's ID URL, if present.
|
|
63
|
+
*/
|
|
64
|
+
readonly activityId?: string;
|
|
65
|
+
/**
|
|
66
|
+
* The actor ID URL (sender of the activity).
|
|
67
|
+
*/
|
|
68
|
+
readonly actorId?: string;
|
|
69
|
+
/**
|
|
70
|
+
* The full JSON representation of the activity.
|
|
71
|
+
*/
|
|
72
|
+
readonly activityJson: string;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the activity was verified (for inbound activities).
|
|
75
|
+
*/
|
|
76
|
+
readonly verified?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Detailed signature verification information (for inbound activities).
|
|
79
|
+
*/
|
|
80
|
+
readonly signatureDetails?: SignatureVerificationDetails;
|
|
81
|
+
/**
|
|
82
|
+
* The timestamp when this record was created (ISO 8601 format).
|
|
83
|
+
*/
|
|
84
|
+
readonly timestamp: string;
|
|
85
|
+
/**
|
|
86
|
+
* The target inbox URL (for outbound activities).
|
|
87
|
+
*/
|
|
88
|
+
readonly inboxUrl?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Summary information about a trace.
|
|
92
|
+
*
|
|
93
|
+
* @since 1.10.0
|
|
94
|
+
*/
|
|
95
|
+
interface TraceSummary {
|
|
96
|
+
/**
|
|
97
|
+
* The trace ID.
|
|
98
|
+
*/
|
|
99
|
+
readonly traceId: string;
|
|
100
|
+
/**
|
|
101
|
+
* The timestamp of the first activity in the trace.
|
|
102
|
+
*/
|
|
103
|
+
readonly timestamp: string;
|
|
104
|
+
/**
|
|
105
|
+
* The number of activities in the trace.
|
|
106
|
+
*/
|
|
107
|
+
readonly activityCount: number;
|
|
108
|
+
/**
|
|
109
|
+
* Activity types present in this trace.
|
|
110
|
+
*/
|
|
111
|
+
readonly activityTypes: readonly string[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Options for configuring the {@link FedifySpanExporter}.
|
|
115
|
+
*
|
|
116
|
+
* @since 1.10.0
|
|
117
|
+
*/
|
|
118
|
+
interface FedifySpanExporterOptions {
|
|
119
|
+
/**
|
|
120
|
+
* The time-to-live for stored trace data.
|
|
121
|
+
* If not specified, data will be stored indefinitely
|
|
122
|
+
* (or until manually deleted).
|
|
123
|
+
*/
|
|
124
|
+
readonly ttl?: Temporal.Duration;
|
|
125
|
+
/**
|
|
126
|
+
* The key prefix for storing trace data in the KvStore.
|
|
127
|
+
* Defaults to `["fedify", "traces"]`.
|
|
128
|
+
*/
|
|
129
|
+
readonly keyPrefix?: KvKey;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Options for the {@link FedifySpanExporter.getRecentTraces} method.
|
|
133
|
+
*
|
|
134
|
+
* @since 1.10.0
|
|
135
|
+
*/
|
|
136
|
+
interface GetRecentTracesOptions {
|
|
137
|
+
/**
|
|
138
|
+
* Maximum number of traces to return.
|
|
139
|
+
* If not specified, returns all available traces.
|
|
140
|
+
*/
|
|
141
|
+
limit?: number;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A SpanExporter that persists ActivityPub activity traces to a
|
|
145
|
+
* {@link KvStore}. This enables distributed tracing across multiple
|
|
146
|
+
* nodes in a Fedify deployment.
|
|
147
|
+
*
|
|
148
|
+
* The exporter captures activity data from OpenTelemetry span events
|
|
149
|
+
* (`activitypub.activity.received` and `activitypub.activity.sent`)
|
|
150
|
+
* and stores them in the KvStore with trace context preserved.
|
|
151
|
+
*
|
|
152
|
+
* @example Basic usage with MemoryKvStore
|
|
153
|
+
* ```typescript ignore
|
|
154
|
+
* import { MemoryKvStore } from "@fedify/fedify";
|
|
155
|
+
* import { FedifySpanExporter } from "@fedify/fedify/otel";
|
|
156
|
+
* import {
|
|
157
|
+
* BasicTracerProvider,
|
|
158
|
+
* SimpleSpanProcessor,
|
|
159
|
+
* } from "@opentelemetry/sdk-trace-base";
|
|
160
|
+
*
|
|
161
|
+
* const kv = new MemoryKvStore();
|
|
162
|
+
* const exporter = new FedifySpanExporter(kv, {
|
|
163
|
+
* ttl: Temporal.Duration.from({ hours: 1 }),
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* const provider = new BasicTracerProvider({
|
|
167
|
+
* spanProcessors: [new SimpleSpanProcessor(exporter)],
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @example Querying stored traces
|
|
172
|
+
* ```typescript ignore
|
|
173
|
+
* import { MemoryKvStore } from "@fedify/fedify";
|
|
174
|
+
* import { FedifySpanExporter } from "@fedify/fedify/otel";
|
|
175
|
+
*
|
|
176
|
+
* const kv = new MemoryKvStore();
|
|
177
|
+
* const exporter = new FedifySpanExporter(kv);
|
|
178
|
+
* const traceId = "abc123";
|
|
179
|
+
*
|
|
180
|
+
* // Get all activities for a specific trace
|
|
181
|
+
* const activities = await exporter.getActivitiesByTraceId(traceId);
|
|
182
|
+
*
|
|
183
|
+
* // Get recent traces
|
|
184
|
+
* const recentTraces = await exporter.getRecentTraces({ limit: 100 });
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* @since 1.10.0
|
|
188
|
+
*/
|
|
189
|
+
declare class FedifySpanExporter implements SpanExporter {
|
|
190
|
+
#private;
|
|
191
|
+
/**
|
|
192
|
+
* Creates a new FedifySpanExporter.
|
|
193
|
+
*
|
|
194
|
+
* @param kv The KvStore to persist trace data to.
|
|
195
|
+
* @param options Configuration options.
|
|
196
|
+
*/
|
|
197
|
+
constructor(kv: KvStore, options?: FedifySpanExporterOptions);
|
|
198
|
+
/**
|
|
199
|
+
* Exports spans to the KvStore.
|
|
200
|
+
*
|
|
201
|
+
* @param spans The spans to export.
|
|
202
|
+
* @param resultCallback Callback to invoke with the export result.
|
|
203
|
+
*/
|
|
204
|
+
export(spans: ReadableSpan[], resultCallback: (result: {
|
|
205
|
+
code: ExportResultCode;
|
|
206
|
+
}) => void): void;
|
|
207
|
+
/**
|
|
208
|
+
* Gets all activity records for a specific trace ID.
|
|
209
|
+
*
|
|
210
|
+
* @param traceId The trace ID to query.
|
|
211
|
+
* @returns An array of activity records belonging to the trace.
|
|
212
|
+
*/
|
|
213
|
+
getActivitiesByTraceId(traceId: string): Promise<TraceActivityRecord[]>;
|
|
214
|
+
/**
|
|
215
|
+
* Gets recent traces with summary information.
|
|
216
|
+
*
|
|
217
|
+
* @param options Options for the query.
|
|
218
|
+
* @returns An array of trace summaries.
|
|
219
|
+
*/
|
|
220
|
+
getRecentTraces(options?: GetRecentTracesOptions): Promise<TraceSummary[]>;
|
|
221
|
+
/**
|
|
222
|
+
* Forces the exporter to flush any buffered data.
|
|
223
|
+
* This is a no-op because we write directly to the KvStore without buffering.
|
|
224
|
+
*/
|
|
225
|
+
forceFlush(): Promise<void>;
|
|
226
|
+
/**
|
|
227
|
+
* Shuts down the exporter.
|
|
228
|
+
*/
|
|
229
|
+
shutdown(): Promise<void>;
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
export { ActivityDirection, FedifySpanExporter, FedifySpanExporterOptions, GetRecentTracesOptions, SignatureVerificationDetails, TraceActivityRecord, TraceSummary };
|