@fedify/cli 2.0.0-pr.458.1796 → 2.0.0-pr.467.1877
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +1 -1
- package/dist/deno.js +1 -1
- package/dist/generate-vocab/command.js +6 -6
- package/dist/inbox.js +5 -2
- package/dist/init/command.js +18 -10
- package/dist/init/templates/defaults/federation.ts.tpl +23 -0
- package/dist/init/templates/defaults/logging.ts.tpl +23 -0
- package/dist/init/templates/express/app.ts.tpl +16 -0
- package/dist/init/templates/express/index.ts.tpl +6 -0
- package/dist/init/templates/hono/app.tsx.tpl +14 -0
- package/dist/init/templates/hono/index/bun.ts.tpl +10 -0
- package/dist/init/templates/hono/index/deno.ts.tpl +13 -0
- package/dist/init/templates/hono/index/node.ts.tpl +14 -0
- package/dist/init/templates/next/middleware.ts.tpl +45 -0
- package/dist/init/templates/nitro/nitro.config.ts.tpl +5 -0
- package/dist/init/templates/nitro/server/error.ts.tpl +3 -0
- package/dist/init/templates/nitro/server/middleware/federation.ts.tpl +8 -0
- package/dist/lookup.js +8 -3
- package/dist/nodeinfo.js +10 -5
- package/dist/tunnel.js +7 -2
- package/dist/webfinger/command.js +7 -2
- package/package.json +6 -6
- package/scripts/pack.ts +8 -1
- package/src/generate-vocab/command.ts +16 -8
- package/src/inbox.tsx +2 -1
- package/src/init/command.ts +39 -15
- package/src/lookup.ts +8 -3
- package/src/nodeinfo.ts +11 -5
- package/src/tunnel.ts +9 -5
- package/src/webfinger/command.ts +10 -5
- package/tsdown.config.ts +11 -0
package/deno.json
CHANGED
package/dist/deno.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
|
|
4
|
-
import { command, constant, message, object, option } from "@optique/core";
|
|
4
|
+
import { argument, command, constant, message, object, option, withDefault } from "@optique/core";
|
|
5
5
|
import { path } from "@optique/run";
|
|
6
6
|
|
|
7
7
|
//#region src/generate-vocab/command.ts
|
|
8
|
-
const schemaDir = option("-i", "--input", path({
|
|
8
|
+
const schemaDir = withDefault(option("-i", "--input", path({
|
|
9
9
|
metavar: "DIR",
|
|
10
10
|
type: "directory",
|
|
11
11
|
mustExist: true
|
|
12
|
-
}));
|
|
13
|
-
const generatedPath =
|
|
12
|
+
}), { description: message`Directory containing schema files.` }), ".");
|
|
13
|
+
const generatedPath = argument(path({
|
|
14
14
|
metavar: "PATH",
|
|
15
15
|
type: "file",
|
|
16
16
|
allowCreate: true
|
|
17
|
-
}));
|
|
18
|
-
const generateVocabCommand = command("generate-vocab", object({
|
|
17
|
+
}), { description: message`Path to output the generated vocabulary classes. Should end with ${".ts"} suffix.` });
|
|
18
|
+
const generateVocabCommand = command("generate-vocab", object("Generation options", {
|
|
19
19
|
command: constant("generate-vocab"),
|
|
20
20
|
schemaDir,
|
|
21
21
|
generatedPath
|
package/dist/inbox.js
CHANGED
|
@@ -27,11 +27,14 @@ const logger = getLogger([
|
|
|
27
27
|
const inboxCommand = command("inbox", merge(object("Inbox options", {
|
|
28
28
|
command: constant("inbox"),
|
|
29
29
|
follow: optional(multiple(option("-f", "--follow", string({ metavar: "URI" }), { description: message`Follow the given actor. The argument can be either an actor URI or a handle. Can be specified multiple times.` }))),
|
|
30
|
-
acceptFollow: optional(multiple(option("-a", "--accept-follow", string({ metavar: "URI" }), { description: 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.` }))),
|
|
30
|
+
acceptFollow: optional(multiple(option("-a", "--accept-follow", string({ metavar: "URI" }), { description: 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.` }))),
|
|
31
31
|
noTunnel: option("-T", "--no-tunnel", { description: message`Do not tunnel the ephemeral ActivityPub server to the public Internet.` }),
|
|
32
32
|
actorName: withDefault(option("--actor-name", string({ metavar: "NAME" }), { description: message`Customize the actor display name.` }), "Fedify Ephemeral Inbox"),
|
|
33
33
|
actorSummary: withDefault(option("--actor-summary", string({ metavar: "SUMMARY" }), { description: message`Customize the actor description.` }), "An ephemeral ActivityPub inbox for testing purposes.")
|
|
34
|
-
}), debugOption), {
|
|
34
|
+
}), debugOption), {
|
|
35
|
+
brief: message`Run an ephemeral ActivityPub inbox server.`,
|
|
36
|
+
description: 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.`
|
|
37
|
+
});
|
|
35
38
|
async function runInbox(command$1) {
|
|
36
39
|
const fetch = createFetchHandler({
|
|
37
40
|
actorName: command$1.actorName,
|
package/dist/init/command.js
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
|
|
4
|
+
import { debugOption } from "../globals.js";
|
|
4
5
|
import { KV_STORE, MESSAGE_QUEUE, PACKAGE_MANAGER, WEB_FRAMEWORK } from "./const.js";
|
|
5
|
-
import { argument, choice, command, constant, message, object, option, optional } from "@optique/core";
|
|
6
|
+
import { argument, choice, command, constant, message, object, option, optionNames, optional } from "@optique/core";
|
|
6
7
|
import { path } from "@optique/run";
|
|
7
8
|
|
|
8
9
|
//#region src/init/command.ts
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const initCommand = command("init", object({
|
|
10
|
+
const webFramework = optional(option("-w", "--web-framework", choice(WEB_FRAMEWORK, { metavar: "WEB_FRAMEWORK" }), { description: message`The web framework to integrate Fedify with.` }));
|
|
11
|
+
const packageManager = optional(option("-p", "--package-manager", choice(PACKAGE_MANAGER, { metavar: "PACKAGE_MANAGER" }), { description: message`The package manager to use for installing dependencies.` }));
|
|
12
|
+
const kvStore = optional(option("-k", "--kv-store", choice(KV_STORE, { metavar: "KV_STORE" }), { description: message`The key-value store to use for caching and some other features.` }));
|
|
13
|
+
const messageQueue = optional(option("-m", "--message-queue", choice(MESSAGE_QUEUE, { metavar: "MESSAGE_QUEUE" }), { description: message`The message queue to use for background tasks.` }));
|
|
14
|
+
const initCommand = command("init", object("Initialization options", {
|
|
15
15
|
command: constant("init"),
|
|
16
|
-
dir: optional(argument(path({ metavar: "
|
|
16
|
+
dir: optional(argument(path({ metavar: "DIR" }), { description: message`The project directory to initialize. If a specified directory does not exist, it will be created.` })),
|
|
17
17
|
webFramework,
|
|
18
18
|
packageManager,
|
|
19
19
|
kvStore,
|
|
20
20
|
messageQueue,
|
|
21
|
-
dryRun: option("-d", "--dry-run")
|
|
22
|
-
|
|
21
|
+
dryRun: option("-d", "--dry-run", { description: message`Perform a trial run with no changes made.` }),
|
|
22
|
+
debugOption
|
|
23
|
+
}), {
|
|
24
|
+
brief: message`Initialize a new Fedify project directory.`,
|
|
25
|
+
description: message`Initialize a new Fedify project directory.
|
|
26
|
+
|
|
27
|
+
By default, it initializes the current directory. You can specify a different directory as an argument.
|
|
28
|
+
|
|
29
|
+
Unless you specify all options (${optionNames(["-w", "--web-framework"])}, ${optionNames(["-p", "--package-manager"])}, ${optionNames(["-k", "--kv-store"])}, and ${optionNames(["-m", "--message-queue"])}), it will prompt you to select the options interactively.`
|
|
30
|
+
});
|
|
23
31
|
|
|
24
32
|
//#endregion
|
|
25
33
|
export { initCommand };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createFederation, Person } from "@fedify/fedify";
|
|
2
|
+
import { getLogger } from "@logtape/logtape";
|
|
3
|
+
/* imports */
|
|
4
|
+
|
|
5
|
+
const logger = getLogger(/* logger */);
|
|
6
|
+
|
|
7
|
+
const federation = createFederation({
|
|
8
|
+
kv: /* kv */,
|
|
9
|
+
queue: /* queue */,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
federation.setActorDispatcher(
|
|
13
|
+
"/users/{identifier}",
|
|
14
|
+
async (ctx, identifier) => {
|
|
15
|
+
return new Person({
|
|
16
|
+
id: ctx.getActorUri(identifier),
|
|
17
|
+
preferredUsername: identifier,
|
|
18
|
+
name: identifier,
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export default federation;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { configure, getConsoleSink } from "@logtape/logtape";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
|
|
4
|
+
await configure({
|
|
5
|
+
contextLocalStorage: new AsyncLocalStorage(),
|
|
6
|
+
sinks: {
|
|
7
|
+
console: getConsoleSink(),
|
|
8
|
+
},
|
|
9
|
+
filters: {},
|
|
10
|
+
loggers: [
|
|
11
|
+
{
|
|
12
|
+
category: /* project name */,
|
|
13
|
+
lowestLevel: "debug",
|
|
14
|
+
sinks: ["console"],
|
|
15
|
+
},
|
|
16
|
+
{ category: "fedify", lowestLevel: "info", sinks: ["console"] },
|
|
17
|
+
{
|
|
18
|
+
category: ["logtape", "meta"],
|
|
19
|
+
lowestLevel: "warning",
|
|
20
|
+
sinks: ["console"],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { integrateFederation } from "@fedify/express";
|
|
2
|
+
import { getLogger } from "@logtape/logtape";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import federation from "./federation.ts";
|
|
5
|
+
|
|
6
|
+
const logger = getLogger("/* logger */");
|
|
7
|
+
|
|
8
|
+
export const app = express();
|
|
9
|
+
|
|
10
|
+
app.set("trust proxy", true);
|
|
11
|
+
|
|
12
|
+
app.use(integrateFederation(federation, () => undefined));
|
|
13
|
+
|
|
14
|
+
app.get("/", (_, res) => res.send("Hello, Fedify!"));
|
|
15
|
+
|
|
16
|
+
export default app;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @ts-nocheck this file is just a template
|
|
2
|
+
import { Hono } from "/* hono */";
|
|
3
|
+
import { federation } from "@fedify/hono";
|
|
4
|
+
import { getLogger } from "@logtape/logtape";
|
|
5
|
+
import fedi from "./federation.ts";
|
|
6
|
+
|
|
7
|
+
const logger = getLogger("/* logger */");
|
|
8
|
+
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
app.use(federation(fedi, () => undefined));
|
|
11
|
+
|
|
12
|
+
app.get("/", (c) => c.text("Hello, Fedify!"));
|
|
13
|
+
|
|
14
|
+
export default app;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { behindProxy } from "@hongminhee/x-forwarded-fetch";
|
|
2
|
+
import "@std/dotenv/load";
|
|
3
|
+
import app from "./app.tsx";
|
|
4
|
+
import "./logging.ts";
|
|
5
|
+
|
|
6
|
+
Deno.serve(
|
|
7
|
+
{
|
|
8
|
+
port: 8000,
|
|
9
|
+
onListen: ({ port, hostname }) =>
|
|
10
|
+
console.log("Server started at http://" + hostname + ":" + port),
|
|
11
|
+
},
|
|
12
|
+
behindProxy(app.fetch.bind(app)),
|
|
13
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @ts-nocheck this file is just a template
|
|
2
|
+
import { serve } from "@hono/node-server";
|
|
3
|
+
import { behindProxy } from "x-forwarded-fetch";
|
|
4
|
+
import app from "./app.tsx";
|
|
5
|
+
import "./logging.ts";
|
|
6
|
+
|
|
7
|
+
serve(
|
|
8
|
+
{
|
|
9
|
+
port: 8000,
|
|
10
|
+
fetch: behindProxy(app.fetch.bind(app)),
|
|
11
|
+
},
|
|
12
|
+
(info) =>
|
|
13
|
+
console.log("Server started at http://" + info.address + ":" + info.port),
|
|
14
|
+
);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { fedifyWith } from "@fedify/next";
|
|
2
|
+
import federation from "./federation";
|
|
3
|
+
|
|
4
|
+
export default fedifyWith(federation)(
|
|
5
|
+
/*
|
|
6
|
+
function (request: Request) {
|
|
7
|
+
// If you need to handle other requests besides federation
|
|
8
|
+
// requests in middleware, you can do it here.
|
|
9
|
+
// If you handle only federation requests in middleware,
|
|
10
|
+
// you don't need this function.
|
|
11
|
+
return NextResponse.next();
|
|
12
|
+
},
|
|
13
|
+
*/
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
// This config needs because middleware process only requests with the
|
|
17
|
+
// "Accept" header matching the federation accept regex.
|
|
18
|
+
// More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional
|
|
19
|
+
export const config = {
|
|
20
|
+
runtime: "nodejs",
|
|
21
|
+
matcher: [
|
|
22
|
+
{
|
|
23
|
+
source: "/:path*",
|
|
24
|
+
has: [
|
|
25
|
+
{
|
|
26
|
+
type: "header",
|
|
27
|
+
key: "Accept",
|
|
28
|
+
value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
source: "/:path*",
|
|
34
|
+
has: [
|
|
35
|
+
{
|
|
36
|
+
type: "header",
|
|
37
|
+
key: "content-type",
|
|
38
|
+
value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{ source: "/.well-known/nodeinfo" },
|
|
43
|
+
{ source: "/.well-known/x-nodeinfo2" },
|
|
44
|
+
],
|
|
45
|
+
};
|
package/dist/lookup.js
CHANGED
|
@@ -6,7 +6,7 @@ import { configureLogging, debugOption } from "./globals.js";
|
|
|
6
6
|
import { spawnTemporaryServer } from "./tempserver.js";
|
|
7
7
|
import { colorEnabled, colors, formatObject } from "./utils.js";
|
|
8
8
|
import { renderImages } from "./imagerenderer.js";
|
|
9
|
-
import { argument, choice, command, constant, flag, float, map, merge, message, multiple, object, option, optional, or, string, withDefault } from "@optique/core";
|
|
9
|
+
import { argument, choice, command, constant, flag, float, map, merge, message, multiple, object, option, optionNames, optional, or, string, withDefault } from "@optique/core";
|
|
10
10
|
import { path, print, printError } from "@optique/run";
|
|
11
11
|
import process from "node:process";
|
|
12
12
|
import { Application, Collection, CryptographicKey, Object as Object$1, generateCryptoKeyPair, getAuthenticatedDocumentLoader, lookupObject, respondWithObject, traverseCollection } from "@fedify/fedify";
|
|
@@ -22,7 +22,7 @@ const logger = getLogger([
|
|
|
22
22
|
]);
|
|
23
23
|
const authorizedFetchOption = withDefault(object({
|
|
24
24
|
authorizedFetch: flag("-a", "--authorized-fetch", { description: message`Sign the request with an one-time key.` }),
|
|
25
|
-
firstKnock: withDefault(option("--first-knock", choice(["draft-cavage-http-signatures-12", "rfc9421"]), { description: message`The first-knock spec for -a
|
|
25
|
+
firstKnock: withDefault(option("--first-knock", choice(["draft-cavage-http-signatures-12", "rfc9421"]), { description: message`The first-knock spec for ${optionNames(["-a", "--authorized-fetch"])}. It is used for the double-knocking technique.` }), "draft-cavage-http-signatures-12")
|
|
26
26
|
}), { authorizedFetch: false });
|
|
27
27
|
const traverseOption = withDefault(object({
|
|
28
28
|
traverse: flag("-t", "--traverse", { description: message`Traverse the given collection(s) to fetch all items.` }),
|
|
@@ -42,7 +42,12 @@ const lookupCommand = command("lookup", merge("Looking up options", object({ com
|
|
|
42
42
|
min: 0,
|
|
43
43
|
metavar: "SECONDS"
|
|
44
44
|
}), { description: message`Set timeout for network requests in seconds.` }))
|
|
45
|
-
})), {
|
|
45
|
+
})), {
|
|
46
|
+
brief: message`Look up Activity Streams objects.`,
|
|
47
|
+
description: message`Look up Activity Streams objects by URL or actor handle.
|
|
48
|
+
|
|
49
|
+
The arguments can be either URLs or actor handles (e.g., ${"@username@domain"}), and they can be multiple.`
|
|
50
|
+
});
|
|
46
51
|
var TimeoutError = class extends Error {
|
|
47
52
|
name = "TimeoutError";
|
|
48
53
|
constructor(message$1) {
|
package/dist/nodeinfo.js
CHANGED
|
@@ -27,15 +27,20 @@ const Jimp = createJimp({
|
|
|
27
27
|
plugins: defaultPlugins
|
|
28
28
|
});
|
|
29
29
|
const nodeInfoOption = optional(or(object({ raw: flag("-r", "--raw", { description: message`Show NodeInfo document in the raw JSON format` }) }), object({
|
|
30
|
-
bestEffort: optional(flag("-b", "--best-effort", { description: message`Parse the NodeInfo document with best effort.
|
|
30
|
+
bestEffort: optional(flag("-b", "--best-effort", { description: message`Parse the NodeInfo document with best effort. If the NodeInfo document is not well-formed, the option will try to parse it as much as possible.` })),
|
|
31
31
|
noFavicon: optional(flag("--no-favicon", { description: message`Disable fetching the favicon of the instance` })),
|
|
32
|
-
metadata: optional(flag("-m", "--metadata", { description: message`
|
|
32
|
+
metadata: optional(flag("-m", "--metadata", { description: message`Show the extra metadata of the NodeInfo, i.e., the metadata field of the document.` }))
|
|
33
33
|
})));
|
|
34
|
-
const userAgentOption = optional(object({ userAgent: option("-u", "--user-agent", string()) }));
|
|
34
|
+
const userAgentOption = optional(object({ userAgent: option("-u", "--user-agent", string(), { description: message`The custom User-Agent header value.` }) }));
|
|
35
35
|
const nodeInfoCommand = command("nodeinfo", merge(object({
|
|
36
36
|
command: constant("nodeinfo"),
|
|
37
|
-
host: argument(string({ metavar: "
|
|
38
|
-
}), debugOption, nodeInfoOption, userAgentOption), {
|
|
37
|
+
host: argument(string({ metavar: "HOST" }), { description: message`Bare hostname or a full URL of the instance` })
|
|
38
|
+
}), debugOption, nodeInfoOption, userAgentOption), {
|
|
39
|
+
brief: message`Get information about a remote node using the NodeInfo protocol`,
|
|
40
|
+
description: message`Get information about a remote node using the NodeInfo protocol.
|
|
41
|
+
|
|
42
|
+
The argument is the hostname of the remote node, or the URL of the remote node.`
|
|
43
|
+
});
|
|
39
44
|
async function runNodeInfo(command$1) {
|
|
40
45
|
const spinner = ora({
|
|
41
46
|
text: "Fetching a NodeInfo document...",
|
package/dist/tunnel.js
CHANGED
|
@@ -20,8 +20,13 @@ const tunnelCommand = command("tunnel", merge("Tunnel options", object({ command
|
|
|
20
20
|
"localhost.run",
|
|
21
21
|
"serveo.net",
|
|
22
22
|
"pinggy.io"
|
|
23
|
-
]), { description: message`The
|
|
24
|
-
}), debugOption), {
|
|
23
|
+
], { metavar: "SERVICE" }), { description: message`The tunneling service to use.` }))
|
|
24
|
+
}), debugOption), {
|
|
25
|
+
brief: message`Expose a local HTTP server to the public internet using a secure tunnel.`,
|
|
26
|
+
description: message`Expose a local HTTP server to the public internet using a secure tunnel.
|
|
27
|
+
|
|
28
|
+
Note that the HTTP requests through the tunnel have X-Forwarded-* headers.`
|
|
29
|
+
});
|
|
25
30
|
async function runTunnel(command$1, deps = {
|
|
26
31
|
openTunnel,
|
|
27
32
|
ora,
|
|
@@ -10,11 +10,16 @@ const allowPrivateAddresses = optional(flag("-p", "--allow-private-address", { d
|
|
|
10
10
|
const maxRedirection = withDefault(option("--max-redirection", integer({ min: 0 }), { description: message`Maximum number of redirections to follow.` }), 5);
|
|
11
11
|
const webFingerCommand = command("webfinger", merge(object({
|
|
12
12
|
command: constant("webfinger"),
|
|
13
|
-
resources: multiple(argument(string({ metavar: "RESOURCE" }), { description: message`WebFinger resource(s) to look up.` })),
|
|
13
|
+
resources: multiple(argument(string({ metavar: "RESOURCE" }), { description: message`WebFinger resource(s) to look up.` }), { min: 1 }),
|
|
14
14
|
userAgent,
|
|
15
15
|
allowPrivateAddresses,
|
|
16
16
|
maxRedirection
|
|
17
|
-
}), debugOption), {
|
|
17
|
+
}), debugOption), {
|
|
18
|
+
brief: message`Look up WebFinger resources.`,
|
|
19
|
+
description: message`Look up WebFinger resources.
|
|
20
|
+
|
|
21
|
+
The argument can be multiple.`
|
|
22
|
+
});
|
|
18
23
|
|
|
19
24
|
//#endregion
|
|
20
25
|
export { webFingerCommand };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/cli",
|
|
3
|
-
"version": "2.0.0-pr.
|
|
3
|
+
"version": "2.0.0-pr.467.1877+dc12636d",
|
|
4
4
|
"description": "CLI toolchain for Fedify and debugging ActivityPub",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fedify",
|
|
@@ -71,16 +71,16 @@
|
|
|
71
71
|
"ora": "^8.2.0",
|
|
72
72
|
"shiki": "^1.6.4",
|
|
73
73
|
"srvx": "^0.8.7",
|
|
74
|
-
"@fedify/fedify": "2.0.0-pr.
|
|
75
|
-
"@fedify/sqlite": "2.0.0-pr.
|
|
76
|
-
"@fedify/vocab-runtime": "2.0.0-pr.
|
|
77
|
-
"@fedify/vocab-tools": "2.0.0-pr.
|
|
74
|
+
"@fedify/fedify": "2.0.0-pr.467.1877+dc12636d",
|
|
75
|
+
"@fedify/sqlite": "2.0.0-pr.467.1877+dc12636d",
|
|
76
|
+
"@fedify/vocab-runtime": "2.0.0-pr.467.1877+dc12636d",
|
|
77
|
+
"@fedify/vocab-tools": "2.0.0-pr.467.1877+dc12636d"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@types/bun": "^1.2.23",
|
|
81
81
|
"@types/node": "^22.17.0",
|
|
82
82
|
"tsdown": "^0.12.9",
|
|
83
|
-
"typescript": "^5.9.
|
|
83
|
+
"typescript": "^5.9.3"
|
|
84
84
|
},
|
|
85
85
|
"scripts": {
|
|
86
86
|
"codegen": "deno task -f @fedify/fedify codegen",
|
package/scripts/pack.ts
CHANGED
|
@@ -24,7 +24,9 @@ async function compile(os: OS, arch: Arch, into: string): Promise<void> {
|
|
|
24
24
|
if (!target) {
|
|
25
25
|
throw new Error(`Unsupported os/arch: ${os}/${arch}`);
|
|
26
26
|
}
|
|
27
|
-
await $`deno compile --allow-all --
|
|
27
|
+
await $`deno compile --allow-all --include=${
|
|
28
|
+
join("src", "init", "templates")
|
|
29
|
+
} --target=${target} --output=${into} ${
|
|
28
30
|
join(dirname(import.meta.dirname!), "src", "mod.ts")
|
|
29
31
|
}`;
|
|
30
32
|
}
|
|
@@ -51,10 +53,15 @@ async function pack(os: OS, arch: Arch): Promise<void> {
|
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
const osFilter = Deno.env.get("OS")?.toLowerCase();
|
|
57
|
+
const archFilter = Deno.env.get("ARCH")?.toLowerCase();
|
|
58
|
+
|
|
54
59
|
const promises: Promise<void>[] = [];
|
|
55
60
|
for (const osKey in triplets) {
|
|
56
61
|
const os = osKey as OS;
|
|
62
|
+
if (osFilter != null && osFilter !== os) continue;
|
|
57
63
|
for (const arch in triplets[os]) {
|
|
64
|
+
if (archFilter != null && archFilter !== arch) continue;
|
|
58
65
|
const promise = pack(os, arch as Arch);
|
|
59
66
|
promises.push(promise);
|
|
60
67
|
}
|
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
+
argument,
|
|
2
3
|
command,
|
|
3
4
|
constant,
|
|
4
5
|
type InferValue,
|
|
5
6
|
message,
|
|
6
7
|
object,
|
|
7
8
|
option,
|
|
9
|
+
withDefault,
|
|
8
10
|
} from "@optique/core";
|
|
9
11
|
import { path } from "@optique/run";
|
|
10
12
|
|
|
11
|
-
const schemaDir =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const schemaDir = withDefault(
|
|
14
|
+
option(
|
|
15
|
+
"-i",
|
|
16
|
+
"--input",
|
|
17
|
+
path({ metavar: "DIR", type: "directory", mustExist: true }),
|
|
18
|
+
{ description: message`Directory containing schema files.` },
|
|
19
|
+
),
|
|
20
|
+
".",
|
|
15
21
|
);
|
|
16
|
-
const generatedPath =
|
|
17
|
-
"-o",
|
|
18
|
-
"--output",
|
|
22
|
+
const generatedPath = argument(
|
|
19
23
|
path({ metavar: "PATH", type: "file", allowCreate: true }),
|
|
24
|
+
{
|
|
25
|
+
description:
|
|
26
|
+
message`Path to output the generated vocabulary classes. Should end with ${".ts"} suffix.`,
|
|
27
|
+
},
|
|
20
28
|
);
|
|
21
29
|
|
|
22
30
|
const generateVocabCommand = command(
|
|
23
31
|
"generate-vocab",
|
|
24
|
-
object({
|
|
32
|
+
object("Generation options", {
|
|
25
33
|
command: constant("generate-vocab"),
|
|
26
34
|
schemaDir,
|
|
27
35
|
generatedPath,
|
package/src/inbox.tsx
CHANGED
|
@@ -79,7 +79,7 @@ export const inboxCommand = command(
|
|
|
79
79
|
multiple(
|
|
80
80
|
option("-a", "--accept-follow", string({ metavar: "URI" }), {
|
|
81
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.`,
|
|
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
83
|
}),
|
|
84
84
|
),
|
|
85
85
|
),
|
|
@@ -107,6 +107,7 @@ export const inboxCommand = command(
|
|
|
107
107
|
debugOption,
|
|
108
108
|
),
|
|
109
109
|
{
|
|
110
|
+
brief: message`Run an ephemeral ActivityPub inbox server.`,
|
|
110
111
|
description:
|
|
111
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.`,
|
|
112
113
|
},
|
package/src/init/command.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
object,
|
|
9
9
|
option,
|
|
10
10
|
optional,
|
|
11
|
+
optionNames,
|
|
11
12
|
} from "@optique/core";
|
|
12
13
|
import { path } from "@optique/run";
|
|
13
14
|
import {
|
|
@@ -16,48 +17,71 @@ import {
|
|
|
16
17
|
PACKAGE_MANAGER,
|
|
17
18
|
WEB_FRAMEWORK,
|
|
18
19
|
} from "./const.ts";
|
|
20
|
+
import { debugOption } from "../globals.ts";
|
|
19
21
|
|
|
20
|
-
const joinSep = (str: readonly string[]) => str.join(" | ");
|
|
21
22
|
const webFramework = optional(option(
|
|
22
23
|
"-w",
|
|
23
24
|
"--web-framework",
|
|
24
|
-
choice(WEB_FRAMEWORK, {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
choice(WEB_FRAMEWORK, { metavar: "WEB_FRAMEWORK" }),
|
|
26
|
+
{
|
|
27
|
+
description: message`The web framework to integrate Fedify with.`,
|
|
28
|
+
},
|
|
27
29
|
));
|
|
28
30
|
const packageManager = optional(option(
|
|
29
31
|
"-p",
|
|
30
32
|
"--package-manager",
|
|
31
|
-
choice(PACKAGE_MANAGER, {
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
choice(PACKAGE_MANAGER, { metavar: "PACKAGE_MANAGER" }),
|
|
34
|
+
{
|
|
35
|
+
description:
|
|
36
|
+
message`The package manager to use for installing dependencies.`,
|
|
37
|
+
},
|
|
34
38
|
));
|
|
35
39
|
const kvStore = optional(option(
|
|
36
40
|
"-k",
|
|
37
41
|
"--kv-store",
|
|
38
|
-
choice(KV_STORE, { metavar:
|
|
42
|
+
choice(KV_STORE, { metavar: "KV_STORE" }),
|
|
43
|
+
{
|
|
44
|
+
description:
|
|
45
|
+
message`The key-value store to use for caching and some other features.`,
|
|
46
|
+
},
|
|
39
47
|
));
|
|
40
48
|
const messageQueue = optional(option(
|
|
41
49
|
"-m",
|
|
42
50
|
"--message-queue",
|
|
43
|
-
choice(MESSAGE_QUEUE, {
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
choice(MESSAGE_QUEUE, { metavar: "MESSAGE_QUEUE" }),
|
|
52
|
+
{
|
|
53
|
+
description: message`The message queue to use for background tasks.`,
|
|
54
|
+
},
|
|
46
55
|
));
|
|
47
56
|
|
|
48
57
|
export const initCommand = command(
|
|
49
58
|
"init",
|
|
50
|
-
object({
|
|
59
|
+
object("Initialization options", {
|
|
51
60
|
command: constant("init"),
|
|
52
|
-
dir: optional(argument(path({ metavar: "
|
|
61
|
+
dir: optional(argument(path({ metavar: "DIR" }), {
|
|
62
|
+
description:
|
|
63
|
+
message`The project directory to initialize. If a specified directory does not exist, it will be created.`,
|
|
64
|
+
})),
|
|
53
65
|
webFramework,
|
|
54
66
|
packageManager,
|
|
55
67
|
kvStore,
|
|
56
68
|
messageQueue,
|
|
57
|
-
dryRun: option("-d", "--dry-run"
|
|
69
|
+
dryRun: option("-d", "--dry-run", {
|
|
70
|
+
description: message`Perform a trial run with no changes made.`,
|
|
71
|
+
}),
|
|
72
|
+
debugOption,
|
|
58
73
|
}),
|
|
59
74
|
{
|
|
60
|
-
|
|
75
|
+
brief: message`Initialize a new Fedify project directory.`,
|
|
76
|
+
description: message`Initialize a new Fedify project directory.
|
|
77
|
+
|
|
78
|
+
By default, it initializes the current directory. You can specify a different directory as an argument.
|
|
79
|
+
|
|
80
|
+
Unless you specify all options (${optionNames(["-w", "--web-framework"])}, ${
|
|
81
|
+
optionNames(["-p", "--package-manager"])
|
|
82
|
+
}, ${optionNames(["-k", "--kv-store"])}, and ${
|
|
83
|
+
optionNames(["-m", "--message-queue"])
|
|
84
|
+
}), it will prompt you to select the options interactively.`,
|
|
61
85
|
},
|
|
62
86
|
);
|
|
63
87
|
|
package/src/lookup.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
object,
|
|
29
29
|
option,
|
|
30
30
|
optional,
|
|
31
|
+
optionNames,
|
|
31
32
|
or,
|
|
32
33
|
string,
|
|
33
34
|
withDefault,
|
|
@@ -54,8 +55,9 @@ export const authorizedFetchOption = withDefault(
|
|
|
54
55
|
"--first-knock",
|
|
55
56
|
choice(["draft-cavage-http-signatures-12", "rfc9421"]),
|
|
56
57
|
{
|
|
57
|
-
description:
|
|
58
|
-
|
|
58
|
+
description: message`The first-knock spec for ${
|
|
59
|
+
optionNames(["-a", "--authorized-fetch"])
|
|
60
|
+
}. It is used for the double-knocking technique.`,
|
|
59
61
|
},
|
|
60
62
|
),
|
|
61
63
|
"draft-cavage-http-signatures-12" as const,
|
|
@@ -147,8 +149,11 @@ export const lookupCommand = command(
|
|
|
147
149
|
}),
|
|
148
150
|
),
|
|
149
151
|
{
|
|
152
|
+
brief: message`Look up Activity Streams objects.`,
|
|
150
153
|
description:
|
|
151
|
-
message`
|
|
154
|
+
message`Look up Activity Streams objects by URL or actor handle.
|
|
155
|
+
|
|
156
|
+
The arguments can be either URLs or actor handles (e.g., ${"@username@domain"}), and they can be multiple.`,
|
|
152
157
|
},
|
|
153
158
|
);
|
|
154
159
|
|
package/src/nodeinfo.ts
CHANGED
|
@@ -44,21 +44,23 @@ const nodeInfoOption = optional(
|
|
|
44
44
|
object({
|
|
45
45
|
bestEffort: optional(flag("-b", "--best-effort", {
|
|
46
46
|
description:
|
|
47
|
-
message`Parse the NodeInfo document with best effort.
|
|
47
|
+
message`Parse the NodeInfo document with best effort. If the NodeInfo document is not well-formed, the option will try to parse it as much as possible.`,
|
|
48
48
|
})),
|
|
49
49
|
noFavicon: optional(flag("--no-favicon", {
|
|
50
50
|
description: message`Disable fetching the favicon of the instance`,
|
|
51
51
|
})),
|
|
52
52
|
metadata: optional(flag("-m", "--metadata", {
|
|
53
53
|
description:
|
|
54
|
-
message`
|
|
54
|
+
message`Show the extra metadata of the NodeInfo, i.e., the metadata field of the document.`,
|
|
55
55
|
})),
|
|
56
56
|
}),
|
|
57
57
|
),
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const userAgentOption = optional(object({
|
|
61
|
-
userAgent: option("-u", "--user-agent", string()
|
|
61
|
+
userAgent: option("-u", "--user-agent", string(), {
|
|
62
|
+
description: message`The custom User-Agent header value.`,
|
|
63
|
+
}),
|
|
62
64
|
}));
|
|
63
65
|
|
|
64
66
|
export const nodeInfoCommand = Command(
|
|
@@ -66,7 +68,7 @@ export const nodeInfoCommand = Command(
|
|
|
66
68
|
merge(
|
|
67
69
|
object({
|
|
68
70
|
command: constant("nodeinfo"),
|
|
69
|
-
host: argument(string({ metavar: "
|
|
71
|
+
host: argument(string({ metavar: "HOST" }), {
|
|
70
72
|
description: message`Bare hostname or a full URL of the instance`,
|
|
71
73
|
}),
|
|
72
74
|
}),
|
|
@@ -75,8 +77,12 @@ export const nodeInfoCommand = Command(
|
|
|
75
77
|
userAgentOption,
|
|
76
78
|
),
|
|
77
79
|
{
|
|
80
|
+
brief:
|
|
81
|
+
message`Get information about a remote node using the NodeInfo protocol`,
|
|
78
82
|
description:
|
|
79
|
-
message`Get information about a remote node using the NodeInfo protocol.
|
|
83
|
+
message`Get information about a remote node using the NodeInfo protocol.
|
|
84
|
+
|
|
85
|
+
The argument is the hostname of the remote node, or the URL of the remote node.`,
|
|
80
86
|
},
|
|
81
87
|
);
|
|
82
88
|
|
package/src/tunnel.ts
CHANGED
|
@@ -32,18 +32,22 @@ export const tunnelCommand = command(
|
|
|
32
32
|
option(
|
|
33
33
|
"-s",
|
|
34
34
|
"--service",
|
|
35
|
-
choice(["localhost.run", "serveo.net", "pinggy.io"]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
35
|
+
choice(["localhost.run", "serveo.net", "pinggy.io"], {
|
|
36
|
+
metavar: "SERVICE",
|
|
37
|
+
}),
|
|
38
|
+
{ description: message`The tunneling service to use.` },
|
|
39
39
|
),
|
|
40
40
|
),
|
|
41
41
|
}),
|
|
42
42
|
debugOption,
|
|
43
43
|
),
|
|
44
44
|
{
|
|
45
|
+
brief:
|
|
46
|
+
message`Expose a local HTTP server to the public internet using a secure tunnel.`,
|
|
45
47
|
description:
|
|
46
|
-
message`Expose a local HTTP server to the public internet using a secure tunnel
|
|
48
|
+
message`Expose a local HTTP server to the public internet using a secure tunnel.
|
|
49
|
+
|
|
50
|
+
Note that the HTTP requests through the tunnel have X-Forwarded-* headers.`,
|
|
47
51
|
},
|
|
48
52
|
);
|
|
49
53
|
|
package/src/webfinger/command.ts
CHANGED
|
@@ -41,9 +41,12 @@ export const webFingerCommand = command(
|
|
|
41
41
|
merge(
|
|
42
42
|
object({
|
|
43
43
|
command: constant("webfinger"),
|
|
44
|
-
resources: multiple(
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
resources: multiple(
|
|
45
|
+
argument(string({ metavar: "RESOURCE" }), {
|
|
46
|
+
description: message`WebFinger resource(s) to look up.`,
|
|
47
|
+
}),
|
|
48
|
+
{ min: 1 },
|
|
49
|
+
),
|
|
47
50
|
userAgent,
|
|
48
51
|
allowPrivateAddresses,
|
|
49
52
|
maxRedirection,
|
|
@@ -51,8 +54,10 @@ export const webFingerCommand = command(
|
|
|
51
54
|
debugOption,
|
|
52
55
|
),
|
|
53
56
|
{
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
brief: message`Look up WebFinger resources.`,
|
|
58
|
+
description: message`Look up WebFinger resources.
|
|
59
|
+
|
|
60
|
+
The argument can be multiple.`,
|
|
56
61
|
},
|
|
57
62
|
);
|
|
58
63
|
|
package/tsdown.config.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { cp } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
1
3
|
import { defineConfig } from "tsdown";
|
|
2
4
|
|
|
3
5
|
export default defineConfig({
|
|
@@ -21,4 +23,13 @@ export default defineConfig({
|
|
|
21
23
|
`;
|
|
22
24
|
return outputOptions;
|
|
23
25
|
},
|
|
26
|
+
hooks: {
|
|
27
|
+
"build:done": async (ctx) => {
|
|
28
|
+
await cp(
|
|
29
|
+
join("src", "init", "templates"),
|
|
30
|
+
join(ctx.options.outDir, "init", "templates"),
|
|
31
|
+
{ recursive: true },
|
|
32
|
+
);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
24
35
|
});
|