@geekity/cms 0.24.0 → 0.26.0

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 (182) hide show
  1. package/README.md +96 -160
  2. package/admin/pages/documents/editor.njk +48 -0
  3. package/admin/pages/federation/settings.njk +1 -59
  4. package/admin/pages/plugins/installed.njk +113 -0
  5. package/admin/pages/plugins/screen.njk +129 -0
  6. package/admin/static/admin.css +144 -4
  7. package/admin/static/editor-actions.js +202 -0
  8. package/dist/admin/accounts.d.ts +18 -39
  9. package/dist/admin/accounts.d.ts.map +1 -1
  10. package/dist/admin/accounts.js +19 -48
  11. package/dist/admin/accounts.js.map +1 -1
  12. package/dist/admin/documents.d.ts +5 -0
  13. package/dist/admin/documents.d.ts.map +1 -1
  14. package/dist/admin/documents.js +17 -8
  15. package/dist/admin/documents.js.map +1 -1
  16. package/dist/admin/editor-actions.d.ts +35 -0
  17. package/dist/admin/editor-actions.d.ts.map +1 -0
  18. package/dist/admin/editor-actions.js +187 -0
  19. package/dist/admin/editor-actions.js.map +1 -0
  20. package/dist/admin/federation.d.ts +4 -5
  21. package/dist/admin/federation.d.ts.map +1 -1
  22. package/dist/admin/federation.js +4 -5
  23. package/dist/admin/federation.js.map +1 -1
  24. package/dist/admin/index.d.ts +1 -1
  25. package/dist/admin/index.d.ts.map +1 -1
  26. package/dist/admin/index.js +1 -1
  27. package/dist/admin/index.js.map +1 -1
  28. package/dist/admin/menu.d.ts +1 -1
  29. package/dist/admin/menu.d.ts.map +1 -1
  30. package/dist/admin/menu.js +10 -3
  31. package/dist/admin/menu.js.map +1 -1
  32. package/dist/admin/plugins.d.ts +24 -0
  33. package/dist/admin/plugins.d.ts.map +1 -0
  34. package/dist/admin/plugins.js +312 -0
  35. package/dist/admin/plugins.js.map +1 -0
  36. package/dist/admin/routes.d.ts.map +1 -1
  37. package/dist/admin/routes.js +5 -1
  38. package/dist/admin/routes.js.map +1 -1
  39. package/dist/admin/settings-federation.d.ts +0 -25
  40. package/dist/admin/settings-federation.d.ts.map +1 -1
  41. package/dist/admin/settings-federation.js +1 -54
  42. package/dist/admin/settings-federation.js.map +1 -1
  43. package/dist/admin/settings.d.ts +2 -14
  44. package/dist/admin/settings.d.ts.map +1 -1
  45. package/dist/admin/settings.js +1 -21
  46. package/dist/admin/settings.js.map +1 -1
  47. package/dist/admin/store.d.ts +8 -1
  48. package/dist/admin/store.d.ts.map +1 -1
  49. package/dist/admin/store.js +7 -3
  50. package/dist/admin/store.js.map +1 -1
  51. package/dist/admin/templates.d.ts +2 -0
  52. package/dist/admin/templates.d.ts.map +1 -1
  53. package/dist/admin/templates.js +2 -0
  54. package/dist/admin/templates.js.map +1 -1
  55. package/dist/cli.d.ts +2 -3
  56. package/dist/cli.d.ts.map +1 -1
  57. package/dist/cli.js +278 -212
  58. package/dist/cli.js.map +1 -1
  59. package/dist/config.d.ts +20 -0
  60. package/dist/config.d.ts.map +1 -1
  61. package/dist/config.js +6 -0
  62. package/dist/config.js.map +1 -1
  63. package/dist/content/store.d.ts +6 -0
  64. package/dist/content/store.d.ts.map +1 -1
  65. package/dist/content/store.js +3 -0
  66. package/dist/content/store.js.map +1 -1
  67. package/dist/drain.d.ts +28 -0
  68. package/dist/drain.d.ts.map +1 -0
  69. package/dist/drain.js +106 -0
  70. package/dist/drain.js.map +1 -0
  71. package/dist/env.d.ts +11 -0
  72. package/dist/env.d.ts.map +1 -1
  73. package/dist/federation/federation.d.ts +4 -2
  74. package/dist/federation/federation.d.ts.map +1 -1
  75. package/dist/federation/federation.js +16 -21
  76. package/dist/federation/federation.js.map +1 -1
  77. package/dist/federation/inbox.d.ts +23 -3
  78. package/dist/federation/inbox.d.ts.map +1 -1
  79. package/dist/federation/inbox.js +63 -1
  80. package/dist/federation/inbox.js.map +1 -1
  81. package/dist/federation/index.d.ts +0 -4
  82. package/dist/federation/index.d.ts.map +1 -1
  83. package/dist/federation/index.js +0 -2
  84. package/dist/federation/index.js.map +1 -1
  85. package/dist/federation/mount.d.ts +6 -12
  86. package/dist/federation/mount.d.ts.map +1 -1
  87. package/dist/federation/mount.js +3 -50
  88. package/dist/federation/mount.js.map +1 -1
  89. package/dist/federation/queue.d.ts +22 -0
  90. package/dist/federation/queue.d.ts.map +1 -0
  91. package/dist/federation/queue.js +58 -0
  92. package/dist/federation/queue.js.map +1 -0
  93. package/dist/files/atomic.d.ts +13 -0
  94. package/dist/files/atomic.d.ts.map +1 -1
  95. package/dist/files/atomic.js +45 -0
  96. package/dist/files/atomic.js.map +1 -1
  97. package/dist/index.d.ts +30 -3
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +156 -79
  100. package/dist/index.js.map +1 -1
  101. package/dist/plugin.d.ts +524 -0
  102. package/dist/plugin.d.ts.map +1 -0
  103. package/dist/plugin.js +23 -0
  104. package/dist/plugin.js.map +1 -0
  105. package/dist/plugins/enabled.d.ts +23 -0
  106. package/dist/plugins/enabled.d.ts.map +1 -0
  107. package/dist/plugins/enabled.js +49 -0
  108. package/dist/plugins/enabled.js.map +1 -0
  109. package/dist/plugins/federation.d.ts +26 -0
  110. package/dist/plugins/federation.d.ts.map +1 -0
  111. package/dist/plugins/federation.js +114 -0
  112. package/dist/plugins/federation.js.map +1 -0
  113. package/dist/plugins/fetch.d.ts +15 -0
  114. package/dist/plugins/fetch.d.ts.map +1 -0
  115. package/dist/plugins/fetch.js +33 -0
  116. package/dist/plugins/fetch.js.map +1 -0
  117. package/dist/plugins/folder.d.ts +50 -0
  118. package/dist/plugins/folder.d.ts.map +1 -0
  119. package/dist/plugins/folder.js +171 -0
  120. package/dist/plugins/folder.js.map +1 -0
  121. package/dist/plugins/install.d.ts +45 -0
  122. package/dist/plugins/install.d.ts.map +1 -0
  123. package/dist/plugins/install.js +275 -0
  124. package/dist/plugins/install.js.map +1 -0
  125. package/dist/plugins/mount.d.ts +17 -0
  126. package/dist/plugins/mount.d.ts.map +1 -0
  127. package/dist/plugins/mount.js +44 -0
  128. package/dist/plugins/mount.js.map +1 -0
  129. package/dist/plugins/registry.d.ts +110 -0
  130. package/dist/plugins/registry.d.ts.map +1 -0
  131. package/dist/plugins/registry.js +447 -0
  132. package/dist/plugins/registry.js.map +1 -0
  133. package/dist/plugins/settings.d.ts +64 -0
  134. package/dist/plugins/settings.d.ts.map +1 -0
  135. package/dist/plugins/settings.js +219 -0
  136. package/dist/plugins/settings.js.map +1 -0
  137. package/dist/plugins/site.d.ts +17 -0
  138. package/dist/plugins/site.d.ts.map +1 -0
  139. package/dist/plugins/site.js +67 -0
  140. package/dist/plugins/site.js.map +1 -0
  141. package/dist/supervisor/primary.d.ts +47 -0
  142. package/dist/supervisor/primary.d.ts.map +1 -0
  143. package/dist/supervisor/primary.js +208 -0
  144. package/dist/supervisor/primary.js.map +1 -0
  145. package/dist/supervisor/protocol.d.ts +37 -0
  146. package/dist/supervisor/protocol.d.ts.map +1 -0
  147. package/dist/supervisor/protocol.js +29 -0
  148. package/dist/supervisor/protocol.js.map +1 -0
  149. package/dist/supervisor/supervision.d.ts +25 -0
  150. package/dist/supervisor/supervision.d.ts.map +1 -0
  151. package/dist/supervisor/supervision.js +7 -0
  152. package/dist/supervisor/supervision.js.map +1 -0
  153. package/dist/supervisor/worker.d.ts +29 -0
  154. package/dist/supervisor/worker.d.ts.map +1 -0
  155. package/dist/supervisor/worker.js +97 -0
  156. package/dist/supervisor/worker.js.map +1 -0
  157. package/dist/web/maintenance.d.ts +2 -2
  158. package/dist/web/maintenance.js +2 -2
  159. package/dist/web/negotiate.d.ts +4 -3
  160. package/dist/web/negotiate.d.ts.map +1 -1
  161. package/dist/web/negotiate.js +4 -3
  162. package/dist/web/negotiate.js.map +1 -1
  163. package/dist/web/routes.d.ts.map +1 -1
  164. package/dist/web/routes.js +33 -14
  165. package/dist/web/routes.js.map +1 -1
  166. package/package.json +10 -1
  167. package/dist/comments/conversation.d.ts +0 -29
  168. package/dist/comments/conversation.d.ts.map +0 -1
  169. package/dist/comments/conversation.js +0 -60
  170. package/dist/comments/conversation.js.map +0 -1
  171. package/dist/federation/import-wordpress.d.ts +0 -128
  172. package/dist/federation/import-wordpress.d.ts.map +0 -1
  173. package/dist/federation/import-wordpress.js +0 -426
  174. package/dist/federation/import-wordpress.js.map +0 -1
  175. package/dist/federation/wordpress.d.ts +0 -131
  176. package/dist/federation/wordpress.d.ts.map +0 -1
  177. package/dist/federation/wordpress.js +0 -342
  178. package/dist/federation/wordpress.js.map +0 -1
  179. package/dist/web/comments.d.ts +0 -60
  180. package/dist/web/comments.d.ts.map +0 -1
  181. package/dist/web/comments.js +0 -207
  182. package/dist/web/comments.js.map +0 -1
