@sdxc/activitypub 0.0.0-pre.1

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 (73) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +711 -0
  3. package/dist/collections.d.ts +67 -0
  4. package/dist/collections.js +38 -0
  5. package/dist/conformance.d.ts +80 -0
  6. package/dist/conformance.js +313 -0
  7. package/dist/discovery.d.ts +46 -0
  8. package/dist/discovery.js +105 -0
  9. package/dist/errors.d.ts +115 -0
  10. package/dist/errors.js +124 -0
  11. package/dist/federation.d.ts +281 -0
  12. package/dist/federation.js +513 -0
  13. package/dist/fixtures/gotosocial.d.ts +114 -0
  14. package/dist/fixtures/gotosocial.js +115 -0
  15. package/dist/fixtures/index.d.ts +15 -0
  16. package/dist/fixtures/index.js +50 -0
  17. package/dist/fixtures/mastodon.d.ts +489 -0
  18. package/dist/fixtures/mastodon.js +334 -0
  19. package/dist/fixtures/misskey.d.ts +254 -0
  20. package/dist/fixtures/misskey.js +163 -0
  21. package/dist/fixtures/pixelfed.d.ts +118 -0
  22. package/dist/fixtures/pixelfed.js +126 -0
  23. package/dist/fixtures/shared.d.ts +14 -0
  24. package/dist/fixtures/shared.js +14 -0
  25. package/dist/fixtures/threads.d.ts +82 -0
  26. package/dist/fixtures/threads.js +88 -0
  27. package/dist/index.d.ts +33 -0
  28. package/dist/index.js +22 -0
  29. package/dist/keys.d.ts +100 -0
  30. package/dist/keys.js +147 -0
  31. package/dist/lib/availability.d.ts +37 -0
  32. package/dist/lib/availability.js +52 -0
  33. package/dist/lib/compact.d.ts +145 -0
  34. package/dist/lib/compact.js +514 -0
  35. package/dist/lib/constants.d.ts +35 -0
  36. package/dist/lib/constants.js +65 -0
  37. package/dist/lib/delivery-fan-out.d.ts +72 -0
  38. package/dist/lib/delivery-fan-out.js +202 -0
  39. package/dist/lib/delivery-post.d.ts +108 -0
  40. package/dist/lib/delivery-post.js +318 -0
  41. package/dist/lib/fetch.d.ts +64 -0
  42. package/dist/lib/fetch.js +103 -0
  43. package/dist/lib/inbox-error.d.ts +45 -0
  44. package/dist/lib/inbox-error.js +74 -0
  45. package/dist/lib/inbox-handle.d.ts +119 -0
  46. package/dist/lib/inbox-handle.js +587 -0
  47. package/dist/lib/inbox-receive.d.ts +117 -0
  48. package/dist/lib/inbox-receive.js +233 -0
  49. package/dist/lib/inbox-signature.d.ts +61 -0
  50. package/dist/lib/inbox-signature.js +156 -0
  51. package/dist/lib/inbox-summarize.d.ts +41 -0
  52. package/dist/lib/inbox-summarize.js +97 -0
  53. package/dist/lib/messages.d.ts +36 -0
  54. package/dist/lib/messages.js +35 -0
  55. package/dist/lib/parse.d.ts +42 -0
  56. package/dist/lib/parse.js +348 -0
  57. package/dist/lib/response.d.ts +45 -0
  58. package/dist/lib/response.js +59 -0
  59. package/dist/lib/stringify.d.ts +51 -0
  60. package/dist/lib/stringify.js +122 -0
  61. package/dist/lib/tombstone.d.ts +24 -0
  62. package/dist/lib/tombstone.js +15 -0
  63. package/dist/lib/types.d.ts +249 -0
  64. package/dist/lib/types.js +0 -0
  65. package/dist/memory.d.ts +77 -0
  66. package/dist/memory.js +146 -0
  67. package/dist/remote.d.ts +105 -0
  68. package/dist/remote.js +262 -0
  69. package/dist/store.d.ts +78 -0
  70. package/dist/store.js +8 -0
  71. package/dist/testing.d.ts +12 -0
  72. package/dist/testing.js +10 -0
  73. package/package.json +54 -0
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Documents in the shapes Misskey emits: its actor with the `misskey:` context, a reply,
3
+ * an emoji reaction sent as a Like with `content` and `_misskey_reaction`, a quote by
4
+ * `_misskey_quote` and `quoteUrl`, and a follow. Ids are made up; the members are Misskey's.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ import { FAKE_PUBLIC_KEY_PEM, LOCAL_ACTOR, LOCAL_ARTICLE } from "./shared.js";
10
+ /** The `@context` Misskey writes on every document. */
11
+ const CONTEXT = [
12
+ "https://www.w3.org/ns/activitystreams",
13
+ "https://w3id.org/security/v1",
14
+ {
15
+ Key: "sec:Key",
16
+ manuallyApprovesFollowers: "as:manuallyApprovesFollowers",
17
+ sensitive: "as:sensitive",
18
+ Hashtag: "as:Hashtag",
19
+ quoteUrl: "as:quoteUrl",
20
+ toot: "http://joinmastodon.org/ns#",
21
+ Emoji: "toot:Emoji",
22
+ featured: "toot:featured",
23
+ discoverable: "toot:discoverable",
24
+ schema: "http://schema.org#",
25
+ PropertyValue: "schema:PropertyValue",
26
+ value: "schema:value",
27
+ misskey: "https://misskey-hub.net/ns#",
28
+ _misskey_content: "misskey:_misskey_content",
29
+ _misskey_quote: "misskey:_misskey_quote",
30
+ _misskey_reaction: "misskey:_misskey_reaction",
31
+ _misskey_votes: "misskey:_misskey_votes",
32
+ _misskey_summary: "misskey:_misskey_summary",
33
+ isCat: "misskey:isCat",
34
+ vcard: "http://www.w3.org/2006/vcard/ns#",
35
+ },
36
+ ];
37
+ /** The custom emoji Misskey attaches wherever a document names `:blobcat:`. */
38
+ const BLOBCAT = {
39
+ id: "https://misskey.io/emojis/blobcat",
40
+ type: "Emoji",
41
+ name: ":blobcat:",
42
+ updated: "2023-05-01T10:00:00.000Z",
43
+ icon: {
44
+ type: "Image",
45
+ mediaType: "image/png",
46
+ url: "https://media.misskey-io.jp/emoji/blobcat.png",
47
+ },
48
+ };
49
+ /** A Misskey account: a separate `sharedInbox` member, a typed `Key`, and `isCat`. */
50
+ export const MISSKEY_ACTOR = {
51
+ "@context": CONTEXT,
52
+ type: "Person",
53
+ id: "https://misskey.io/users/9k2xq3h7c1",
54
+ inbox: "https://misskey.io/users/9k2xq3h7c1/inbox",
55
+ outbox: "https://misskey.io/users/9k2xq3h7c1/outbox",
56
+ followers: "https://misskey.io/users/9k2xq3h7c1/followers",
57
+ following: "https://misskey.io/users/9k2xq3h7c1/following",
58
+ featured: "https://misskey.io/users/9k2xq3h7c1/collections/featured",
59
+ sharedInbox: "https://misskey.io/inbox",
60
+ endpoints: { sharedInbox: "https://misskey.io/inbox" },
61
+ url: "https://misskey.io/@carol",
62
+ preferredUsername: "carol",
63
+ name: "Carol :blobcat:",
64
+ summary: "<p><span>Drawing cats, mostly.</span></p>",
65
+ _misskey_summary: "Drawing cats, mostly.",
66
+ icon: {
67
+ type: "Image",
68
+ url: "https://media.misskey-io.jp/files/webpublic-0a1b2c3d.webp",
69
+ sensitive: false,
70
+ name: null,
71
+ },
72
+ image: null,
73
+ tag: [BLOBCAT],
74
+ manuallyApprovesFollowers: false,
75
+ discoverable: true,
76
+ publicKey: {
77
+ id: "https://misskey.io/users/9k2xq3h7c1#main-key",
78
+ type: "Key",
79
+ owner: "https://misskey.io/users/9k2xq3h7c1",
80
+ publicKeyPem: FAKE_PUBLIC_KEY_PEM,
81
+ },
82
+ isCat: true,
83
+ attachment: [
84
+ {
85
+ type: "PropertyValue",
86
+ name: "Portfolio",
87
+ value: '<a href="https://carol.art" rel="me nofollow noopener" target="_blank">https://carol.art</a>',
88
+ },
89
+ ],
90
+ };
91
+ /** A reply to a local article, with Misskey's markdown source kept beside the HTML. */
92
+ export const MISSKEY_CREATE_NOTE = {
93
+ "@context": CONTEXT,
94
+ id: "https://misskey.io/notes/9k3a1b2c3d/activity",
95
+ actor: "https://misskey.io/users/9k2xq3h7c1",
96
+ type: "Create",
97
+ published: "2026-10-02T08:00:00.000Z",
98
+ object: {
99
+ id: "https://misskey.io/notes/9k3a1b2c3d",
100
+ type: "Note",
101
+ attributedTo: "https://misskey.io/users/9k2xq3h7c1",
102
+ content: '<p><a href="https://letters.blog/@hello" class="u-url mention">@hello@letters.blog</a><span> Lovely :blobcat:</span></p>',
103
+ _misskey_content: "@hello@letters.blog Lovely :blobcat:",
104
+ source: {
105
+ content: "@hello@letters.blog Lovely :blobcat:",
106
+ mediaType: "text/x.misskeymarkdown",
107
+ },
108
+ published: "2026-10-02T08:00:00.000Z",
109
+ to: ["https://www.w3.org/ns/activitystreams#Public"],
110
+ cc: ["https://misskey.io/users/9k2xq3h7c1/followers", LOCAL_ACTOR],
111
+ inReplyTo: LOCAL_ARTICLE,
112
+ attachment: [],
113
+ sensitive: false,
114
+ tag: [{ type: "Mention", href: LOCAL_ACTOR, name: "@hello@letters.blog" }, BLOBCAT],
115
+ },
116
+ to: ["https://www.w3.org/ns/activitystreams#Public"],
117
+ cc: ["https://misskey.io/users/9k2xq3h7c1/followers", LOCAL_ACTOR],
118
+ };
119
+ /** An emoji reaction: a Like whose `content` and `_misskey_reaction` name the emoji. */
120
+ export const MISSKEY_REACTION = {
121
+ "@context": CONTEXT,
122
+ type: "Like",
123
+ id: "https://misskey.io/likes/9k3b4c5d6e",
124
+ actor: "https://misskey.io/users/9k2xq3h7c1",
125
+ object: LOCAL_ARTICLE,
126
+ content: ":blobcat:",
127
+ _misskey_reaction: ":blobcat:",
128
+ tag: [BLOBCAT],
129
+ };
130
+ /** A quote of a local article, named by `_misskey_quote` and `quoteUrl`. */
131
+ export const MISSKEY_QUOTE = {
132
+ "@context": CONTEXT,
133
+ id: "https://misskey.io/notes/9k3c7d8e9f/activity",
134
+ actor: "https://misskey.io/users/9k2xq3h7c1",
135
+ type: "Create",
136
+ published: "2026-10-02T09:30:00.000Z",
137
+ object: {
138
+ id: "https://misskey.io/notes/9k3c7d8e9f",
139
+ type: "Note",
140
+ attributedTo: "https://misskey.io/users/9k2xq3h7c1",
141
+ content: '<p><span>This one</span><span class="quote-inline"><br><br>RE: <a href="https://letters.blog/articles/remix-v3">https://letters.blog/articles/remix-v3</a></span></p>',
142
+ _misskey_content: "This one",
143
+ _misskey_quote: LOCAL_ARTICLE,
144
+ quoteUrl: LOCAL_ARTICLE,
145
+ published: "2026-10-02T09:30:00.000Z",
146
+ to: ["https://www.w3.org/ns/activitystreams#Public"],
147
+ cc: ["https://misskey.io/users/9k2xq3h7c1/followers"],
148
+ inReplyTo: null,
149
+ attachment: [],
150
+ sensitive: false,
151
+ tag: [],
152
+ },
153
+ to: ["https://www.w3.org/ns/activitystreams#Public"],
154
+ cc: ["https://misskey.io/users/9k2xq3h7c1/followers"],
155
+ };
156
+ /** A follow of the local actor; Misskey ids it by follower and followee. */
157
+ export const MISSKEY_FOLLOW = {
158
+ "@context": CONTEXT,
159
+ id: "https://misskey.io/follows/9k2xq3h7c1/9k3d0e1f2a",
160
+ type: "Follow",
161
+ actor: "https://misskey.io/users/9k2xq3h7c1",
162
+ object: LOCAL_ACTOR,
163
+ };
@@ -0,0 +1,118 @@
1
+ /** A Pixelfed account. */
2
+ export declare const PIXELFED_ACTOR: {
3
+ "@context": (string | {
4
+ toot: string;
5
+ manuallyApprovesFollowers: string;
6
+ alsoKnownAs: {
7
+ "@id": string;
8
+ "@type": string;
9
+ };
10
+ movedTo: {
11
+ "@id": string;
12
+ "@type": string;
13
+ };
14
+ indexable: string;
15
+ suspended: string;
16
+ })[];
17
+ id: string;
18
+ type: string;
19
+ following: string;
20
+ followers: string;
21
+ inbox: string;
22
+ outbox: string;
23
+ preferredUsername: string;
24
+ name: string;
25
+ summary: string;
26
+ url: string;
27
+ manuallyApprovesFollowers: boolean;
28
+ indexable: boolean;
29
+ published: string;
30
+ publicKey: {
31
+ id: string;
32
+ owner: string;
33
+ publicKeyPem: string;
34
+ };
35
+ icon: {
36
+ type: string;
37
+ mediaType: string;
38
+ url: string;
39
+ };
40
+ endpoints: {
41
+ sharedInbox: string;
42
+ };
43
+ };
44
+ /** A photo post with two images and a hashtag. */
45
+ export declare const PIXELFED_CREATE_NOTE: {
46
+ "@context": (string | {
47
+ Hashtag: string;
48
+ sensitive: string;
49
+ commentsEnabled: {
50
+ "@id": string;
51
+ "@type": string;
52
+ };
53
+ capabilities: {
54
+ "@id": string;
55
+ "@container": string;
56
+ };
57
+ pixelfed: string;
58
+ schema: string;
59
+ blurhash: string;
60
+ toot: string;
61
+ })[];
62
+ id: string;
63
+ type: string;
64
+ actor: string;
65
+ published: string;
66
+ to: string[];
67
+ cc: string[];
68
+ object: {
69
+ id: string;
70
+ type: string;
71
+ summary: null;
72
+ content: string;
73
+ inReplyTo: null;
74
+ published: string;
75
+ url: string;
76
+ attributedTo: string;
77
+ to: string[];
78
+ cc: string[];
79
+ sensitive: boolean;
80
+ attachment: ({
81
+ type: string;
82
+ mediaType: string;
83
+ url: string;
84
+ name: string;
85
+ blurhash: string;
86
+ width: number;
87
+ height: number;
88
+ } | {
89
+ type: string;
90
+ mediaType: string;
91
+ url: string;
92
+ name: null;
93
+ blurhash: string;
94
+ width: number;
95
+ height: number;
96
+ })[];
97
+ tag: {
98
+ type: string;
99
+ href: string;
100
+ name: string;
101
+ }[];
102
+ commentsEnabled: boolean;
103
+ capabilities: {
104
+ announce: string;
105
+ like: string;
106
+ reply: string;
107
+ };
108
+ location: null;
109
+ };
110
+ };
111
+ /** A like of a local article. */
112
+ export declare const PIXELFED_LIKE: {
113
+ "@context": string;
114
+ id: string;
115
+ type: string;
116
+ actor: string;
117
+ object: string;
118
+ };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Documents in the shapes Pixelfed emits: its actor with the security context listed
3
+ * first, a photo post whose attachments are typed `Image`, and a like. Ids are made up;
4
+ * the members are Pixelfed's.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ import { FAKE_PUBLIC_KEY_PEM, LOCAL_ARTICLE } from "./shared.js";
10
+ /** A Pixelfed account. */
11
+ export const PIXELFED_ACTOR = {
12
+ "@context": [
13
+ "https://w3id.org/security/v1",
14
+ "https://www.w3.org/ns/activitystreams",
15
+ {
16
+ toot: "http://joinmastodon.org/ns#",
17
+ manuallyApprovesFollowers: "as:manuallyApprovesFollowers",
18
+ alsoKnownAs: { "@id": "as:alsoKnownAs", "@type": "@id" },
19
+ movedTo: { "@id": "as:movedTo", "@type": "@id" },
20
+ indexable: "toot:indexable",
21
+ suspended: "toot:suspended",
22
+ },
23
+ ],
24
+ id: "https://pixelfed.social/users/dan",
25
+ type: "Person",
26
+ following: "https://pixelfed.social/users/dan/following",
27
+ followers: "https://pixelfed.social/users/dan/followers",
28
+ inbox: "https://pixelfed.social/users/dan/inbox",
29
+ outbox: "https://pixelfed.social/users/dan/outbox",
30
+ preferredUsername: "dan",
31
+ name: "Dan",
32
+ summary: "Film photography and long walks.",
33
+ url: "https://pixelfed.social/dan",
34
+ manuallyApprovesFollowers: false,
35
+ indexable: true,
36
+ published: "2019-06-01T00:00:00Z",
37
+ publicKey: {
38
+ id: "https://pixelfed.social/users/dan#main-key",
39
+ owner: "https://pixelfed.social/users/dan",
40
+ publicKeyPem: FAKE_PUBLIC_KEY_PEM,
41
+ },
42
+ icon: {
43
+ type: "Image",
44
+ mediaType: "image/jpeg",
45
+ url: "https://pixelfed.social/storage/avatars/000/000/000/001/avatar.jpg?v=4",
46
+ },
47
+ endpoints: { sharedInbox: "https://pixelfed.social/f/inbox" },
48
+ };
49
+ /** A photo post with two images and a hashtag. */
50
+ export const PIXELFED_CREATE_NOTE = {
51
+ "@context": [
52
+ "https://w3id.org/security/v1",
53
+ "https://www.w3.org/ns/activitystreams",
54
+ {
55
+ Hashtag: "as:Hashtag",
56
+ sensitive: "as:sensitive",
57
+ commentsEnabled: { "@id": "pixelfed:commentsEnabled", "@type": "schema:Boolean" },
58
+ capabilities: { "@id": "pixelfed:capabilities", "@container": "@set" },
59
+ pixelfed: "http://pixelfed.org/ns#",
60
+ schema: "http://schema.org/",
61
+ blurhash: "toot:blurhash",
62
+ toot: "http://joinmastodon.org/ns#",
63
+ },
64
+ ],
65
+ id: "https://pixelfed.social/p/dan/712345678901234567/activity",
66
+ type: "Create",
67
+ actor: "https://pixelfed.social/users/dan",
68
+ published: "2026-10-03T18:20:00+00:00",
69
+ to: ["https://www.w3.org/ns/activitystreams#Public"],
70
+ cc: ["https://pixelfed.social/users/dan/followers"],
71
+ object: {
72
+ id: "https://pixelfed.social/p/dan/712345678901234567",
73
+ type: "Note",
74
+ summary: null,
75
+ content: 'Golden hour <a href="https://pixelfed.social/discover/tags/filmphotography?src=hash" title="#filmphotography" class="u-url hashtag" rel="external nofollow noopener">#filmphotography</a>',
76
+ inReplyTo: null,
77
+ published: "2026-10-03T18:20:00+00:00",
78
+ url: "https://pixelfed.social/p/dan/712345678901234567",
79
+ attributedTo: "https://pixelfed.social/users/dan",
80
+ to: ["https://www.w3.org/ns/activitystreams#Public"],
81
+ cc: ["https://pixelfed.social/users/dan/followers"],
82
+ sensitive: false,
83
+ attachment: [
84
+ {
85
+ type: "Image",
86
+ mediaType: "image/jpeg",
87
+ url: "https://pixelfed.social/storage/m/_v2/000/001/a1b2c3.jpg",
88
+ name: "A beach at sunset",
89
+ blurhash: "U9Fh=@~qD%M{xuIUWBof00Rj%Mxu",
90
+ width: 1080,
91
+ height: 1350,
92
+ },
93
+ {
94
+ type: "Image",
95
+ mediaType: "image/jpeg",
96
+ url: "https://pixelfed.social/storage/m/_v2/000/001/d4e5f6.jpg",
97
+ name: null,
98
+ blurhash: "U7F~gc00_3t7M{t7t7of~qWBRjof",
99
+ width: 1080,
100
+ height: 1080,
101
+ },
102
+ ],
103
+ tag: [
104
+ {
105
+ type: "Hashtag",
106
+ href: "https://pixelfed.social/discover/tags/filmphotography",
107
+ name: "#filmphotography",
108
+ },
109
+ ],
110
+ commentsEnabled: true,
111
+ capabilities: {
112
+ announce: "https://www.w3.org/ns/activitystreams#Public",
113
+ like: "https://www.w3.org/ns/activitystreams#Public",
114
+ reply: "https://www.w3.org/ns/activitystreams#Public",
115
+ },
116
+ location: null,
117
+ },
118
+ };
119
+ /** A like of a local article. */
120
+ export const PIXELFED_LIKE = {
121
+ "@context": "https://www.w3.org/ns/activitystreams",
122
+ id: "https://pixelfed.social/users/dan#likes/9988776",
123
+ type: "Like",
124
+ actor: "https://pixelfed.social/users/dan",
125
+ object: LOCAL_ARTICLE,
126
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The local side every fixture points at (the actor being followed and the article
3
+ * being answered) and a stand-in key, so the documents of every implementation
4
+ * address the same server.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ /** The local actor that remote servers follow, mention and address. */
10
+ export declare const LOCAL_ACTOR = "https://letters.blog/activitypub/actor";
11
+ /** The local article that remote servers reply to, like, boost and quote. */
12
+ export declare const LOCAL_ARTICLE = "https://letters.blog/articles/remix-v3";
13
+ /** A PEM-armored stand-in in the shape every implementation publishes; it verifies nothing. */
14
+ export declare const FAKE_PUBLIC_KEY_PEM = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----\n";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The local side every fixture points at (the actor being followed and the article
3
+ * being answered) and a stand-in key, so the documents of every implementation
4
+ * address the same server.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ /** The local actor that remote servers follow, mention and address. */
10
+ export const LOCAL_ACTOR = "https://letters.blog/activitypub/actor";
11
+ /** The local article that remote servers reply to, like, boost and quote. */
12
+ export const LOCAL_ARTICLE = "https://letters.blog/articles/remix-v3";
13
+ /** A PEM-armored stand-in in the shape every implementation publishes; it verifies nothing. */
14
+ export const FAKE_PUBLIC_KEY_PEM = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----\n";
@@ -0,0 +1,82 @@
1
+ /** A Threads profile shared to the fediverse. */
2
+ export declare const THREADS_ACTOR: {
3
+ "@context": (string | {
4
+ manuallyApprovesFollowers: string;
5
+ sensitive: string;
6
+ toot: string;
7
+ discoverable: string;
8
+ indexable: string;
9
+ })[];
10
+ id: string;
11
+ type: string;
12
+ preferredUsername: string;
13
+ name: string;
14
+ summary: string;
15
+ url: string;
16
+ inbox: string;
17
+ outbox: string;
18
+ followers: string;
19
+ following: string;
20
+ endpoints: {
21
+ sharedInbox: string;
22
+ };
23
+ publicKey: {
24
+ id: string;
25
+ owner: string;
26
+ publicKeyPem: string;
27
+ };
28
+ icon: {
29
+ type: string;
30
+ url: string;
31
+ };
32
+ manuallyApprovesFollowers: boolean;
33
+ discoverable: boolean;
34
+ indexable: boolean;
35
+ published: string;
36
+ };
37
+ /** A reply whose `url` lists the HTML page among other links. */
38
+ export declare const THREADS_CREATE_NOTE: {
39
+ "@context": (string | {
40
+ manuallyApprovesFollowers: string;
41
+ sensitive: string;
42
+ toot: string;
43
+ discoverable: string;
44
+ indexable: string;
45
+ })[];
46
+ id: string;
47
+ type: string;
48
+ actor: string;
49
+ published: string;
50
+ to: string[];
51
+ cc: string[];
52
+ object: {
53
+ id: string;
54
+ type: string;
55
+ attributedTo: string;
56
+ content: string;
57
+ published: string;
58
+ inReplyTo: string;
59
+ to: string[];
60
+ cc: string[];
61
+ url: {
62
+ type: string;
63
+ href: string;
64
+ mediaType: string;
65
+ }[];
66
+ sensitive: boolean;
67
+ tag: {
68
+ type: string;
69
+ href: string;
70
+ name: string;
71
+ }[];
72
+ attachment: never[];
73
+ };
74
+ };
75
+ /** A like of a local article. */
76
+ export declare const THREADS_LIKE: {
77
+ "@context": string;
78
+ id: string;
79
+ type: string;
80
+ actor: string;
81
+ object: string;
82
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Documents in the shapes Threads emits: trailing-slash ids under `/ap/`, a profile URL
3
+ * on another host than the actor, and a post whose `url` is a list of Links. Ids are
4
+ * made up; the members are those Threads publishes.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ import { FAKE_PUBLIC_KEY_PEM, LOCAL_ACTOR, LOCAL_ARTICLE } from "./shared.js";
10
+ /** The `@context` Threads writes. */
11
+ const CONTEXT = [
12
+ "https://www.w3.org/ns/activitystreams",
13
+ "https://w3id.org/security/v1",
14
+ {
15
+ manuallyApprovesFollowers: "as:manuallyApprovesFollowers",
16
+ sensitive: "as:sensitive",
17
+ toot: "http://joinmastodon.org/ns#",
18
+ discoverable: "toot:discoverable",
19
+ indexable: "toot:indexable",
20
+ },
21
+ ];
22
+ /** A Threads profile shared to the fediverse. */
23
+ export const THREADS_ACTOR = {
24
+ "@context": CONTEXT,
25
+ id: "https://threads.net/ap/users/17841400000000001/",
26
+ type: "Person",
27
+ preferredUsername: "frank",
28
+ name: "Frank",
29
+ summary: "",
30
+ url: "https://www.threads.net/@frank",
31
+ inbox: "https://threads.net/ap/users/17841400000000001/inbox/",
32
+ outbox: "https://threads.net/ap/users/17841400000000001/outbox/",
33
+ followers: "https://threads.net/ap/users/17841400000000001/followers/",
34
+ following: "https://threads.net/ap/users/17841400000000001/following/",
35
+ endpoints: { sharedInbox: "https://threads.net/ap/inbox/" },
36
+ publicKey: {
37
+ id: "https://threads.net/ap/users/17841400000000001/#main-key",
38
+ owner: "https://threads.net/ap/users/17841400000000001/",
39
+ publicKeyPem: FAKE_PUBLIC_KEY_PEM,
40
+ },
41
+ icon: {
42
+ type: "Image",
43
+ url: "https://scontent.cdninstagram.com/v/t51.2885-19/000000000_n.jpg",
44
+ },
45
+ manuallyApprovesFollowers: false,
46
+ discoverable: true,
47
+ indexable: false,
48
+ published: "2024-03-21T00:00:00Z",
49
+ };
50
+ /** A reply whose `url` lists the HTML page among other links. */
51
+ export const THREADS_CREATE_NOTE = {
52
+ "@context": CONTEXT,
53
+ id: "https://threads.net/ap/users/17841400000000001/post/18000000000000001/activity/",
54
+ type: "Create",
55
+ actor: "https://threads.net/ap/users/17841400000000001/",
56
+ published: "2026-10-05T15:00:00+0000",
57
+ to: ["as:Public"],
58
+ cc: ["https://threads.net/ap/users/17841400000000001/followers/", LOCAL_ACTOR],
59
+ object: {
60
+ id: "https://threads.net/ap/users/17841400000000001/post/18000000000000001/",
61
+ type: "Note",
62
+ attributedTo: "https://threads.net/ap/users/17841400000000001/",
63
+ content: "<p>Bookmarking this for later.</p>",
64
+ published: "2026-10-05T15:00:00+0000",
65
+ inReplyTo: LOCAL_ARTICLE,
66
+ to: ["as:Public"],
67
+ cc: ["https://threads.net/ap/users/17841400000000001/followers/", LOCAL_ACTOR],
68
+ url: [
69
+ { type: "Link", href: "threads://post/C8abcdEFgh", mediaType: "application/x-threads" },
70
+ {
71
+ type: "Link",
72
+ href: "https://www.threads.net/@frank/post/C8abcdEFgh",
73
+ mediaType: "text/html",
74
+ },
75
+ ],
76
+ sensitive: false,
77
+ tag: [{ type: "Mention", href: LOCAL_ACTOR, name: "@hello@letters.blog" }],
78
+ attachment: [],
79
+ },
80
+ };
81
+ /** A like of a local article. */
82
+ export const THREADS_LIKE = {
83
+ "@context": "https://www.w3.org/ns/activitystreams",
84
+ id: "https://threads.net/ap/users/17841400000000001/likes/18000000000000002/",
85
+ type: "Like",
86
+ actor: "https://threads.net/ap/users/17841400000000001/",
87
+ object: LOCAL_ARTICLE,
88
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * ActivityPub for one local actor: the `Federation` runtime that serves its documents and
3
+ * inbox and runs every queued step, the `ActorKeys` it signs with, a `RemoteResolver` for
4
+ * remote documents, and the ActivityStreams vocabulary read and written as plain functions.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ export type { CollectionInit, CollectionItem, PageInit } from "./collections.js";
10
+ export type { ActivityPubFetchErrorCode } from "./errors.js";
11
+ export type { DeliveryErrorCode } from "./lib/delivery-post.js";
12
+ export type { InboxErrorCode } from "./lib/inbox-error.js";
13
+ export type { FollowDecision, HandleReason } from "./lib/inbox-handle.js";
14
+ export type { BlockedCheck, Verification, VerifiedFetch } from "./lib/inbox-receive.js";
15
+ export type { Summary, SummaryAuthor } from "./lib/inbox-summarize.js";
16
+ export type { ActivityPub } from "./lib/types.js";
17
+ export type { TombstoneInit } from "./lib/tombstone.js";
18
+ export type { ResolvedKey, ResolveOptions, Resolver, ResolverOptions, ResolverSigner, ResolverTtl, } from "./remote.js";
19
+ export type { Follower, FollowerStore, KeyProvider, LocalObjects, SeenActivities, StorePage, } from "./store.js";
20
+ export { collection, collectionPage, orderedCollection, orderedCollectionPage, } from "./collections.js";
21
+ export { actorLink } from "./discovery.js";
22
+ export { ActivityPubError, ActivityPubFetchError, ActivityPubParseError, FederationError, } from "./errors.js";
23
+ export { Federation } from "./federation.js";
24
+ export { ActorKeys } from "./keys.js";
25
+ export { ACTIVITY_ACCEPT, ACTIVITY_CONTENT_TYPE, ACTIVITY_JSON, ACTIVITY_TYPES, ACTOR_TYPES, AS2_CONTEXT, DATA_INTEGRITY_CONTEXT, LD_JSON, LD_JSON_ACTIVITY, MULTIKEY_CONTEXT, PUBLIC, SECURITY_CONTEXT, } from "./lib/constants.js";
26
+ export { MAX_ACTIVITY_BYTES } from "./lib/delivery-fan-out.js";
27
+ export { DELIVERY_BACKOFF, DeliveryError } from "./lib/delivery-post.js";
28
+ export { InboxError } from "./lib/inbox-error.js";
29
+ export { parseActivity, parseActor, parseCollection, parseObject } from "./lib/parse.js";
30
+ export { wantsActivity } from "./lib/response.js";
31
+ export { EXTENSION_CONTEXT, stringify } from "./lib/stringify.js";
32
+ export { tombstone } from "./lib/tombstone.js";
33
+ export { RemoteResolver } from "./remote.js";
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * ActivityPub for one local actor: the `Federation` runtime that serves its documents and
3
+ * inbox and runs every queued step, the `ActorKeys` it signs with, a `RemoteResolver` for
4
+ * remote documents, and the ActivityStreams vocabulary read and written as plain functions.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ export { collection, collectionPage, orderedCollection, orderedCollectionPage, } from "./collections.js";
10
+ export { actorLink } from "./discovery.js";
11
+ export { ActivityPubError, ActivityPubFetchError, ActivityPubParseError, FederationError, } from "./errors.js";
12
+ export { Federation } from "./federation.js";
13
+ export { ActorKeys } from "./keys.js";
14
+ export { ACTIVITY_ACCEPT, ACTIVITY_CONTENT_TYPE, ACTIVITY_JSON, ACTIVITY_TYPES, ACTOR_TYPES, AS2_CONTEXT, DATA_INTEGRITY_CONTEXT, LD_JSON, LD_JSON_ACTIVITY, MULTIKEY_CONTEXT, PUBLIC, SECURITY_CONTEXT, } from "./lib/constants.js";
15
+ export { MAX_ACTIVITY_BYTES } from "./lib/delivery-fan-out.js";
16
+ export { DELIVERY_BACKOFF, DeliveryError } from "./lib/delivery-post.js";
17
+ export { InboxError } from "./lib/inbox-error.js";
18
+ export { parseActivity, parseActor, parseCollection, parseObject } from "./lib/parse.js";
19
+ export { wantsActivity } from "./lib/response.js";
20
+ export { EXTENSION_CONTEXT, stringify } from "./lib/stringify.js";
21
+ export { tombstone } from "./lib/tombstone.js";
22
+ export { RemoteResolver } from "./remote.js";