Loading CHANGES.md +12 −0 Original line number Diff line number Diff line Loading @@ -133,6 +133,18 @@ To be released. it's terminated so that the peers can clean up data related to the temporary actor. [[#135]] - Add options for PostgreSQL drivers to `fedify init` command. - Added `postgres` value to the `-k`/`--kv-store` option of the `fedify init` command. - Added `postgres` value to the `-q`/`--message-queue` option of the `fedify init` command. - The generated project by the `fedify init` command now enables dotenv by default. - The `fedify init` command now generates *.env* file with default values. - Added more log messages using the [LogTape] library. Currently the below logger categories are used: Loading cli/import_map.g.json +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ "@fedify/fedify/x/hono": "../src/./x/hono.ts", "@hongminhee/aitertools": "jsr:@hongminhee/aitertools@^0.6.0", "@hugoalh/http-header-link": "jsr:@hugoalh/http-header-link@^1.0.2", "@logtape/logtape": "jsr:@logtape/logtape@^0.4.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.5.1", "@phensley/language-tag": "npm:@phensley/language-tag@^1.8.1", "@std/assert": "jsr:@std/assert@^0.226.0", "@std/async/delay": "jsr:@std/async@^0.224.2/delay", Loading Loading @@ -53,6 +53,7 @@ "@david/dax": "jsr:@david/dax@^0.41.0", "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.2.0", "@poppanator/http-constants": "npm:@poppanator/http-constants@^1.1.1", "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "cli-highlight": "npm:cli-highlight@^2.1.11", "hono": "jsr:@hono/hono@^4.5.9", "hono/": "jsr:/@hono/hono@^4.5.9/", Loading cli/import_map.json +2 −1 Original line number Diff line number Diff line Loading @@ -7,8 +7,9 @@ "@cross/dir": "jsr:@cross/dir@^1.1.0", "@david/dax": "jsr:@david/dax@^0.41.0", "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.2.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.4.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.5.1", "@poppanator/http-constants": "npm:@poppanator/http-constants@^1.1.1", "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "@std/fs": "jsr:@std/fs@^0.229.3", "@std/path": "jsr:@std/path@^0.225.1", "@std/semver": "jsr:@std/semver@^0.224.3", Loading cli/init.ts +144 −30 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import { colors } from "@cliffy/ansi"; import { Command, EnumType } from "@cliffy/command"; import { Select } from "@cliffy/prompt"; import { getLogger } from "@logtape/logtape"; import { stringify } from "@std/dotenv/stringify"; import { exists } from "@std/fs"; import { basename, dirname, join, normalize } from "@std/path"; import { format, greaterThan, parse } from "@std/semver"; Loading Loading @@ -175,11 +176,13 @@ Then, try look up an actor from your server: init: (projectName, runtime, pm) => ({ dependencies: runtime === "deno" ? { "@std/dotenv": "^0.225.2", "@hono/hono": "^4.5.0", "@hongminhee/x-forwarded-fetch": "^0.2.0", } as Record<string, string> : runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", hono: "^4.5.0", "@hono/node-server": "^1.12.0", tsx: "^4.17.0", Loading Loading @@ -237,6 +240,7 @@ const server = Bun.serve({ console.log("Server started at", server.url.href); ` : `\ import "@std/dotenv/load"; import { behindProxy } from "@hongminhee/x-forwarded-fetch"; import app from "./app.tsx"; import "./logging.ts"; Loading Loading @@ -268,12 +272,12 @@ Deno.serve( ? "deno run -A --watch ./src/index.ts" : runtime === "bun" ? "bun run --hot ./src/index.ts" : "tsx watch ./src/index.ts", : "dotenvx run -- tsx watch ./src/index.ts", "prod": runtime === "deno" ? "deno run -A ./src/index.ts" : runtime === "bun" ? "bun run ./src/index.ts" : "node --import tsx ./src/index.ts", : "dotenvx run -- node --import tsx ./src/index.ts", }, instruction: ` To start the server, run the following command: Loading Loading @@ -301,7 +305,12 @@ Then, try look up an actor from your server: dependencies: { express: "^4.19.2", "@fedify/express": "^0.1.3", ...(runtime === "node" ? { tsx: "^4.17.0" } : {}), ...(runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", tsx: "^4.17.0", } : {}), }, devDependencies: { "@types/express": "^4.17.21", Loading Loading @@ -350,10 +359,10 @@ app.listen(8000, () => { tasks: { "dev": runtime === "bun" ? "bun run --hot ./src/index.ts" : "tsx watch ./src/index.ts", : "dotenvx run -- tsx watch ./src/index.ts", "prod": runtime === "bun" ? "bun run ./src/index.ts" : "node --import tsx ./src/index.ts", : "dotenvx run -- node --import tsx ./src/index.ts", }, instruction: ` To start the server, run the following command: Loading Loading @@ -422,23 +431,50 @@ Then, try look up an actor from your server: }, } as const; type KvStore = "redis" | "denokv"; type KvStore = "redis" | "postgres" | "denokv"; interface KvStoreDescription { label: string; runtimes?: Runtime[]; dependencies?: Record<string, string>; imports?: Record<string, string[]>; object: string; imports?: Record<string, string | string[]>; object: string | Record<Runtime, string>; denoUnstable?: string[]; env?: Record<string, string>; } const kvStores: Record<KvStore, KvStoreDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.1.1", "npm:ioredis": "^5.4.1" }, dependencies: { "@fedify/redis": "^0.2.0-dev.10+568b0ac5", "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisKvStore"], ioredis: ["Redis"] }, object: "new RedisKvStore(new Redis())", object: { deno: 'new RedisKvStore(new Redis(Deno.env.get("REDIS_URL")))', node: "new RedisKvStore(new Redis(process.env.REDIS_URL))", bun: "new RedisKvStore(new Redis(process.env.REDIS_URL))", }, env: { REDIS_URL: "redis://localhost:6379", }, }, postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.1.0-dev.4+d5239460", "npm:postgres": "^3.4.4", }, imports: { "@fedify/postgres": ["PostgresKvStore"], postgres: "postgres" }, object: { deno: 'new PostgresKvStore(postgres(Deno.env.get("DATABASE_URL")))', node: "new PostgresKvStore(postgres(process.env.DATABASE_URL))", bun: "new PostgresKvStore(postgres(process.env.DATABASE_URL))", }, env: { DATABASE_URL: "postgres://postgres@localhost:5432/postgres", }, }, denokv: { label: "Deno KV", Loading @@ -449,23 +485,53 @@ const kvStores: Record<KvStore, KvStoreDescription> = { }, } as const; type MessageQueue = "redis" | "denokv"; type MessageQueue = "redis" | "postgres" | "denokv"; interface MessageQueueDescription { label: string; runtimes?: Runtime[]; dependencies?: Record<string, string>; imports?: Record<string, string[]>; object: string; imports?: Record<string, string | string[]>; object: string | Record<Runtime, string>; denoUnstable?: string[]; env?: Record<string, string>; } const messageQueues: Record<MessageQueue, MessageQueueDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.1.1", "npm:ioredis": "^5.4.1" }, dependencies: { "@fedify/redis": "^0.2.0-dev.10+568b0ac5", "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisMessageQueue"], ioredis: ["Redis"] }, object: "new RedisMessageQueue(() => new Redis())", object: { deno: 'new RedisMessageQueue(() => new Redis(Deno.env.get("REDIS_URL")))', node: "new RedisMessageQueue(() => new Redis(process.env.REDIS_URL))", bun: "new RedisMessageQueue(() => new Redis(process.env.REDIS_URL))", }, env: { REDIS_URL: "redis://localhost:6379", }, }, postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.1.0-dev.4+d5239460", "npm:postgres": "^3.4.4", }, imports: { "@fedify/postgres": ["PostgresMessageQueue"], postgres: "postgres", }, object: { deno: 'new PostgresMessageQueue(postgres(Deno.env.get("DATABASE_URL")))', node: "new PostgresMessageQueue(postgres(process.env.DATABASE_URL))", bun: "new PostgresMessageQueue(postgres(process.env.DATABASE_URL))", }, env: { DATABASE_URL: "postgres://postgres@localhost:5432/postgres", }, }, denokv: { label: "Deno KV", Loading Loading @@ -683,9 +749,13 @@ export const command = new Command() federationFile: "federation.ts", loggingFile: "logging.ts", dependencies: runtime === "deno" ? { "@hongminhee/x-forwarded-fetch": "^0.2.0" } ? { "@std/dotenv": "^0.225.2", "@hongminhee/x-forwarded-fetch": "^0.2.0", } : runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", "@hono/node-server": "^1.12.0", tsx: "^4.17.0", "x-forwarded-fetch": "^0.2.0", Loading Loading @@ -727,6 +797,7 @@ const server = Bun.serve({ console.log("Server started at", server.url.href); ` : `\ import "@std/dotenv/load"; import { behindProxy } from "@hongminhee/x-forwarded-fetch"; import federation from "./federation.ts"; import "./logging.ts"; Loading Loading @@ -761,12 +832,12 @@ Deno.serve( ? "deno run -A --watch ./main.ts" : runtime === "bun" ? "bun run --hot ./main.ts" : "tsx watch ./main.ts", : "dotenvx run -- tsx watch ./main.ts", "prod": runtime === "deno" ? "deno run -A ./main.ts" : runtime === "bun" ? "bun run ./main.ts" : "node --import tsx ./main.ts", : "dotenvx run -- node --import tsx ./main.ts", }, instruction: ` To start the server, run the following command: Loading Loading @@ -812,7 +883,7 @@ Then, try look up an actor from your server: imports: { "@fedify/fedify": ["InProcessMessageQueue"] }, object: "new InProcessMessageQueue()", }; const imports: Record<string, string[]> = {}; const imports: Record<string, { $: string | null; names: string[] }> = {}; for ( const [module, symbols] of [ ...Object.entries(kvStoreDesc.imports ?? {}), Loading @@ -820,17 +891,36 @@ Then, try look up an actor from your server: ] ) { if (module in imports) { if (Array.isArray(symbols)) { for (const symbol of symbols) { if (imports[module].includes(symbol)) continue; imports[module].push(symbol); if (imports[module].names.includes(symbol)) continue; imports[module].names.push(symbol); } } else if (imports[module].$ == null) { imports[module].$ = symbols; } else if (symbols !== imports[module].$) { throw new Error( "Multiple default imports from the same module; report this as a bug.", ); } } else { imports[module] = symbols; if (Array.isArray(symbols)) { imports[module] = { $: null, names: symbols }; } else { imports[module] = { $: symbols, names: [] }; } } } const importStatements = Object.entries(imports) .map(([module, symbols]) => `import { ${symbols.join(", ")} } from ${JSON.stringify(module)};` .map(( [module, { $, names }], ) => [ $ == null ? null : `import ${$} from ${JSON.stringify(module)};`, names.length > 0 ? `import { ${names.join(", ")} } from ${JSON.stringify(module)};` : null, ].filter((s) => s != null).join("\n") ) .join("\n"); const federation = `\ Loading @@ -841,8 +931,14 @@ ${importStatements} const logger = getLogger(${JSON.stringify(projectName)}); const federation = createFederation({ kv: ${kvStoreDesc.object}, queue: ${mqDesc.object}, kv: ${ typeof kvStoreDesc.object === "string" ? kvStoreDesc.object : kvStoreDesc.object[runtime] }, queue: ${ typeof mqDesc.object === "string" ? mqDesc.object : mqDesc.object[runtime] }, }); federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { Loading Loading @@ -872,9 +968,11 @@ await configure({ ], }); `; const env = { ...kvStoreDesc.env, ...mqDesc.env }; const files = { [initializer.federationFile]: federation, [initializer.loggingFile]: logging, ".env": stringify(env), ...initializer.files, }; const { prependFiles } = initializer; Loading Loading @@ -1134,6 +1232,18 @@ await configure({ ); } console.error(initializer.instruction); if (Object.keys(env).length > 0) { console.error( `Note that you probably want to edit the ${ colors.bold.blue(".env") } file. It currently contains the following values:\n`, ); for (const key in env) { const value = stringify({ _: env[key] }).substring(2); console.error(` ${colors.green.bold(key)}${colors.gray("=")}${value}`); } console.error(); } console.error(`\ Start by editing the ${colors.bold.blue(initializer.federationFile)} \ file to define your federation! Loading Loading @@ -1193,8 +1303,12 @@ async function addDependencies( const deps = Object.entries(dependencies) .map(([name, version]) => `${ runtime != "deno" && name.startsWith("npm:") ? name.substring(4) : name }@${version}` runtime !== "deno" && name.startsWith("npm:") ? name.substring(4) : name }@${ runtime !== "deno" && version.includes("+") ? version.substring(0, version.indexOf("+")) : version }` ); if (deps.length < 1) return; const cmd = new Deno.Command( Loading Loading @@ -1264,4 +1378,4 @@ function uniqueArray<T extends boolean | number | string>(a: T[]): T[] { return result; } // cSpell: ignore denoland biomejs // cSpell: ignore asynciterable bunx giget denoland biomejs dotenvx docs/cli.md +5 −2 Original line number Diff line number Diff line Loading @@ -96,8 +96,8 @@ project. It will ask you a few questions to set up the project: - Package manager (if Node.js): [npm], [pnpm], or [Yarn] - Web framework: Bare-bones, [Fresh] (if Deno), [Hono], [Express] (unless Deno), or [Nitro] (unless Deno) - Key-value store: In-memory, [Redis], or [Deno KV] (if Deno) - Message queue: In-memory, [Redis], or [Deno KV] (if Deno) - Key-value store: In-memory, [Redis], [PostgreSQL], or [Deno KV] (if Deno) - Message queue: In-memory, [Redis], [PostgreSQL], or [Deno KV] (if Deno) Alternatively, you can specify the options in the command line to skip some of interactive prompts: Loading @@ -110,6 +110,7 @@ interactive prompts: [Express]: https://expressjs.com/ [Nitro]: https://nitro.unjs.io/ [Redis]: https://redis.io/ [PostgreSQL]: https://www.postgresql.org/ [Deno KV]: https://deno.com/kv ### `-r`/`--runtime`: JavaScript runtime Loading Loading @@ -151,6 +152,7 @@ You can specify the key-value store to use by using the `-k`/`--kv-store` option. The available options are: - `redis`: [Redis] - `postgres`: [PostgreSQL] - `denokv`: [Deno KV] (if Deno) If it's omitted, the in-memory key-value store (which is for development Loading @@ -162,6 +164,7 @@ You can specify the message queue to use by using the `-q`/`--message-queue` option. The available options are: - `redis`: [Redis] - `postgres`: [PostgreSQL] - `denokv`: [Deno KV] (if Deno) If it's omitted, the in-process message queue (which is for development purpose) Loading Loading
CHANGES.md +12 −0 Original line number Diff line number Diff line Loading @@ -133,6 +133,18 @@ To be released. it's terminated so that the peers can clean up data related to the temporary actor. [[#135]] - Add options for PostgreSQL drivers to `fedify init` command. - Added `postgres` value to the `-k`/`--kv-store` option of the `fedify init` command. - Added `postgres` value to the `-q`/`--message-queue` option of the `fedify init` command. - The generated project by the `fedify init` command now enables dotenv by default. - The `fedify init` command now generates *.env* file with default values. - Added more log messages using the [LogTape] library. Currently the below logger categories are used: Loading
cli/import_map.g.json +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ "@fedify/fedify/x/hono": "../src/./x/hono.ts", "@hongminhee/aitertools": "jsr:@hongminhee/aitertools@^0.6.0", "@hugoalh/http-header-link": "jsr:@hugoalh/http-header-link@^1.0.2", "@logtape/logtape": "jsr:@logtape/logtape@^0.4.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.5.1", "@phensley/language-tag": "npm:@phensley/language-tag@^1.8.1", "@std/assert": "jsr:@std/assert@^0.226.0", "@std/async/delay": "jsr:@std/async@^0.224.2/delay", Loading Loading @@ -53,6 +53,7 @@ "@david/dax": "jsr:@david/dax@^0.41.0", "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.2.0", "@poppanator/http-constants": "npm:@poppanator/http-constants@^1.1.1", "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "cli-highlight": "npm:cli-highlight@^2.1.11", "hono": "jsr:@hono/hono@^4.5.9", "hono/": "jsr:/@hono/hono@^4.5.9/", Loading
cli/import_map.json +2 −1 Original line number Diff line number Diff line Loading @@ -7,8 +7,9 @@ "@cross/dir": "jsr:@cross/dir@^1.1.0", "@david/dax": "jsr:@david/dax@^0.41.0", "@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.2.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.4.0", "@logtape/logtape": "jsr:@logtape/logtape@^0.5.1", "@poppanator/http-constants": "npm:@poppanator/http-constants@^1.1.1", "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "@std/fs": "jsr:@std/fs@^0.229.3", "@std/path": "jsr:@std/path@^0.225.1", "@std/semver": "jsr:@std/semver@^0.224.3", Loading
cli/init.ts +144 −30 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import { colors } from "@cliffy/ansi"; import { Command, EnumType } from "@cliffy/command"; import { Select } from "@cliffy/prompt"; import { getLogger } from "@logtape/logtape"; import { stringify } from "@std/dotenv/stringify"; import { exists } from "@std/fs"; import { basename, dirname, join, normalize } from "@std/path"; import { format, greaterThan, parse } from "@std/semver"; Loading Loading @@ -175,11 +176,13 @@ Then, try look up an actor from your server: init: (projectName, runtime, pm) => ({ dependencies: runtime === "deno" ? { "@std/dotenv": "^0.225.2", "@hono/hono": "^4.5.0", "@hongminhee/x-forwarded-fetch": "^0.2.0", } as Record<string, string> : runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", hono: "^4.5.0", "@hono/node-server": "^1.12.0", tsx: "^4.17.0", Loading Loading @@ -237,6 +240,7 @@ const server = Bun.serve({ console.log("Server started at", server.url.href); ` : `\ import "@std/dotenv/load"; import { behindProxy } from "@hongminhee/x-forwarded-fetch"; import app from "./app.tsx"; import "./logging.ts"; Loading Loading @@ -268,12 +272,12 @@ Deno.serve( ? "deno run -A --watch ./src/index.ts" : runtime === "bun" ? "bun run --hot ./src/index.ts" : "tsx watch ./src/index.ts", : "dotenvx run -- tsx watch ./src/index.ts", "prod": runtime === "deno" ? "deno run -A ./src/index.ts" : runtime === "bun" ? "bun run ./src/index.ts" : "node --import tsx ./src/index.ts", : "dotenvx run -- node --import tsx ./src/index.ts", }, instruction: ` To start the server, run the following command: Loading Loading @@ -301,7 +305,12 @@ Then, try look up an actor from your server: dependencies: { express: "^4.19.2", "@fedify/express": "^0.1.3", ...(runtime === "node" ? { tsx: "^4.17.0" } : {}), ...(runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", tsx: "^4.17.0", } : {}), }, devDependencies: { "@types/express": "^4.17.21", Loading Loading @@ -350,10 +359,10 @@ app.listen(8000, () => { tasks: { "dev": runtime === "bun" ? "bun run --hot ./src/index.ts" : "tsx watch ./src/index.ts", : "dotenvx run -- tsx watch ./src/index.ts", "prod": runtime === "bun" ? "bun run ./src/index.ts" : "node --import tsx ./src/index.ts", : "dotenvx run -- node --import tsx ./src/index.ts", }, instruction: ` To start the server, run the following command: Loading Loading @@ -422,23 +431,50 @@ Then, try look up an actor from your server: }, } as const; type KvStore = "redis" | "denokv"; type KvStore = "redis" | "postgres" | "denokv"; interface KvStoreDescription { label: string; runtimes?: Runtime[]; dependencies?: Record<string, string>; imports?: Record<string, string[]>; object: string; imports?: Record<string, string | string[]>; object: string | Record<Runtime, string>; denoUnstable?: string[]; env?: Record<string, string>; } const kvStores: Record<KvStore, KvStoreDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.1.1", "npm:ioredis": "^5.4.1" }, dependencies: { "@fedify/redis": "^0.2.0-dev.10+568b0ac5", "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisKvStore"], ioredis: ["Redis"] }, object: "new RedisKvStore(new Redis())", object: { deno: 'new RedisKvStore(new Redis(Deno.env.get("REDIS_URL")))', node: "new RedisKvStore(new Redis(process.env.REDIS_URL))", bun: "new RedisKvStore(new Redis(process.env.REDIS_URL))", }, env: { REDIS_URL: "redis://localhost:6379", }, }, postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.1.0-dev.4+d5239460", "npm:postgres": "^3.4.4", }, imports: { "@fedify/postgres": ["PostgresKvStore"], postgres: "postgres" }, object: { deno: 'new PostgresKvStore(postgres(Deno.env.get("DATABASE_URL")))', node: "new PostgresKvStore(postgres(process.env.DATABASE_URL))", bun: "new PostgresKvStore(postgres(process.env.DATABASE_URL))", }, env: { DATABASE_URL: "postgres://postgres@localhost:5432/postgres", }, }, denokv: { label: "Deno KV", Loading @@ -449,23 +485,53 @@ const kvStores: Record<KvStore, KvStoreDescription> = { }, } as const; type MessageQueue = "redis" | "denokv"; type MessageQueue = "redis" | "postgres" | "denokv"; interface MessageQueueDescription { label: string; runtimes?: Runtime[]; dependencies?: Record<string, string>; imports?: Record<string, string[]>; object: string; imports?: Record<string, string | string[]>; object: string | Record<Runtime, string>; denoUnstable?: string[]; env?: Record<string, string>; } const messageQueues: Record<MessageQueue, MessageQueueDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.1.1", "npm:ioredis": "^5.4.1" }, dependencies: { "@fedify/redis": "^0.2.0-dev.10+568b0ac5", "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisMessageQueue"], ioredis: ["Redis"] }, object: "new RedisMessageQueue(() => new Redis())", object: { deno: 'new RedisMessageQueue(() => new Redis(Deno.env.get("REDIS_URL")))', node: "new RedisMessageQueue(() => new Redis(process.env.REDIS_URL))", bun: "new RedisMessageQueue(() => new Redis(process.env.REDIS_URL))", }, env: { REDIS_URL: "redis://localhost:6379", }, }, postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.1.0-dev.4+d5239460", "npm:postgres": "^3.4.4", }, imports: { "@fedify/postgres": ["PostgresMessageQueue"], postgres: "postgres", }, object: { deno: 'new PostgresMessageQueue(postgres(Deno.env.get("DATABASE_URL")))', node: "new PostgresMessageQueue(postgres(process.env.DATABASE_URL))", bun: "new PostgresMessageQueue(postgres(process.env.DATABASE_URL))", }, env: { DATABASE_URL: "postgres://postgres@localhost:5432/postgres", }, }, denokv: { label: "Deno KV", Loading Loading @@ -683,9 +749,13 @@ export const command = new Command() federationFile: "federation.ts", loggingFile: "logging.ts", dependencies: runtime === "deno" ? { "@hongminhee/x-forwarded-fetch": "^0.2.0" } ? { "@std/dotenv": "^0.225.2", "@hongminhee/x-forwarded-fetch": "^0.2.0", } : runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", "@hono/node-server": "^1.12.0", tsx: "^4.17.0", "x-forwarded-fetch": "^0.2.0", Loading Loading @@ -727,6 +797,7 @@ const server = Bun.serve({ console.log("Server started at", server.url.href); ` : `\ import "@std/dotenv/load"; import { behindProxy } from "@hongminhee/x-forwarded-fetch"; import federation from "./federation.ts"; import "./logging.ts"; Loading Loading @@ -761,12 +832,12 @@ Deno.serve( ? "deno run -A --watch ./main.ts" : runtime === "bun" ? "bun run --hot ./main.ts" : "tsx watch ./main.ts", : "dotenvx run -- tsx watch ./main.ts", "prod": runtime === "deno" ? "deno run -A ./main.ts" : runtime === "bun" ? "bun run ./main.ts" : "node --import tsx ./main.ts", : "dotenvx run -- node --import tsx ./main.ts", }, instruction: ` To start the server, run the following command: Loading Loading @@ -812,7 +883,7 @@ Then, try look up an actor from your server: imports: { "@fedify/fedify": ["InProcessMessageQueue"] }, object: "new InProcessMessageQueue()", }; const imports: Record<string, string[]> = {}; const imports: Record<string, { $: string | null; names: string[] }> = {}; for ( const [module, symbols] of [ ...Object.entries(kvStoreDesc.imports ?? {}), Loading @@ -820,17 +891,36 @@ Then, try look up an actor from your server: ] ) { if (module in imports) { if (Array.isArray(symbols)) { for (const symbol of symbols) { if (imports[module].includes(symbol)) continue; imports[module].push(symbol); if (imports[module].names.includes(symbol)) continue; imports[module].names.push(symbol); } } else if (imports[module].$ == null) { imports[module].$ = symbols; } else if (symbols !== imports[module].$) { throw new Error( "Multiple default imports from the same module; report this as a bug.", ); } } else { imports[module] = symbols; if (Array.isArray(symbols)) { imports[module] = { $: null, names: symbols }; } else { imports[module] = { $: symbols, names: [] }; } } } const importStatements = Object.entries(imports) .map(([module, symbols]) => `import { ${symbols.join(", ")} } from ${JSON.stringify(module)};` .map(( [module, { $, names }], ) => [ $ == null ? null : `import ${$} from ${JSON.stringify(module)};`, names.length > 0 ? `import { ${names.join(", ")} } from ${JSON.stringify(module)};` : null, ].filter((s) => s != null).join("\n") ) .join("\n"); const federation = `\ Loading @@ -841,8 +931,14 @@ ${importStatements} const logger = getLogger(${JSON.stringify(projectName)}); const federation = createFederation({ kv: ${kvStoreDesc.object}, queue: ${mqDesc.object}, kv: ${ typeof kvStoreDesc.object === "string" ? kvStoreDesc.object : kvStoreDesc.object[runtime] }, queue: ${ typeof mqDesc.object === "string" ? mqDesc.object : mqDesc.object[runtime] }, }); federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { Loading Loading @@ -872,9 +968,11 @@ await configure({ ], }); `; const env = { ...kvStoreDesc.env, ...mqDesc.env }; const files = { [initializer.federationFile]: federation, [initializer.loggingFile]: logging, ".env": stringify(env), ...initializer.files, }; const { prependFiles } = initializer; Loading Loading @@ -1134,6 +1232,18 @@ await configure({ ); } console.error(initializer.instruction); if (Object.keys(env).length > 0) { console.error( `Note that you probably want to edit the ${ colors.bold.blue(".env") } file. It currently contains the following values:\n`, ); for (const key in env) { const value = stringify({ _: env[key] }).substring(2); console.error(` ${colors.green.bold(key)}${colors.gray("=")}${value}`); } console.error(); } console.error(`\ Start by editing the ${colors.bold.blue(initializer.federationFile)} \ file to define your federation! Loading Loading @@ -1193,8 +1303,12 @@ async function addDependencies( const deps = Object.entries(dependencies) .map(([name, version]) => `${ runtime != "deno" && name.startsWith("npm:") ? name.substring(4) : name }@${version}` runtime !== "deno" && name.startsWith("npm:") ? name.substring(4) : name }@${ runtime !== "deno" && version.includes("+") ? version.substring(0, version.indexOf("+")) : version }` ); if (deps.length < 1) return; const cmd = new Deno.Command( Loading Loading @@ -1264,4 +1378,4 @@ function uniqueArray<T extends boolean | number | string>(a: T[]): T[] { return result; } // cSpell: ignore denoland biomejs // cSpell: ignore asynciterable bunx giget denoland biomejs dotenvx
docs/cli.md +5 −2 Original line number Diff line number Diff line Loading @@ -96,8 +96,8 @@ project. It will ask you a few questions to set up the project: - Package manager (if Node.js): [npm], [pnpm], or [Yarn] - Web framework: Bare-bones, [Fresh] (if Deno), [Hono], [Express] (unless Deno), or [Nitro] (unless Deno) - Key-value store: In-memory, [Redis], or [Deno KV] (if Deno) - Message queue: In-memory, [Redis], or [Deno KV] (if Deno) - Key-value store: In-memory, [Redis], [PostgreSQL], or [Deno KV] (if Deno) - Message queue: In-memory, [Redis], [PostgreSQL], or [Deno KV] (if Deno) Alternatively, you can specify the options in the command line to skip some of interactive prompts: Loading @@ -110,6 +110,7 @@ interactive prompts: [Express]: https://expressjs.com/ [Nitro]: https://nitro.unjs.io/ [Redis]: https://redis.io/ [PostgreSQL]: https://www.postgresql.org/ [Deno KV]: https://deno.com/kv ### `-r`/`--runtime`: JavaScript runtime Loading Loading @@ -151,6 +152,7 @@ You can specify the key-value store to use by using the `-k`/`--kv-store` option. The available options are: - `redis`: [Redis] - `postgres`: [PostgreSQL] - `denokv`: [Deno KV] (if Deno) If it's omitted, the in-memory key-value store (which is for development Loading @@ -162,6 +164,7 @@ You can specify the message queue to use by using the `-q`/`--message-queue` option. The available options are: - `redis`: [Redis] - `postgres`: [PostgreSQL] - `denokv`: [Deno KV] (if Deno) If it's omitted, the in-process message queue (which is for development purpose) Loading