diff --git a/app/src/cli/commands/create/npm.ts b/app/src/cli/commands/create/npm.ts index 690d891..7722e1c 100644 --- a/app/src/cli/commands/create/npm.ts +++ b/app/src/cli/commands/create/npm.ts @@ -24,6 +24,32 @@ export async function overrideJson( await writeFile(pkgPath, JSON.stringify(newPkg, null, opts?.indent || 2)); } +export async function upsertEnvFile( + kv: Record, + opts?: { dir?: string; file?: string }, +) { + const file = opts?.file ?? ".env"; + const envPath = path.resolve(opts?.dir ?? process.cwd(), file); + const current: Record = {}; + + try { + const values = await readFile(envPath, "utf-8"); + const lines = values.split("\n"); + for (const line of lines) { + const [key, value] = line.split("="); + if (key && value) { + current[key] = value; + } + } + } catch (e) { + await writeFile(envPath, ""); + } + + const newEnv = { ...current, ...kv }; + const lines = Object.entries(newEnv).map(([key, value]) => `${key}=${value}`); + await writeFile(envPath, lines.join("\n")); +} + export async function overridePackageJson( fn: (pkg: TPackageJson) => Promise | TPackageJson, opts?: { dir?: string }, diff --git a/app/src/cli/commands/create/templates/aws.ts b/app/src/cli/commands/create/templates/aws.ts new file mode 100644 index 0000000..e4a8b92 --- /dev/null +++ b/app/src/cli/commands/create/templates/aws.ts @@ -0,0 +1,85 @@ +import * as $p from "@clack/prompts"; +import { upsertEnvFile } from "cli/commands/create/npm"; +import { typewriter } from "cli/utils/cli"; +import c from "picocolors"; +import type { Template } from "."; +import open from "open"; + +export const aws = { + key: "aws", + title: "AWS Lambda Basic", + integration: "aws", + description: "A basic bknd AWS Lambda starter", + path: "gh:bknd-io/bknd/examples/aws-lambda", + ref: true, + setup: async (ctx) => { + await $p.stream.info( + (async function* () { + yield* typewriter("You need a running LibSQL instance for this adapter to work."); + })(), + ); + + const choice = await $p.select({ + message: "How do you want to proceed?", + options: [ + { label: "Enter instance details", value: "enter" }, + { label: "Create a new instance", value: "new" }, + ], + }); + if ($p.isCancel(choice)) { + process.exit(1); + } + + if (choice === "new") { + await $p.stream.info( + (async function* () { + yield* typewriter(c.dim("Proceed on turso.tech to create your instance.")); + })(), + ); + + await open("https://sqlite.new"); + } + + const url = await $p.text({ + message: "Enter database URL", + placeholder: "libsql://.turso.io", + validate: (v) => { + if (!v) { + return "Invalid URL"; + } + return; + }, + }); + if ($p.isCancel(url)) { + process.exit(1); + } + + const token = await $p.text({ + message: "Enter database token", + placeholder: "eyJhbGciOiJIUzI1NiIsInR...", + validate: (v) => { + if (!v) { + return ""; + } + return; + }, + }); + if ($p.isCancel(token)) { + process.exit(1); + } + + await upsertEnvFile( + { + DB_URL: url, + DB_TOKEN: token ?? "", + }, + { dir: ctx.dir }, + ); + + await $p.stream.info( + (async function* () { + yield* typewriter(`Connection details written to ${c.cyan(".env")}`); + })(), + ); + }, +} as const satisfies Template; diff --git a/app/src/cli/commands/create/templates/cloudflare.ts b/app/src/cli/commands/create/templates/cloudflare.ts index 0e4dee8..8bbc234 100644 --- a/app/src/cli/commands/create/templates/cloudflare.ts +++ b/app/src/cli/commands/create/templates/cloudflare.ts @@ -78,6 +78,12 @@ async function createD1(ctx: TemplateSetupCtx) { process.exit(1); } + await $p.stream.info( + (async function* () { + yield* typewriter("Now running wrangler to create a D1 database..."); + })(), + ); + exec(`npx wrangler d1 create ${name}`); await $p.stream.info( (async function* () {