@fedify/cli 2.0.0-pr.479.1922 → 2.0.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 (160) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -3
  3. package/dist/cache.js +17 -3
  4. package/dist/config.js +105 -0
  5. package/dist/deno.js +18 -8
  6. package/dist/generate-vocab/action.js +1 -1
  7. package/dist/imagerenderer.js +1 -1
  8. package/dist/inbox/rendercode.js +11 -21
  9. package/dist/inbox.js +162 -132
  10. package/dist/init/mod.js +3 -3
  11. package/dist/log.js +35 -1
  12. package/dist/lookup.js +55 -23
  13. package/dist/mod.js +95 -18
  14. package/dist/nodeinfo.js +39 -22
  15. package/dist/options.js +84 -0
  16. package/dist/relay.js +136 -0
  17. package/dist/tempserver.js +15 -8
  18. package/dist/tunnel.js +6 -10
  19. package/dist/utils.js +19 -108
  20. package/dist/webfinger/action.js +1 -1
  21. package/dist/webfinger/command.js +17 -9
  22. package/dist/webfinger/lib.js +3 -3
  23. package/package.json +50 -28
  24. package/deno.json +0 -71
  25. package/dist/globals.js +0 -49
  26. package/dist/init/action/configs.js +0 -91
  27. package/dist/init/action/const.js +0 -10
  28. package/dist/init/action/deps.js +0 -50
  29. package/dist/init/action/dir.js +0 -16
  30. package/dist/init/action/env.js +0 -13
  31. package/dist/init/action/install.js +0 -20
  32. package/dist/init/action/mod.js +0 -39
  33. package/dist/init/action/notice.js +0 -55
  34. package/dist/init/action/patch.js +0 -147
  35. package/dist/init/action/precommand.js +0 -28
  36. package/dist/init/action/recommend.js +0 -24
  37. package/dist/init/action/set.js +0 -31
  38. package/dist/init/action/templates.js +0 -58
  39. package/dist/init/action/utils.js +0 -50
  40. package/dist/init/ask/dir.js +0 -82
  41. package/dist/init/ask/kv.js +0 -44
  42. package/dist/init/ask/mod.js +0 -16
  43. package/dist/init/ask/mq.js +0 -46
  44. package/dist/init/ask/pm.js +0 -49
  45. package/dist/init/ask/wf.js +0 -29
  46. package/dist/init/command.js +0 -50
  47. package/dist/init/const.js +0 -31
  48. package/dist/init/json/biome.js +0 -24
  49. package/dist/init/json/kv.js +0 -53
  50. package/dist/init/json/mq.js +0 -72
  51. package/dist/init/json/pm.js +0 -44
  52. package/dist/init/json/rt.js +0 -39
  53. package/dist/init/json/vscode-settings-for-deno.js +0 -53
  54. package/dist/init/json/vscode-settings.js +0 -49
  55. package/dist/init/lib.js +0 -136
  56. package/dist/init/templates/defaults/federation.ts.tpl +0 -23
  57. package/dist/init/templates/defaults/logging.ts.tpl +0 -23
  58. package/dist/init/templates/express/app.ts.tpl +0 -16
  59. package/dist/init/templates/express/index.ts.tpl +0 -6
  60. package/dist/init/templates/hono/app.tsx.tpl +0 -14
  61. package/dist/init/templates/hono/index/bun.ts.tpl +0 -10
  62. package/dist/init/templates/hono/index/deno.ts.tpl +0 -13
  63. package/dist/init/templates/hono/index/node.ts.tpl +0 -14
  64. package/dist/init/templates/next/middleware.ts.tpl +0 -45
  65. package/dist/init/templates/nitro/.env.test.tpl +0 -1
  66. package/dist/init/templates/nitro/nitro.config.ts.tpl +0 -14
  67. package/dist/init/templates/nitro/server/error.ts.tpl +0 -3
  68. package/dist/init/templates/nitro/server/middleware/federation.ts.tpl +0 -8
  69. package/dist/init/test/action.js +0 -17
  70. package/dist/init/test/create.js +0 -100
  71. package/dist/init/test/fill.js +0 -32
  72. package/dist/init/test/lookup.js +0 -190
  73. package/dist/init/test/run.js +0 -25
  74. package/dist/init/test/utils.js +0 -17
  75. package/dist/init/webframeworks.js +0 -136
  76. package/scripts/pack.ts +0 -71
  77. package/src/cache.ts +0 -17
  78. package/src/docloader.ts +0 -67
  79. package/src/generate-vocab/action.ts +0 -17
  80. package/src/generate-vocab/command.ts +0 -44
  81. package/src/generate-vocab/mod.ts +0 -2
  82. package/src/globals.ts +0 -43
  83. package/src/imagerenderer.ts +0 -149
  84. package/src/inbox/entry.ts +0 -10
  85. package/src/inbox/rendercode.ts +0 -68
  86. package/src/inbox/view.tsx +0 -598
  87. package/src/inbox.tsx +0 -536
  88. package/src/init/action/configs.ts +0 -133
  89. package/src/init/action/const.ts +0 -9
  90. package/src/init/action/deps.ts +0 -161
  91. package/src/init/action/dir.ts +0 -11
  92. package/src/init/action/env.ts +0 -14
  93. package/src/init/action/install.ts +0 -24
  94. package/src/init/action/mod.ts +0 -66
  95. package/src/init/action/notice.ts +0 -103
  96. package/src/init/action/patch.ts +0 -233
  97. package/src/init/action/precommand.ts +0 -29
  98. package/src/init/action/recommend.ts +0 -38
  99. package/src/init/action/set.ts +0 -65
  100. package/src/init/action/templates.ts +0 -96
  101. package/src/init/action/utils.ts +0 -64
  102. package/src/init/ask/dir.ts +0 -98
  103. package/src/init/ask/kv.ts +0 -82
  104. package/src/init/ask/mod.ts +0 -23
  105. package/src/init/ask/mq.ts +0 -86
  106. package/src/init/ask/pm.ts +0 -58
  107. package/src/init/ask/wf.ts +0 -27
  108. package/src/init/command.ts +0 -135
  109. package/src/init/const.ts +0 -4
  110. package/src/init/json/biome.json +0 -17
  111. package/src/init/json/kv.json +0 -39
  112. package/src/init/json/mq.json +0 -95
  113. package/src/init/json/pm.json +0 -47
  114. package/src/init/json/rt.json +0 -42
  115. package/src/init/json/vscode-settings-for-deno.json +0 -43
  116. package/src/init/json/vscode-settings.json +0 -41
  117. package/src/init/lib.ts +0 -223
  118. package/src/init/mod.ts +0 -3
  119. package/src/init/templates/defaults/federation.ts.tpl +0 -23
  120. package/src/init/templates/defaults/logging.ts.tpl +0 -23
  121. package/src/init/templates/express/app.ts.tpl +0 -16
  122. package/src/init/templates/express/index.ts.tpl +0 -6
  123. package/src/init/templates/hono/app.tsx.tpl +0 -14
  124. package/src/init/templates/hono/index/bun.ts.tpl +0 -10
  125. package/src/init/templates/hono/index/deno.ts.tpl +0 -13
  126. package/src/init/templates/hono/index/node.ts.tpl +0 -14
  127. package/src/init/templates/next/middleware.ts.tpl +0 -45
  128. package/src/init/templates/nitro/.env.test.tpl +0 -1
  129. package/src/init/templates/nitro/nitro.config.ts.tpl +0 -14
  130. package/src/init/templates/nitro/server/error.ts.tpl +0 -3
  131. package/src/init/templates/nitro/server/middleware/federation.ts.tpl +0 -8
  132. package/src/init/test/action.ts +0 -28
  133. package/src/init/test/create.ts +0 -137
  134. package/src/init/test/fill.ts +0 -67
  135. package/src/init/test/lookup.ts +0 -254
  136. package/src/init/test/run.ts +0 -39
  137. package/src/init/test/types.ts +0 -27
  138. package/src/init/test/utils.ts +0 -21
  139. package/src/init/types.ts +0 -89
  140. package/src/init/webframeworks.ts +0 -168
  141. package/src/kv.bun.ts +0 -12
  142. package/src/kv.node.ts +0 -11
  143. package/src/log.ts +0 -64
  144. package/src/lookup.test.ts +0 -182
  145. package/src/lookup.ts +0 -563
  146. package/src/mod.ts +0 -62
  147. package/src/nodeinfo.test.ts +0 -229
  148. package/src/nodeinfo.ts +0 -454
  149. package/src/table.ts +0 -17
  150. package/src/tempserver.ts +0 -87
  151. package/src/tunnel.test.ts +0 -157
  152. package/src/tunnel.ts +0 -94
  153. package/src/utils.ts +0 -254
  154. package/src/webfinger/action.ts +0 -50
  155. package/src/webfinger/command.ts +0 -64
  156. package/src/webfinger/error.ts +0 -47
  157. package/src/webfinger/lib.ts +0 -37
  158. package/src/webfinger/mod.test.ts +0 -79
  159. package/src/webfinger/mod.ts +0 -2
  160. package/tsdown.config.ts +0 -35
