Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ Released on March 19, 2026.
repository-relative path logic has been made safe for published JSR
execution. [[#624], [#633]]

- Revived removed `fedify init` options. [[#632], [#638] by ChanHaeng Lee]
- `bare-bones` option for web framework.
- `in-memory` option for key-value store.
- `in-process` option for message queue.

[#624]: https://github.com/fedify-dev/fedify/issues/624
[#632]: https://github.com/fedify-dev/fedify/issues/632
[#633]: https://github.com/fedify-dev/fedify/pull/633
[#638]: https://github.com/fedify-dev/fedify/pull/638

### @fedify/vocab-runtime

Expand Down
15 changes: 12 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: >-
features of the fedify command.
---

<!-- deno-fmt-ignore-file -->

`fedify`: CLI toolchain
=======================

Expand Down Expand Up @@ -222,11 +224,12 @@ fedify init my-fedify-project
The above command will start the interactive prompt to initialize a new Fedify
project. It will ask you a few questions to set up the project:

- Web framework: [Hono], [Elysia], [Express], [Nitro], or [Next.js]
- Web framework: Bare-bones, [Hono], [Elysia], [Express], [Nitro],
or [Next.js]
- Package manager: [Deno], [Bun], [npm], [pnpm], or [Yarn]
- Message queue: [Redis], [PostgreSQL], [AMQP] (e.g., [RabbitMQ]),
- Message queue: In-Process, [Redis], [PostgreSQL], [AMQP] (e.g., [RabbitMQ]),
or [Deno KV] (if Deno)
- Key–value store: [Redis], [PostgreSQL], or [Deno KV] (if Deno)
- Key–value store: In-Memory, [Redis], [PostgreSQL], or [Deno KV] (if Deno)

> [!TIP]
> Projects created with `fedify init` automatically include [`@fedify/lint`]
Expand Down Expand Up @@ -276,6 +279,8 @@ option. The available options are:
You can specify the web framework to integrate with Fedify by using
the `-w`/`--web-framework` option. The available options are:

- `bare-bones`: A minimal setup without any web framework integration, but in
Node.js, [Hono] is used for a simple adapter for a lightweight experience.
- `hono`: [Hono]
- `nitro`: [Nitro]
- `next`: [Next.js]
Expand All @@ -287,6 +292,8 @@ the `-w`/`--web-framework` option. The available options are:
You can specify the key–value store to use by using the `-k`/`--kv-store`
option. The available options are:

- `in-memory`: An in-memory key–value store that does not persist data across
restarts. This is useful for testing and development purposes.
- `redis`: [Redis]
- `postgres`: [PostgreSQL]
- `denokv`: [Deno KV] (if Deno)
Expand All @@ -296,6 +303,8 @@ option. The available options are:
You can specify the message queue to use by using the `-m`/`--message-queue`
option. The available options are:

- `in-process`: An in-process message queue that does not persist messages
across restarts. This is useful for testing and development purposes.
- `redis`: [Redis]
- `postgres`: [PostgreSQL]
- `amqp`: [AMQP] (e.g., [RabbitMQ])
Expand Down
6 changes: 3 additions & 3 deletions packages/init/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ Supported options

The initializer supports the following project configurations:

- **Web frameworks**: [Hono], [Nitro], [Next.js], [Elysia], [Express]
- **Web frameworks**: Bare-bones, [Hono], [Nitro], [Next.js], [Elysia], [Express]
- **Package managers**: Deno, pnpm, Bun, Yarn, npm
- **Key-value stores**: Deno KV, Redis, PostgreSQL
- **Message queues**: Deno KV, Redis, PostgreSQL, AMQP
- **Key-value stores**: In-Memory, Deno KV, Redis, PostgreSQL
- **Message queues**: In-Process, Deno KV, Redis, PostgreSQL, AMQP

[Hono]: https://hono.dev/
[Nitro]: https://nitro.build/
Expand Down
14 changes: 12 additions & 2 deletions packages/init/src/const.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import kv from "./json/kv.json" with { type: "json" };
import mq from "./json/mq.json" with { type: "json" };

/** All supported package manager identifiers, in display order. */
export const PACKAGE_MANAGER = ["deno", "pnpm", "bun", "yarn", "npm"] as const;
export const WEB_FRAMEWORK = [
"bare-bones",
"hono",
"nitro",
"next",
"elysia",
"express",
] as const;
export const MESSAGE_QUEUE = ["denokv", "redis", "postgres", "amqp"] as const;
export const KV_STORE = ["denokv", "redis", "postgres"] as const;

/** All supported message queue backend identifiers. */
export const MESSAGE_QUEUE = Object.keys(mq) as readonly (keyof typeof mq)[];

/** All supported key-value store backend identifiers. */
export const KV_STORE = Object.keys(kv) as readonly (keyof typeof kv)[];

export const DB_TO_CHECK = ["redis", "postgres", "amqp"] as const;
8 changes: 8 additions & 0 deletions packages/init/src/json/kv.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"in-memory": {
"label": "In-Memory",
"packageManagers": ["deno", "bun", "npm", "yarn", "pnpm"],
"imports": {
"@fedify/fedify": { "MemoryKvStore": "MemoryKvStore" }
},
"object": "new MemoryKvStore()"
},
"redis": {
"label": "Redis",
"packageManagers": ["deno", "bun", "npm", "yarn", "pnpm"],
Expand Down
16 changes: 16 additions & 0 deletions packages/init/src/json/mq.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
{
"in-process": {
"label": "In-Process",
"packageManagers": [
"deno",
"bun",
"npm",
"yarn",
"pnpm"
],
"imports": {
"@fedify/fedify": {
"InProcessMessageQueue": "InProcessMessageQueue"
}
},
"object": "new InProcessMessageQueue()"
},
"redis": {
"label": "Redis",
"packageManagers": [
Expand Down
6 changes: 5 additions & 1 deletion packages/init/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,15 @@ const addFedifyDeps = <T extends object>(json: T): T =>
key,
toMerged(value, {
dependencies: {
[`@fedify/${key}`]: PACKAGE_VERSION,
...(NO_INTEGRATIONS.includes(key) ? {} : {
[`@fedify/${key}`]: PACKAGE_VERSION,
}),
},
}),
]),
) as T;
const NO_INTEGRATIONS = ["in-memory", "in-process", "bare-bones"];

export const kvStores = addFedifyDeps(kv as KvStores);
export const messageQueues = addFedifyDeps(mq as MessageQueues);
const toRegExp = (str: string): RegExp => new RegExp(str);
Expand Down
16 changes: 16 additions & 0 deletions packages/init/src/templates/bare-bones/main/bun.ts.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { behindProxy } from "x-forwarded-fetch";
import federation from "./federation.ts";
import "./logging.ts";

const server = Bun.serve({
port: 8000,
fetch: behindProxy((req) =>
new URL(req.url).pathname === "/"
? new Response("Hello, this is a Fedify server!", {
headers: { "Content-Type": "text/plain" },
})
: federation.fetch(req, { contextData: undefined })
),
});

console.log("Server started at", server.url.href);
19 changes: 19 additions & 0 deletions packages/init/src/templates/bare-bones/main/deno.ts.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import "@std/dotenv/load";
import { behindProxy } from "@hongminhee/x-forwarded-fetch";
import federation from "./federation.ts";
import "./logging.ts";

Deno.serve(
{
port: 8000,
onListen: ({ port, hostname }) =>
console.log("Server started at http://" + hostname + ":" + port)
},
behindProxy((req) =>
new URL(req.url).pathname === "/"
? new Response("Hello, this is a Fedify server!", {
headers: { "Content-Type": "text/plain" },
})
: federation.fetch(req, { contextData: undefined })
),
);
19 changes: 19 additions & 0 deletions packages/init/src/templates/bare-bones/main/node.ts.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { serve } from "@hono/node-server";
import { behindProxy } from "x-forwarded-fetch";
import federation from "./federation.ts";
import "./logging.ts";

serve(
{
port: 8000,
fetch: behindProxy((req) =>
new URL(req.url).pathname === "/"
? new Response("Hello, this is a Fedify server!", {
headers: { "Content-Type": "text/plain" },
})
: federation.fetch(req, { contextData: undefined })
),
},
(info) =>
console.log("Server started at http://" + info.address + ":" + info.port)
);
10 changes: 8 additions & 2 deletions packages/init/src/test/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { createWriteStream } from "node:fs";
import { join, sep } from "node:path";
import process from "node:process";
import type Stream from "node:stream";
import { printErrorMessage, printMessage, runSubCommand } from "../utils.ts";
import { getDevCommand } from "../lib.ts";
import type {
KvStore,
MessageQueue,
PackageManager,
WebFramework,
} from "../types.ts";
import { printErrorMessage, printMessage, runSubCommand } from "../utils.ts";
import webFrameworks from "../webframeworks.ts";

const HANDLE = "john";
Expand Down Expand Up @@ -80,6 +80,7 @@ async function testApp(dir: string): Promise<boolean> {
const result = await serverClosure(
dir,
getDevCommand(pm),
webFrameworks[wf].defaultPort,
sendLookup,
);

Expand Down Expand Up @@ -154,6 +155,7 @@ async function waitForServer(url: string, timeout: number): Promise<boolean> {
async function serverClosure<T>(
dir: string,
cmd: string,
defaultPort: number,
callback: (port: number) => Promise<T>,
): Promise<Awaited<T>> {
// Start the dev server using Node.js spawn
Expand All @@ -172,7 +174,11 @@ async function serverClosure<T>(
serverProcess.stderr?.pipe(stderr);

try {
const port = await determinePort(serverProcess);
const port = await determinePort(serverProcess).catch((err) => {
printErrorMessage`Failed to determine server port: ${err.message}`;
printErrorMessage`Use default port ${String(defaultPort)} for lookup.`;
return defaultPort;
});
return await callback(port);
} finally {
try {
Expand Down
67 changes: 67 additions & 0 deletions packages/init/src/webframeworks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,73 @@ import type { WebFrameworks } from "./types.ts";
import { replace } from "./utils.ts";

const webFrameworks: WebFrameworks = {
"bare-bones": {
label: "Bare-bones",
packageManagers: PACKAGE_MANAGER,
defaultPort: 8000,
init: async ({ packageManager: pm }) => ({
dependencies: pm === "deno"
? {
...defaultDenoDependencies,
"@std/dotenv": "^0.225.2",
"@hongminhee/x-forwarded-fetch": "^0.2.0",
}
: pm === "bun"
? { "npm:x-forwarded-fetch": "^0.2.0" }
: {
"npm:@dotenvx/dotenvx": "^1.14.1",
"npm:@hono/node-server": "^1.12.0",
"npm:tsx": "^4.17.0",
"npm:x-forwarded-fetch": "^0.2.0",
},
devDependencies: {
...defaultDevDependencies,
...(pm === "bun"
? { "@types/bun": "^1.1.6" }
: { "@types/node": "^18.0.0" }),
},
federationFile: "src/federation.ts",
loggingFile: "src/logging.ts",
files: {
"src/main.ts": await readTemplate(
`bare-bones/main/${packageManagerToRuntime(pm)}.ts`,
),
...(pm !== "deno"
? {
"eslint.config.ts": await readTemplate("defaults/eslint.config.ts"),
}
: {}),
},
compilerOptions: (pm === "deno"
? {
"jsx": "precompile",
"jsxImportSource": "hono/jsx",
}
: {
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"strict": true,
}) as Record<string, string | boolean | number | string[] | null>,
tasks: {
"dev": pm === "deno"
? "deno run -A --watch ./src/main.ts"
: pm === "bun"
? "bun run --hot ./src/main.ts"
: "dotenvx run -- tsx watch ./src/main.ts",
"prod": pm === "deno"
? "deno run -A ./src/main.ts"
: pm === "bun"
? "bun run ./src/main.ts"
: "dotenvx run -- node --import tsx ./src/main.ts",
},
instruction: getInstruction(pm, 8000),
}),
},
hono: {
label: "Hono",
packageManagers: PACKAGE_MANAGER,
Expand Down
Loading