@@ -1,342 +0,0 @@
1
- import path from 'node:path';
2
- import { createFederation, InProcessMessageQueue, MemoryKvStore } from '@fedify/fedify';
3
- import { Accept, Announce, Create, Delete, Follow, Like, QuoteRequest, Reject, Undo, } from '@fedify/vocab';
4
- import { listUsers } from '../admin/accounts.js';
5
- import { readFileIfPresentSync, updateFileAtomically } from '../files/atomic.js';
6
- import { authorNames } from '../web/authors.js';
7
- import { userActor } from './actor.js';
8
- import { federationOrigin } from './paths.js';
9
- import { outboxPage, OUTBOX_PAGE_SIZE } from './federation.js';
10
- import { followersPage, lastFollowersCursor } from './followers.js';
11
- import { handleAccept, handleDelete, handleFollow, handleLoggedActivity, handleQuoteRequest, handleReject, handleUndo, } from './inbox.js';
12
- import { loadActorKeyPairs } from './keys.js';
13
- /**
14
- * The WordPress ActivityPub plugin's paths, served behind a switch (TASK-70).
15
- *
16
- * A follower's server delivers to the inbox URL it cached from the actor
17
- * document, and replaces it only when it next refetches the actor. A site that
18
- * moved here from the plugin therefore goes on being delivered to at
19
- * `/wp-json/activitypub/1.0/actors/2/inbox` and `/wp-json/activitypub/1.0/inbox`
20
- * for as long as those caches last, and decision-14 calls that **cache rather
21
- * than identity**: the CMS carries the plugin's layout until the caches have
22
- * moved on, and no longer.
23
- *
24
- * So everything here is behind the `wordpressActivityPub` site setting, and
25
- * everything a peer reads back is the canonical identity. The actor served at
26
- * `…/actors/2` is the same `Person` the author URL serves — same `id`, same
27
- * canonical `inbox` — so a peer that refetches here learns the new endpoints
28
- * rather than being handed the old ones again. That is what eventually makes
29
- * the switch safe to turn off.
30
- *
31
- * A second `Federation` is how Fedify serves a second inbox path at all: one
32
- * object may have exactly one pair of inbox listeners, and `ctx.routeActivity`
33
- * re-verifies from scratch in a way a Mastodon or WordPress `Follow` cannot
34
- * satisfy (doc-8). The second object shares the canonical one's KV store, and
35
- * both sets of listeners are set to `per-origin` idempotence, because the
36
- * default folds the recipient identifier into the key — so the same `Follow`
37
- * redelivered to `andrew` and to `2` would otherwise be handled twice.
38
- */
39
- /** Where the plugin's REST namespace lives, on the site's origin. */
40
- export const WORDPRESS_ACTIVITYPUB_BASE = '/wp-json/activitypub/1.0';
41
- /** The plugin's actor path. Its identifier is the WordPress user's number. */
42
- export const WORDPRESS_ACTOR_PATH = `${WORDPRESS_ACTIVITYPUB_BASE}/actors/{identifier}`;
43
- /** The actor's inbox, outbox and two follow collections, as the plugin spells them. */
44
- export const WORDPRESS_INBOX_PATH = `${WORDPRESS_ACTOR_PATH}/inbox`;
45
- export const WORDPRESS_OUTBOX_PATH = `${WORDPRESS_ACTOR_PATH}/outbox`;
46
- export const WORDPRESS_FOLLOWERS_PATH = `${WORDPRESS_ACTOR_PATH}/followers`;
47
- export const WORDPRESS_FOLLOWING_PATH = `${WORDPRESS_ACTOR_PATH}/following`;
48
- /** The plugin's instance-wide inbox, which its `sharedInbox` endpoint names. */
49
- export const WORDPRESS_SHARED_INBOX_PATH = `${WORDPRESS_ACTIVITYPUB_BASE}/inbox`;
50
- /**
51
- * Build the compatibility federation: the plugin's inbox and collections,
52
- * mapped to users by the number WordPress gave them.
53
- *
54
- * Nothing else is registered. WebFinger, NodeInfo and the actor's real
55
- * endpoints belong to the canonical federation and stay there; this object
56
- * exists only so that deliveries and fetches aimed at the old layout land
57
- * somewhere, signature-verified at the real request path exactly as the
58
- * canonical inbox verifies them.
59
- */
60
- export function createWordPressFederation(options) {
61
- const { canonical } = options;
62
- const federation = createFederation({
63
- kv: options.kv ?? new MemoryKvStore(),
64
- origin: federationOrigin(options.baseUrl),
65
- ...(options.queue === null ? {} : { queue: options.queue ?? new InProcessMessageQueue() }),
66
- ...(options.allowPrivateAddress === undefined
67
- ? {}
68
- : { allowPrivateAddress: options.allowPrivateAddress }),
69
- ...options.federationOptions,
70
- });
71
- /** The user a dispatcher's identifier names, which here is a number. */
72
- function actorFor(context, identifier) {
73
- return userByWordPressActorId(context.data.config.dataDir, identifier);
74
- }
75
- /**
76
- * A context of the canonical federation over the same data.
77
- *
78
- * Every id a peer reads or verifies comes from here rather than from the
79
- * compatibility context, so the actor, the key ids, the `Accept` and the
80
- * collections a peer is pointed at are the ones the site really publishes.
81
- */
82
- function identity(context) {
83
- return canonical.createContext(new URL(context.origin), context.data);
84
- }
85
- /** Every stored `author` string that reads as this user (TASK-67). */
86
- function namesOf(context, user) {
87
- return authorNames(listUsers(context.data.config.dataDir), user);
88
- }
89
- federation
90
- .setActorDispatcher(WORDPRESS_ACTOR_PATH, async (context, identifier) => {
91
- const user = actorFor(context, identifier);
92
- if (user === undefined)
93
- return null;
94
- // The canonical document, verbatim: a peer refetching the actor at the
95
- // old URL is exactly the peer that should learn the new inbox.
96
- return await userActor(identity(context), user, { baseUrl: context.data.config.baseUrl });
97
- })
98
- .setKeyPairsDispatcher(async (context, identifier) => {
99
- const user = actorFor(context, identifier);
100
- return user === undefined
101
- ? []
102
- : await loadActorKeyPairs(context.data.config.dataDir, user.username);
103
- });
104
- federation
105
- .setOutboxDispatcher(WORDPRESS_OUTBOX_PATH, (context, identifier, cursor) => {
106
- const user = actorFor(context, identifier);
107
- return user === undefined
108
- ? null
109
- : outboxPage(identity(context), namesOf(context, user), cursor);
110
- })
111
- .setCounter((context, identifier) => {
112
- const user = actorFor(context, identifier);
113
- return user === undefined ? null : context.data.store.countByAuthor(namesOf(context, user));
114
- })
115
- .setFirstCursor((context, identifier) => actorFor(context, identifier) === undefined ? null : '0')
116
- .setLastCursor((context, identifier) => {
117
- const user = actorFor(context, identifier);
118
- if (user === undefined)
119
- return null;
120
- const total = context.data.store.countByAuthor(namesOf(context, user));
121
- return String(total === 0 ? 0 : Math.floor((total - 1) / OUTBOX_PAGE_SIZE) * OUTBOX_PAGE_SIZE);
122
- });
123
- federation
124
- .setFollowersDispatcher(WORDPRESS_FOLLOWERS_PATH, (context, identifier, cursor) => {
125
- const user = actorFor(context, identifier);
126
- return user === undefined ? null : followersPage(context, user.username, cursor);
127
- })
128
- .setCounter((context, identifier) => {
129
- const user = actorFor(context, identifier);
130
- return user === undefined ? null : context.data.admin.countFollowers(user.username);
131
- })
132
- .setFirstCursor((context, identifier) => actorFor(context, identifier) === undefined ? null : '0')
133
- .setLastCursor((context, identifier) => {
134
- const user = actorFor(context, identifier);
135
- return user === undefined
136
- ? null
137
- : lastFollowersCursor(context.data.admin.countFollowers(user.username));
138
- });
139
- federation.setFollowingDispatcher(WORDPRESS_FOLLOWING_PATH, (context, identifier) => actorFor(context, identifier) === undefined ? null : { items: [] });
140
- // The same handlers the canonical inbox runs, over a canonical context.
141
- // `per-origin` idempotence is what keeps one `Follow` redelivered to both
142
- // inboxes from being handled twice (doc-8); the canonical federation is set
143
- // the same way, and they share a KV store so the two agree about what they
144
- // have already seen.
145
- federation
146
- .setInboxListeners(WORDPRESS_INBOX_PATH, WORDPRESS_SHARED_INBOX_PATH)
147
- .withIdempotency('per-origin')
148
- .on(Follow, canonically(handleFollow))
149
- .on(Accept, canonically(handleAccept))
150
- .on(Reject, canonically(handleReject))
151
- .on(Undo, canonically(handleUndo))
152
- .on(Delete, canonically(handleDelete))
153
- .on(Like, canonically(handleLoggedActivity))
154
- .on(Announce, canonically(handleLoggedActivity))
155
- .on(Create, canonically(handleLoggedActivity))
156
- .on(QuoteRequest, canonically(handleQuoteRequest));
157
- /**
158
- * One inbox handler, run against the canonical federation.
159
- *
160
- * Two things are swapped. The context is the canonical one, so `parseUri`
161
- * recognises the site's own actor URLs, the `Accept` is signed with the key
162
- * the actor document publishes and sent from the id its followers hold. And
163
- * `recipient` — which arrives here as the WordPress number, straight off the
164
- * path — is the username, because that is what every handler and the inbox
165
- * log mean by a recipient.
166
- */
167
- function canonically(handle) {
168
- return async (context, activity) => {
169
- const user = context.recipient === null ? undefined : actorFor(context, context.recipient);
170
- await handle(withRecipient(identity(context), context, user?.username ?? null), activity);
171
- };
172
- }
173
- return federation;
174
- }
175
- /**
176
- * A canonical context wearing one inbox delivery's recipient.
177
- *
178
- * A `Proxy` rather than a copy: Fedify's context is a class with private state,
179
- * so its methods have to keep running against the object they were made for.
180
- * Everything but `recipient` and `forwardActivity` is the canonical context's
181
- * own.
182
- */
183
- function withRecipient(canonical, delivered, recipient) {
184
- return new Proxy(canonical, {
185
- get(target, property) {
186
- if (property === 'recipient')
187
- return recipient;
188
- // Forwarding is the one thing only the delivering context can do: it
189
- // holds the bytes that arrived, signatures and all.
190
- if (property === 'forwardActivity')
191
- return delivered.forwardActivity.bind(delivered);
192
- const value = Reflect.get(target, property, target);
193
- return typeof value === 'function'
194
- ? value.bind(target)
195
- : value;
196
- },
197
- });
198
- }
199
- /**
200
- * The user the WordPress ActivityPub plugin numbered `identifier`, or
201
- * `undefined`.
202
- *
203
- * The identifier is a path segment, so it is compared as the decimal the
204
- * plugin writes: `02` and `2.0` name nobody, because neither is a URL the
205
- * plugin ever published.
206
- */
207
- export function userByWordPressActorId(dataDir, identifier) {
208
- if (!/^[1-9][0-9]*$/.test(identifier))
209
- return undefined;
210
- const wanted = Number(identifier);
211
- return listUsers(dataDir).find((user) => user.wordpressActorId === wanted);
212
- }
213
- /**
214
- * The compatibility path a request asks for, or `undefined` for anything else.
215
- *
216
- * Matched here rather than left to Fedify because the record of what was last
217
- * asked for has to be written whether or not a user answers: a delivery to a
218
- * number nobody carries is still a peer holding the old URL, and it is exactly
219
- * the sort of thing the owner watching the screen wants to see. Fedify's
220
- * router still decides what is actually served.
221
- */
222
- export function wordPressRequestTarget(pathname) {
223
- if (pathname === WORDPRESS_SHARED_INBOX_PATH)
224
- return { route: 'sharedInbox' };
225
- const under = `${WORDPRESS_ACTIVITYPUB_BASE}/actors/`;
226
- if (!pathname.startsWith(under))
227
- return undefined;
228
- const [number, name, ...rest] = pathname.slice(under.length).split('/');
229
- if (number === undefined || number === '' || rest.length > 0)
230
- return undefined;
231
- if (name === undefined || name === '')
232
- return { route: 'actor', wordpressActorId: number };
233
- if (name === 'inbox' || name === 'outbox' || name === 'followers' || name === 'following') {
234
- return { route: name, wordpressActorId: number };
235
- }
236
- return undefined;
237
- }
238
- /** The file the instants live in, relative to `dataDir`. */
239
- export const WORDPRESS_REQUESTS_FILE = 'wordpress-activitypub.json';
240
- /** Where that file lives for a given data directory. */
241
- export function wordPressRequestsFile(dataDir) {
242
- return path.join(dataDir, WORDPRESS_REQUESTS_FILE);
243
- }
244
- /** The file as it reads now; a site nobody has asked has nothing to say. */
245
- export function readWordPressRequests(dataDir) {
246
- const source = readFileIfPresentSync(wordPressRequestsFile(dataDir));
247
- if (source === undefined)
248
- return { users: {} };
249
- let parsed;
250
- try {
251
- parsed = JSON.parse(source);
252
- }
253
- catch {
254
- // A record of who asked for what is not worth failing a request over, and
255
- // "never" is the honest answer when the file cannot be read.
256
- return { users: {} };
257
- }
258
- return requestsFrom(parsed);
259
- }
260
- /**
261
- * Record that one compatibility path was just asked for.
262
- *
263
- * Written through {@link updateFileAtomically}, so two deliveries arriving
264
- * together cannot lose one another's instant and a reader never sees a
265
- * half-written file. A path whose number names nobody is not recorded: the
266
- * record is per user, and there is no user to record it against.
267
- */
268
- export async function recordWordPressRequest(options) {
269
- const { target, username } = options;
270
- if (target.route !== 'sharedInbox' && username === undefined)
271
- return;
272
- const instant = options.at.toISOString();
273
- const file = wordPressRequestsFile(options.dataDir);
274
- await updateFileAtomically(file, (current) => {
275
- const requests = requestsFrom(parseOrEmpty(current));
276
- const next = target.route === 'sharedInbox'
277
- ? { ...requests, sharedInbox: instant }
278
- : {
279
- ...requests,
280
- users: {
281
- ...requests.users,
282
- [username ?? '']: {
283
- ...requests.users[username ?? ''],
284
- [target.route]: instant,
285
- },
286
- },
287
- };
288
- return `${JSON.stringify(next, null, 2)}\n`;
289
- });
290
- }
291
- /** The bytes of the file as whatever JSON they hold, or nothing usable. */
292
- function parseOrEmpty(source) {
293
- if (source === undefined)
294
- return undefined;
295
- try {
296
- return JSON.parse(source);
297
- }
298
- catch {
299
- return undefined;
300
- }
301
- }
302
- /**
303
- * Whatever the file held as the instants this version understands.
304
- *
305
- * Read key by key and dropped rather than refused, on the rule the users file
306
- * and `site.json` are read by: this is a record of what happened, and a
307
- * damaged one should cost the screen a column, not the site a boot.
308
- */
309
- function requestsFrom(value) {
310
- if (typeof value !== 'object' || value === null || Array.isArray(value))
311
- return { users: {} };
312
- const record = value;
313
- const users = {};
314
- const listed = record['users'];
315
- if (typeof listed === 'object' && listed !== null && !Array.isArray(listed)) {
316
- for (const [username, routes] of Object.entries(listed)) {
317
- if (typeof routes !== 'object' || routes === null || Array.isArray(routes))
318
- continue;
319
- const kept = {};
320
- for (const [name, instant] of Object.entries(routes)) {
321
- if (typeof instant === 'string' && isWordPressRoute(name))
322
- kept[name] = instant;
323
- }
324
- if (Object.keys(kept).length > 0)
325
- users[username] = kept;
326
- }
327
- }
328
- const shared = record['sharedInbox'];
329
- return {
330
- ...(typeof shared === 'string' ? { sharedInbox: shared } : {}),
331
- users,
332
- };
333
- }
334
- /** Whether a stored key names a path this version serves. */
335
- function isWordPressRoute(name) {
336
- return (name === 'actor' ||
337
- name === 'inbox' ||
338
- name === 'outbox' ||
339
- name === 'followers' ||
340
- name === 'following');
341
- }
342
- //# sourceMappingURL=wordpress.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wordpress.js","sourceRoot":"","sources":["../../src/federation/wordpress.ts"],"names":[],"mappings":"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"}
@@ -1,60 +0,0 @@
1
- import type { AdminStore } from '../admin/store.ts';
2
- import type { Document } from '../content/document.ts';
3
- import type { ContentStore } from '../content/store.ts';
4
- import type { FeedComment } from './feeds.ts';
5
- /**
6
- * The comments a site has, in the two shapes it has them: replies its inbox
7
- * was sent, and comments people left on the page itself.
8
- *
9
- * A fediverse reply names the post it answers by the post's ActivityStreams
10
- * object id, and lives in the inbox log; a native comment names the post by
11
- * its slug and lives in `content/_data/comments/` (TASK-50). This module is
12
- * where the two meet for the feeds: a reader subscribed to a post's comments
13
- * should hear about an answer whichever door it came in by, and
14
- * `source:comments` should count what a reader would actually see.
15
- *
16
- * Only approved native comments are here. One waiting for a moderator and one
17
- * filed as spam are both stored and neither is anything to publish.
18
- */
19
- /** One comment, with the post it answers. */
20
- export interface Comment extends FeedComment {
21
- /** The post it answers, which the site-wide feed names on every item. */
22
- post: Document;
23
- }
24
- /** What the comment queries need to reach: both indexes and the site's origin. */
25
- export interface CommentContext {
26
- /** Where the replies are logged. */
27
- admin: AdminStore;
28
- /** Where the posts are. */
29
- store: ContentStore;
30
- /** The site's public origin, for the object ids. */
31
- baseUrl: string;
32
- }
33
- /**
34
- * One post's comments, newest first, from both sources.
35
- *
36
- * A post that has never been delivered has no object id and so can have no
37
- * fediverse replies — nothing out there has a name for it yet — but it can
38
- * still have native ones, which are found by its slug.
39
- */
40
- export declare function postComments(context: CommentContext, document: Document, limit: number): FeedComment[];
41
- /**
42
- * Every post's comments, newest first, each with the post it answers.
43
- *
44
- * One about a post that has since been unpublished or trashed is left out,
45
- * because the post it is about is not there to read: the feed would be showing
46
- * a conversation about nothing. That filtering happens after the database has
47
- * paged, so the pages are read until enough survive.
48
- */
49
- export declare function siteComments(context: CommentContext, limit: number): Comment[];
50
- /**
51
- * How many comments each of these documents has, by permalink: the fediverse
52
- * replies and the approved native ones together, which is what a reader
53
- * following `source:comments` would actually find on the page.
54
- *
55
- * Resolved rather than counted on demand, because the number goes into the
56
- * feed's own validator: a feed whose comment counts moved is a changed feed,
57
- * and a reader holding the old one should be told so.
58
- */
59
- export declare function commentCounts(context: CommentContext, documents: readonly Document[]): Map<string, number>;
60
- //# sourceMappingURL=comments.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/web/comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C;;;;;;;;;;;;;GAaG;AAEH,6CAA6C;AAC7C,MAAM,WAAW,OAAQ,SAAQ,WAAW;IAC1C,yEAAyE;IACzE,IAAI,EAAE,QAAQ,CAAC;CAChB;AAYD,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,KAAK,EAAE,UAAU,CAAC;IAClB,2BAA2B;IAC3B,KAAK,EAAE,YAAY,CAAC;IACpB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,GACZ,WAAW,EAAE,CAYf;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAkC9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,SAAS,QAAQ,EAAE,GAC7B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAWrB"}
@@ -1,207 +0,0 @@
1
- import { commentAnchor } from '../comments/conversation.js';
2
- import { FEDERATION_PREFIX } from '../federation/paths.js';
3
- import { replyFrom } from '../federation/replies.js';
4
- import { activityStreamsId, isPublicDocument } from './documents.js';
5
- import { absoluteUrl } from './negotiate.js';
6
- /**
7
- * How many candidates a site-wide page reads for each one it keeps.
8
- *
9
- * Replies to a post that has since been unpublished are dropped after the
10
- * database has already counted them, so the query has to over-read. Four is
11
- * generous for a site whose posts mostly stay published and bounded for one
12
- * whose posts do not.
13
- */
14
- const OVERSCAN = 4;
15
- /**
16
- * One post's comments, newest first, from both sources.
17
- *
18
- * A post that has never been delivered has no object id and so can have no
19
- * fediverse replies — nothing out there has a name for it yet — but it can
20
- * still have native ones, which are found by its slug.
21
- */
22
- export function postComments(context, document, limit) {
23
- const objectId = activityStreamsId(document, context.baseUrl);
24
- const naming = authorNaming(context.admin);
25
- const federated = objectId === undefined
26
- ? []
27
- : context.admin
28
- .listRepliesTo(objectId, { limit })
29
- .map((activity) => replyFrom(activity, naming))
30
- .filter((reply) => reply !== undefined);
31
- return newestFirst([...federated, ...nativeComments(context, document)], limit);
32
- }
33
- /**
34
- * Every post's comments, newest first, each with the post it answers.
35
- *
36
- * One about a post that has since been unpublished or trashed is left out,
37
- * because the post it is about is not there to read: the feed would be showing
38
- * a conversation about nothing. That filtering happens after the database has
39
- * paged, so the pages are read until enough survive.
40
- */
41
- export function siteComments(context, limit) {
42
- const naming = authorNaming(context.admin);
43
- const posts = new PostsByObjectId(context);
44
- const comments = [];
45
- for (let offset = 0; comments.length < limit;) {
46
- const page = context.admin.listReplies({ limit: limit * OVERSCAN, offset });
47
- if (page.length === 0)
48
- break;
49
- offset += page.length;
50
- for (const activity of page) {
51
- const reply = replyFrom(activity, naming);
52
- if (reply === undefined)
53
- continue;
54
- const post = posts.get(reply.inReplyTo);
55
- if (post === undefined)
56
- continue;
57
- comments.push({ ...reply, post });
58
- if (comments.length === limit)
59
- break;
60
- }
61
- }
62
- // The native comments are over-read for the same reason the replies are: one
63
- // on a post that has since been unpublished is dropped after the index has
64
- // already counted it.
65
- for (const stored of context.admin.listComments({
66
- status: 'approved',
67
- limit: limit * OVERSCAN,
68
- })) {
69
- const post = context.store.getBySlug(stored.slug);
70
- if (post === undefined || !isPublicDocument(post, context.store.now()))
71
- continue;
72
- comments.push({ ...feedCommentOf(stored, post, context.baseUrl), post });
73
- }
74
- return newestFirst(comments, limit);
75
- }
76
- /**
77
- * How many comments each of these documents has, by permalink: the fediverse
78
- * replies and the approved native ones together, which is what a reader
79
- * following `source:comments` would actually find on the page.
80
- *
81
- * Resolved rather than counted on demand, because the number goes into the
82
- * feed's own validator: a feed whose comment counts moved is a changed feed,
83
- * and a reader holding the old one should be told so.
84
- */
85
- export function commentCounts(context, documents) {
86
- const counts = new Map();
87
- for (const document of documents) {
88
- const objectId = activityStreamsId(document, context.baseUrl);
89
- const federated = objectId === undefined ? 0 : context.admin.countRepliesTo(objectId);
90
- counts.set(document.permalink, federated + context.admin.countCommentsFor(document.slug, 'approved'));
91
- }
92
- return counts;
93
- }
94
- /** One post's approved native comments, in the shape a feed item wants. */
95
- function nativeComments(context, document) {
96
- return context.admin
97
- .listCommentsFor(document.slug)
98
- .filter((comment) => comment.status === 'approved')
99
- .map((comment) => feedCommentOf(comment, document, context.baseUrl));
100
- }
101
- /**
102
- * One stored comment as a feed item.
103
- *
104
- * Its `url` is where a reader can actually read it — this page, at the
105
- * comment's own anchor — and its `id` is the comment's own name, which is what
106
- * a `guid isPermaLink="false"` is for: a reader that has seen it once does not
107
- * see it again if the post moves.
108
- */
109
- function feedCommentOf(comment, post, baseUrl) {
110
- return {
111
- id: comment.id,
112
- url: `${absoluteUrl(post.permalink, baseUrl)}#${commentAnchor(comment.id)}`,
113
- author: comment.author.name,
114
- published: new Date(comment.submitted),
115
- html: comment.content.html,
116
- };
117
- }
118
- /** The newest `limit` of a mixed list, which is the order every feed shows. */
119
- function newestFirst(comments, limit) {
120
- return comments
121
- .sort((left, right) => right.published.getTime() - left.published.getTime())
122
- .slice(0, limit);
123
- }
124
- /** The name to show for an actor: the follower profile the site holds, if any. */
125
- function authorNaming(admin) {
126
- const known = new Map();
127
- return (actorId) => {
128
- if (!known.has(actorId)) {
129
- const follower = admin.getFollower(actorId);
130
- known.set(actorId, follower?.name ?? follower?.handle ?? undefined);
131
- }
132
- return known.get(actorId);
133
- };
134
- }
135
- /**
136
- * The public post an ActivityStreams object id names, memoised.
137
- *
138
- * Almost every id is the one the slug implies, so the slug is tried first and
139
- * the answer is checked against the document's own id — a post that has been
140
- * renamed keeps the id it was first delivered under, which no slug spells any
141
- * more. Only when that fails is the whole index read, once, to find it.
142
- */
143
- class PostsByObjectId {
144
- #context;
145
- #found = new Map();
146
- #all;
147
- constructor(context) {
148
- this.#context = context;
149
- }
150
- get(objectId) {
151
- if (!this.#found.has(objectId))
152
- this.#found.set(objectId, this.#resolve(objectId));
153
- return this.#found.get(objectId);
154
- }
155
- #resolve(objectId) {
156
- const slug = slugOfObjectId(objectId, this.#context.baseUrl);
157
- if (slug !== undefined) {
158
- const document = this.#context.store.getBySlug(slug);
159
- if (document !== undefined &&
160
- activityStreamsId(document, this.#context.baseUrl) === objectId) {
161
- return document;
162
- }
163
- }
164
- return this.#everything().get(objectId);
165
- }
166
- #everything() {
167
- if (this.#all === undefined) {
168
- this.#all = new Map();
169
- for (const document of this.#context.store.listPosts()) {
170
- const id = activityStreamsId(document, this.#context.baseUrl);
171
- if (id !== undefined)
172
- this.#all.set(id, document);
173
- }
174
- }
175
- return this.#all;
176
- }
177
- }
178
- /**
179
- * The slug an object id names, when it is one this site would have minted.
180
- *
181
- * An id from another host, or one under some other path, belongs to no post
182
- * here however it is spelled.
183
- */
184
- function slugOfObjectId(objectId, baseUrl) {
185
- let url;
186
- try {
187
- url = new URL(objectId);
188
- }
189
- catch {
190
- return undefined;
191
- }
192
- if (url.origin !== new URL(baseUrl).origin)
193
- return undefined;
194
- const prefix = `${FEDERATION_PREFIX}/posts/`;
195
- if (!url.pathname.startsWith(prefix))
196
- return undefined;
197
- const slug = url.pathname.slice(prefix.length);
198
- if (slug === '' || slug.includes('/'))
199
- return undefined;
200
- try {
201
- return decodeURIComponent(slug);
202
- }
203
- catch {
204
- return undefined;
205
- }
206
- }
207
- //# sourceMappingURL=comments.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/web/comments.ts"],"names":[],"mappings":"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"}