package/src/inbox.tsx DELETED
@@ -1,536 +0,0 @@
1
- /** @jsx react-jsx */
2
- /** @jsxImportSource hono/jsx */
3
- import {
4
- Accept,
5
- Activity,
6
- type Actor,
7
- Application,
8
- type Context,
9
- createFederation,
10
- Delete,
11
- Endpoints,
12
- Follow,
13
- generateCryptoKeyPair,
14
- getActorHandle,
15
- Image,
16
- isActor,
17
- lookupObject,
18
- MemoryKvStore,
19
- PUBLIC_COLLECTION,
20
- type Recipient,
21
- } from "@fedify/fedify";
22
- import { getLogger } from "@logtape/logtape";
23
- import {
24
- command,
25
- constant,
26
- type InferValue,
27
- merge,
28
- message,
29
- multiple,
30
- object,
31
- option,
32
- optional,
33
- string,
34
- withDefault,
35
- } from "@optique/core";
36
- import Table from "cli-table3";
37
- import { type Context as HonoContext, Hono } from "hono";
38
- import type { BlankEnv, BlankInput } from "hono/types";
39
- import process from "node:process";
40
- import ora from "ora";
41
- import metadata from "../deno.json" with { type: "json" };
42
- import { getDocumentLoader } from "./docloader.ts";
43
- import { configureLogging, debugOption } from "./globals.ts";
44
- import type { ActivityEntry } from "./inbox/entry.ts";
45
- import { ActivityEntryPage, ActivityListPage } from "./inbox/view.tsx";
46
- import { recordingSink } from "./log.ts";
47
- import { tableStyle } from "./table.ts";
48
- import { spawnTemporaryServer, type TemporaryServer } from "./tempserver.ts";
49
- import { colors } from "./utils.ts";
50
-
51
- /**
52
- * Context data for the ephemeral ActivityPub inbox server.
53
- *
54
- * This interface defines the shape of context data passed to federation
55
- * handlers during inbox command execution.
56
- */
57
- interface ContextData {
58
- activityIndex: number;
59
- actorName: string;
60
- actorSummary: string;
61
- }
62
-
63
- const logger = getLogger(["fedify", "cli", "inbox"]);
64
-
65
- export const inboxCommand = command(
66
- "inbox",
67
- merge(
68
- object("Inbox options", {
69
- command: constant("inbox"),
70
- follow: optional(
71
- multiple(
72
- option("-f", "--follow", string({ metavar: "URI" }), {
73
- description:
74
- message`Follow the given actor. The argument can be either an actor URI or a handle. Can be specified multiple times.`,
75
- }),
76
- ),
77
- ),
78
- acceptFollow: optional(
79
- multiple(
80
- option("-a", "--accept-follow", string({ metavar: "URI" }), {
81
- description:
82
- message`Accept follow requests from the given actor. The argument can be either an actor URI or a handle, or a wildcard (${"*"}). Can be specified multiple times. If a wildcard is specified, all follow requests will be accepted.`,
83
- }),
84
- ),
85
- ),
86
- noTunnel: option(
87
- "-T",
88
- "--no-tunnel",
89
- {
90
- description:
91
- message`Do not tunnel the ephemeral ActivityPub server to the public Internet.`,
92
- },
93
- ),
94
- actorName: withDefault(
95
- option("--actor-name", string({ metavar: "NAME" }), {
96
- description: message`Customize the actor display name.`,
97
- }),
98
- "Fedify Ephemeral Inbox",
99
- ),
100
- actorSummary: withDefault(
101
- option("--actor-summary", string({ metavar: "SUMMARY" }), {
102
- description: message`Customize the actor description.`,
103
- }),
104
- "An ephemeral ActivityPub inbox for testing purposes.",
105
- ),
106
- }),
107
- debugOption,
108
- ),
109
- {
110
- brief: message`Run an ephemeral ActivityPub inbox server.`,
111
- description:
112
- message`Spins up an ephemeral server that serves the ActivityPub inbox with an one-time actor, through a short-lived public DNS with HTTPS. You can monitor the incoming activities in real-time.`,
113
- },
114
- );
115
-
116
- export async function runInbox(
117
- command: InferValue<typeof inboxCommand>,
118
- ) {
119
- const fetch = createFetchHandler({
120
- actorName: command.actorName,
121
- actorSummary: command.actorSummary,
122
- });
123
- const sendDeleteToPeers = createSendDeleteToPeers({
124
- actorName: command.actorName,
125
- actorSummary: command.actorSummary,
126
- });
127
-
128
- // Enable Debug mode if requested
129
- if (command.debug) {
130
- await configureLogging();
131
- }
132
-
133
- const spinner = ora({
134
- text: "Spinning up an ephemeral ActivityPub server...",
135
- discardStdin: false,
136
- }).start();
137
- const server = await spawnTemporaryServer(fetch, {
138
- noTunnel: command.noTunnel,
139
- });
140
- spinner.succeed(
141
- `The ephemeral ActivityPub server is up and running: ${
142
- colors.green(
143
- server.url.href,
144
- )
145
- }`,
146
- );
147
- process.on("SIGINT", () => {
148
- spinner.stop();
149
- const peersCnt = Object.keys(peers).length;
150
- spinner.start(
151
- `Sending Delete(Application) activities to the ${peersCnt} ${
152
- peersCnt === 1 ? "peer" : "peers"
153
- }...`,
154
- );
155
- sendDeleteToPeers(server).then(() => {
156
- spinner.text = "Stopping server...";
157
- server.close().then(() => {
158
- spinner.succeed("Server stopped.");
159
- process.exit(0);
160
- });
161
- });
162
- });
163
- spinner.start();
164
-
165
- const fedCtx = federation.createContext(server.url, {
166
- activityIndex: -1,
167
- actorName: command.actorName,
168
- actorSummary: command.actorSummary,
169
- });
170
-
171
- if (command.acceptFollow != null && command.acceptFollow.length > 0) {
172
- acceptFollows.push(...(command.acceptFollow ?? []));
173
- }
174
- if (command.follow != null && command.follow.length > 0) {
175
- spinner.text = "Following actors...";
176
- const documentLoader = await fedCtx.getDocumentLoader({
177
- identifier: "i",
178
- });
179
- for (const uri of command.follow) {
180
- spinner.text = `Following ${colors.green(uri)}...`;
181
- const actor = await lookupObject(uri, { documentLoader });
182
- if (!isActor(actor)) {
183
- spinner.fail(`Not an actor: ${colors.red(uri)}`);
184
- spinner.start();
185
- continue;
186
- }
187
- if (actor.id != null) peers[actor.id?.href] = actor;
188
- await fedCtx.sendActivity(
189
- { identifier: "i" },
190
- actor,
191
- new Follow({
192
- id: new URL(`#follows/${actor.id?.href}`, fedCtx.getActorUri("i")),
193
- actor: fedCtx.getActorUri("i"),
194
- object: actor.id,
195
- }),
196
- );
197
- spinner.succeed(`Sent follow request to ${colors.green(uri)}.`);
198
- spinner.start();
199
- }
200
- }
201
- spinner.stop();
202
- printServerInfo(fedCtx);
203
- }
204
-
205
- const federationDocumentLoader = await getDocumentLoader();
206
-
207
- const federation = createFederation<ContextData>({
208
- kv: new MemoryKvStore(),
209
- documentLoaderFactory: () => {
210
- return federationDocumentLoader;
211
- },
212
- });
213
-
214
- const time = Temporal.Now.instant();
215
- let actorKeyPairs: CryptoKeyPair[] | undefined = undefined;
216
-
217
- federation
218
- .setActorDispatcher("/{identifier}", async (ctx, identifier) => {
219
- if (identifier !== "i") return null;
220
- return new Application({
221
- id: ctx.getActorUri(identifier),
222
- preferredUsername: identifier,
223
- name: ctx.data.actorName,
224
- summary: ctx.data.actorSummary,
225
- inbox: ctx.getInboxUri(identifier),
226
- endpoints: new Endpoints({
227
- sharedInbox: ctx.getInboxUri(),
228
- }),
229
- followers: ctx.getFollowersUri(identifier),
230
- following: ctx.getFollowingUri(identifier),
231
- outbox: ctx.getOutboxUri(identifier),
232
- manuallyApprovesFollowers: true,
233
- published: time,
234
- icon: new Image({
235
- url: new URL("https://fedify.dev/logo.png"),
236
- mediaType: "image/png",
237
- }),
238
- publicKey: (await ctx.getActorKeyPairs(identifier))[0].cryptographicKey,
239
- assertionMethods: (await ctx.getActorKeyPairs(identifier))
240
- .map((pair) => pair.multikey),
241
- url: ctx.getActorUri(identifier),
242
- });
243
- })
244
- .setKeyPairsDispatcher(async (_ctxData, identifier) => {
245
- if (identifier !== "i") return [];
246
- if (actorKeyPairs == null) {
247
- actorKeyPairs = [
248
- await generateCryptoKeyPair("RSASSA-PKCS1-v1_5"),
249
- await generateCryptoKeyPair("Ed25519"),
250
- ];
251
- }
252
- return actorKeyPairs;
253
- });
254
-
255
- const activities: ActivityEntry[] = [];
256
-
257
- const acceptFollows: string[] = [];
258
-
259
- async function acceptsFollowFrom(actor: Actor): Promise<boolean> {
260
- const actorUri = actor.id;
261
- let actorHandle: string | undefined = undefined;
262
- if (actorUri == null) return false;
263
- for (let uri of acceptFollows) {
264
- if (uri === "*") return true;
265
- if (uri.startsWith("http:") || uri.startsWith("https:")) {
266
- uri = new URL(uri).href; // normalize
267
- if (uri === actorUri.href) return true;
268
- }
269
- if (actorHandle == null) actorHandle = await getActorHandle(actor);
270
- if (actorHandle === uri) return true;
271
- }
272
- return false;
273
- }
274
-
275
- const peers: Record<string, Actor> = {};
276
-
277
- function createSendDeleteToPeers(
278
- actorOptions: { actorName: string; actorSummary: string },
279
- ): (server: TemporaryServer) => Promise<void> {
280
- return async function sendDeleteToPeers(
281
- server: TemporaryServer,
282
- ): Promise<void> {
283
- const ctx = federation.createContext(new Request(server.url), {
284
- activityIndex: -1,
285
- actorName: actorOptions.actorName,
286
- actorSummary: actorOptions.actorSummary,
287
- });
288
-
289
- const actor = (await ctx.getActor("i"))!;
290
- try {
291
- await ctx.sendActivity(
292
- { identifier: "i" },
293
- Object.values(peers),
294
- new Delete({
295
- id: new URL(`#delete`, actor.id!),
296
- actor: actor.id!,
297
- to: PUBLIC_COLLECTION,
298
- object: actor,
299
- }),
300
- );
301
- } catch (error) {
302
- logger.error(
303
- "Failed to send Delete(Application) activities to peers:\n{error}",
304
- { error },
305
- );
306
- }
307
- };
308
- }
309
-
310
- const followers: Record<string, Actor> = {};
311
-
312
- federation
313
- .setInboxListeners("/{identifier}/inbox", "/inbox")
314
- .setSharedKeyDispatcher((_) => ({ identifier: "i" }))
315
- .on(Activity, async (ctx, activity) => {
316
- activities[ctx.data.activityIndex].activity = activity;
317
- for await (const actor of activity.getActors()) {
318
- if (actor.id != null) peers[actor.id.href] = actor;
319
- }
320
- for await (const actor of activity.getAttributions()) {
321
- if (actor.id != null) peers[actor.id.href] = actor;
322
- }
323
- if (activity instanceof Follow) {
324
- if (acceptFollows.length < 1) return;
325
- const objectId = activity.objectId;
326
- if (objectId == null) return;
327
- const parsed = ctx.parseUri(objectId);
328
- if (parsed?.type !== "actor" || parsed.identifier !== "i") return;
329
- const { identifier } = parsed;
330
- const follower = await activity.getActor();
331
- if (!isActor(follower)) return;
332
- const accepts = await acceptsFollowFrom(follower);
333
- if (!accepts || activity.id == null) {
334
- logger.debug("Does not accept follow from {actor}.", {
335
- actor: follower.id?.href,
336
- });
337
- return;
338
- }
339
- logger.debug("Accepting follow from {actor}.", {
340
- actor: follower.id?.href,
341
- });
342
- followers[activity.id.href] = follower;
343
- await ctx.sendActivity(
344
- { identifier },
345
- follower,
346
- new Accept({
347
- id: new URL(`#accepts/${follower.id?.href}`, ctx.getActorUri("i")),
348
- actor: ctx.getActorUri(identifier),
349
- object: activity.id,
350
- }),
351
- );
352
- }
353
- });
354
-
355
- federation
356
- .setFollowersDispatcher("/{identifier}/followers", (_ctx, identifier) => {
357
- if (identifier !== "i") return null;
358
- const items: Recipient[] = [];
359
- for (const follower of Object.values(followers)) {
360
- if (follower.id == null) continue;
361
- items.push(follower);
362
- }
363
- return { items };
364
- })
365
- .setCounter((_ctx, identifier) => {
366
- if (identifier !== "i") return null;
367
- return Object.keys(followers).length;
368
- });
369
-
370
- federation
371
- .setFollowingDispatcher(
372
- "/{identifier}/following",
373
- (_ctx, _identifier) => null,
374
- )
375
- .setCounter((_ctx, _identifier) => 0);
376
-
377
- federation
378
- .setOutboxDispatcher("/{identifier}/outbox", (_ctx, _identifier) => null)
379
- .setCounter((_ctx, _identifier) => 0);
380
-
381
- federation.setNodeInfoDispatcher("/nodeinfo/2.1", (_ctx) => {
382
- return {
383
- software: {
384
- name: "fedify-cli",
385
- version: metadata.version,
386
- repository: new URL("https://github.com/fedify-dev/fedify"),
387
- },
388
- protocols: ["activitypub"],
389
- usage: {
390
- users: {
391
- total: 1,
392
- activeMonth: 1,
393
- activeHalfyear: 1,
394
- },
395
- localComments: 0,
396
- localPosts: 0,
397
- },
398
- };
399
- });
400
-
401
- function printServerInfo(fedCtx: Context<ContextData>): void {
402
- const table = new Table({
403
- chars: tableStyle,
404
- style: { head: [], border: [] },
405
- });
406
-
407
- table.push(
408
- { "Actor handle:": colors.green(`i@${fedCtx.getActorUri("i").host}`) },
409
- { "Actor URI:": colors.green(fedCtx.getActorUri("i").href) },
410
- { "Actor inbox:": colors.green(fedCtx.getInboxUri("i").href) },
411
- { "Shared inbox:": colors.green(fedCtx.getInboxUri().href) },
412
- );
413
-
414
- console.log(table.toString());
415
- }
416
-
417
- async function printActivityEntry(
418
- idx: number,
419
- entry: ActivityEntry,
420
- ): Promise<void> {
421
- const request = entry.request.clone();
422
- const response = entry.response?.clone();
423
- const url = new URL(request.url);
424
- const activity = entry.activity;
425
- const object = await activity?.getObject();
426
-
427
- const table = new Table({
428
- chars: tableStyle,
429
- style: { head: [], border: [] },
430
- });
431
-
432
- table.push(
433
- { "Request #:": colors.bold(idx.toString()) },
434
- {
435
- "Activity type:": activity == null
436
- ? colors.red("failed to parse")
437
- : colors.green(
438
- `${activity.constructor.name}(${object?.constructor.name})`,
439
- ),
440
- },
441
- {
442
- "HTTP request:": `${
443
- request.method === "POST"
444
- ? colors.green("POST")
445
- : colors.red(request.method)
446
- } ${url.pathname + url.search}`,
447
- },
448
- ...(response == null ? [] : [{
449
- "HTTP response:": `${
450
- response.ok
451
- ? colors.green(response.status.toString())
452
- : colors.red(response.status.toString())
453
- } ${response.statusText}`,
454
- }]),
455
- { "Details": new URL(`/r/${idx}`, url).href },
456
- );
457
-
458
- console.log(table.toString());
459
- }
460
-
461
- function getHandle<T extends string>(
462
- c: HonoContext<BlankEnv, T, BlankInput>,
463
- ): string {
464
- const url = new URL(c.req.url);
465
- return `@i@${url.host}`;
466
- }
467
-
468
- const app = new Hono();
469
-
470
- app.get("/", (c) => c.redirect("/r"));
471
-
472
- app.get(
473
- "/r",
474
- (c) =>
475
- c.html(
476
- <ActivityListPage handle={getHandle(c)} entries={activities} />,
477
- ),
478
- );
479
-
480
- app.get("/r/:idx{[0-9]+}", (c) => {
481
- const idx = parseInt(c.req.param("idx"));
482
- const tab = c.req.query("tab") ?? "request";
483
- const activity = activities[idx];
484
- if (activity == null) return c.notFound();
485
- if (
486
- tab !== "request" && tab !== "response" && tab !== "raw-activity" &&
487
- tab !== "compact-activity" && tab !== "expanded-activity" && tab !== "logs"
488
- ) {
489
- return c.notFound();
490
- }
491
- return c.html(
492
- <ActivityEntryPage
493
- handle={getHandle(c)}
494
- idx={idx}
495
- entry={activity}
496
- tabPage={tab}
497
- />,
498
- );
499
- });
500
-
501
- function createFetchHandler(
502
- actorOptions: { actorName: string; actorSummary: string },
503
- ): (request: Request) => Promise<Response> {
504
- return async function fetch(request: Request): Promise<Response> {
505
- const timestamp = Temporal.Now.instant();
506
- const idx = activities.length;
507
- const pathname = new URL(request.url).pathname;
508
- if (pathname === "/r" || pathname.startsWith("/r/")) {
509
- return app.fetch(request);
510
- }
511
- const inboxRequest = pathname === "/inbox" ||
512
- pathname.startsWith("/i/inbox");
513
- if (inboxRequest) {
514
- recordingSink.startRecording();
515
- // @ts-ignore: Work around `deno publish --dry-run` bug
516
- activities.push({ timestamp, request: request.clone(), logs: [] });
517
- }
518
- const response = await federation.fetch(request, {
519
- contextData: {
520
- activityIndex: inboxRequest ? idx : -1,
521
- actorName: actorOptions.actorName,
522
- actorSummary: actorOptions.actorSummary,
523
- },
524
- onNotAcceptable: app.fetch.bind(app),
525
- onNotFound: app.fetch.bind(app),
526
- onUnauthorized: app.fetch.bind(app),
527
- });
528
- if (inboxRequest) {
529
- recordingSink.stopRecording();
530
- activities[idx].response = response.clone();
531
- activities[idx].logs = recordingSink.getRecords();
532
- await printActivityEntry(idx, activities[idx]);
533
- }
534
- return response;
535
- };
536
- }
@@ -1,133 +0,0 @@
1
- import {
2
- concat,
3
- filter,
4
- keys,
5
- map,
6
- pick,
7
- pipe,
8
- toArray,
9
- } from "@fxts/core/index.js";
10
- import { uniq } from "es-toolkit";
11
- import { realpathSync } from "node:fs";
12
- import { join as joinPath, relative } from "node:path";
13
- import { merge } from "../../utils.ts";
14
- import biome from "../json/biome.json" with { type: "json" };
15
- import vscodeSettingsForDeno from "../json/vscode-settings-for-deno.json" with {
16
- type: "json",
17
- };
18
- import vscodeSettings from "../json/vscode-settings.json" with {
19
- type: "json",
20
- };
21
- import type { InitCommandData } from "../types.ts";
22
- import { PACKAGES_PATH } from "./const.ts";
23
- import { getDependencies, getDevDependencies, joinDepsReg } from "./deps.ts";
24
-
25
- /**
26
- * Loads Deno configuration object with compiler options, unstable features, and tasks.
27
- * Combines unstable features required by KV store and message queue with framework-specific options.
28
- *
29
- * @param param0 - Destructured initialization data containing KV, MQ, initializer, and directory
30
- * @returns Configuration object with path and Deno-specific settings
31
- */
32
- export const loadDenoConfig = (
33
- data: InitCommandData,
34
- ) => ({
35
- path: "deno.json",
36
- data: {
37
- ...pick(["compilerOptions", "tasks"], data.initializer),
38
- unstable: getUnstable(data),
39
- nodeModulesDir: "auto",
40
- imports: joinDepsReg("deno")(getDependencies(data)),
41
- ...(data.testMode ? { links: getLinks(data) } : {}),
42
- },
43
- });
44
-
45
- const getUnstable = <T extends Pick<InitCommandData, "kv" | "mq">>({
46
- kv: { denoUnstable: kv = [] },
47
- mq: { denoUnstable: mq = [] },
48
- }: T) =>
49
- pipe(
50
- ["temporal"],
51
- concat(kv),
52
- concat(mq),
53
- toArray,
54
- uniq,
55
- );
56
-
57
- const getLinks = <
58
- T extends Pick<InitCommandData, "kv" | "mq" | "initializer" | "dir">,
59
- >({ kv, mq, initializer, dir }: T) =>
60
- pipe(
61
- { "@fedify/fedify": "" },
62
- merge(initializer.dependencies),
63
- merge(kv.dependencies),
64
- merge(mq.dependencies),
65
- keys,
66
- filter((dep) => dep.includes("@fedify/")),
67
- map((dep) => dep.replace("@fedify/", "")),
68
- map((dep) => joinPath(PACKAGES_PATH, dep)),
69
- map((absolutePath) => realpathSync(absolutePath)),
70
- map((realAbsolutePath) => relative(realpathSync(dir), realAbsolutePath)),
71
- toArray,
72
- );
73
-
74
- /**
75
- * Loads TypeScript configuration object for Node.js/Bun projects.
76
- * Uses compiler options from the framework initializer.
77
- *
78
- * @param param0 - Destructured initialization data containing initializer and directory
79
- * @returns Configuration object with path and TypeScript compiler options
80
- */
81
- export const loadTsConfig = ({ initializer, dir }: InitCommandData) => ({
82
- path: joinPath(dir, "tsconfig.json"),
83
- data: {
84
- compilerOptions: initializer.compilerOptions,
85
- },
86
- });
87
-
88
- /**
89
- * Loads package.json configuration object for Node.js/Bun projects.
90
- * Sets up ES modules and includes framework-specific npm scripts.
91
- *
92
- * @param param0 - Destructured initialization data containing initializer and directory
93
- * @returns Configuration object with path and package.json settings
94
- */
95
- export const loadPackageJson = (
96
- data: InitCommandData,
97
- ) => ({
98
- path: "package.json",
99
- data: {
100
- type: "module",
101
- scripts: data.initializer.tasks,
102
- dependencies: getDependencies(data),
103
- devDependencies: getDevDependencies(data),
104
- },
105
- });
106
-
107
- /**
108
- * Configuration objects for various development tool setup files.
109
- * Contains predefined configurations for code formatting, VS Code settings, and extensions
110
- * based on the project type (Node.js/Bun or Deno).
111
- */
112
- export const devToolConfigs = {
113
- biome: {
114
- path: joinPath("biome.json"),
115
- data: biome,
116
- },
117
- vscExt: {
118
- path: joinPath(".vscode", "extensions.json"),
119
- data: { recommendations: ["biomejs.biome"] },
120
- },
121
- vscSet: {
122
- path: joinPath(".vscode", "settings.json"),
123
- data: vscodeSettings,
124
- },
125
- vscSetDeno: {
126
- path: joinPath(".vscode", "settings.json"),
127
- data: vscodeSettingsForDeno,
128
- },
129
- vscExtDeno: {
130
- path: joinPath(".vscode", "extensions.json"),
131
- data: { recommendations: ["denoland.vscode-deno"] },
132
- },
133
- } as const;
@@ -1,9 +0,0 @@
1
- import { join as joinPath } from "node:path";
2
-
3
- export const PACKAGES_PATH = joinPath(
4
- import.meta.dirname!, // action
5
- "..", // init
6
- "..", // src
7
- "..", // cli
8
- "..", // packages
9
- );