diff --git a/pkgs/api/_deploy.ts b/pkgs/api/_deploy.ts index 3703d7a..b985ac3 100644 --- a/pkgs/api/_deploy.ts +++ b/pkgs/api/_deploy.ts @@ -1,10 +1,11 @@ import { $ } from "execa"; import * as fs from "fs"; -import { dirAsync, removeAsync, writeAsync } from "fs-jetpack"; +import { dirAsync, readAsync, removeAsync, writeAsync } from "fs-jetpack"; import { apiContext } from "service-srv"; import { deploy } from "utils/deploy"; import { dir } from "utils/dir"; import { g } from "utils/global"; +import { parse } from "utils/parse-env"; import { restartServer } from "utils/restart"; export const _ = { @@ -55,30 +56,39 @@ DATABASE_URL="${action.url}" return "ok"; case "db-pull": { - await writeAsync( - dir("app/db/prisma/schema.prisma"), - `\ -generator client { - provider = "prisma-client-js" -} + const env = await readAsync(dir("app/db/.env")); + if (env) { + const ENV = parse(env); + if (typeof ENV.DATABASE_URL === "string") { + const type = ENV.DATABASE_URL.split("://").shift(); + if (type) { + await writeAsync( + dir("app/db/prisma/schema.prisma"), + `\ + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "${type}" + url = env("DATABASE_URL") + }` + ); -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -}` - ); - - try { - await $({ cwd: dir("app/db") })`bun install`; - await $({ cwd: dir("app/db") })`bun prisma db pull --force`; - await $({ cwd: dir("app/db") })`bun prisma generate`; - } catch (e) { - console.error(e); + try { + await $({ cwd: dir("app/db") })`bun install`; + await $({ cwd: dir("app/db") })`bun prisma db pull --force`; + await $({ cwd: dir("app/db") })`bun prisma generate`; + } catch (e) { + console.error(e); + } + res.send("ok"); + setTimeout(() => { + restartServer(); + }, 300); + } + } } - res.send("ok"); - setTimeout(() => { - restartServer(); - }, 300); } break; case "restart": diff --git a/pkgs/server/create.ts b/pkgs/server/create.ts index a9c2dca..fd24d33 100644 --- a/pkgs/server/create.ts +++ b/pkgs/server/create.ts @@ -72,13 +72,12 @@ export const createServer = async () => { } } - await g.deploy.server?.init?.(); - g.server = Bun.serve({ port: g.port, maxRequestBodySize: 1024 * 1024 * 128, async fetch(req) { const url = new URL(req.url) as URL; + const prasi = {}; const handle = async (req: Request) => { const api = await serveAPI(url, req); @@ -146,6 +145,7 @@ export const createServer = async () => { server: g.server, url: { pathname: url.pathname, raw: url }, index: g.deploy.index, + prasi, }); } catch (e) { console.error(e); @@ -163,3 +163,5 @@ export const createServer = async () => { g.log.info(`Started at port: ${g.server.port}`); } }; + +await g.deploy.server?.init?.({ port: g.server.port }); diff --git a/pkgs/utils/global.ts b/pkgs/utils/global.ts index 4c8655a..8452bae 100644 --- a/pkgs/utils/global.ts +++ b/pkgs/utils/global.ts @@ -32,6 +32,7 @@ type PrasiServer = { mode: "dev" | "prod"; handle: (req: Request) => Promise; index: { head: string[]; body: string[]; render: () => string }; + prasi: { page_id?: string }; }) => Promise; init?: (arg: { port: number }) => Promise; }; diff --git a/pkgs/utils/parse-env.ts b/pkgs/utils/parse-env.ts new file mode 100644 index 0000000..a03ed2f --- /dev/null +++ b/pkgs/utils/parse-env.ts @@ -0,0 +1,66 @@ +/** We don't normalize anything, so it is just strings and strings. */ +export type Data = Record; + +/** We typecast the value as a string so that it is compatible with envfiles. */ +export type Input = Record; + +// perhaps in the future we can use @bevry/json's toJSON and parseJSON and JSON.stringify to support more advanced types + +function removeQuotes(str: string) { + // Check if the string starts and ends with single or double quotes + if ( + (str.startsWith('"') && str.endsWith('"')) || + (str.startsWith("'") && str.endsWith("'")) + ) { + // Remove the quotes + return str.slice(1, -1); + } + // If the string is not wrapped in quotes, return it as is + return str; +} + +/** Parse an envfile string. */ +export function parse(src: string): Data { + const result: Data = {}; + const lines = splitInLines(src); + for (const line of lines) { + const match = line.match(/^([^=:#]+?)[=:]((.|\n)*)/); + if (match) { + const key = match[1].trim(); + const value = removeQuotes(match[2].trim()); + result[key] = value; + } + } + return result; +} + +/** Turn an object into an envfile string. */ +export function stringify(obj: Input): string { + let result = ""; + for (const [key, value] of Object.entries(obj)) { + if (key) { + const line = `${key}=${jsonValueToEnv(value)}`; + result += line + "\n"; + } + } + return result; +} + +function splitInLines(src: string): string[] { + return src + .replace(/("[\s\S]*?")/g, (_m, cg) => { + return cg.replace(/\n/g, "%%LINE-BREAK%%"); + }) + .split("\n") + .filter((i) => Boolean(i.trim())) + .map((i) => i.replace(/%%LINE-BREAK%%/g, "\n")); +} + +function jsonValueToEnv(value: any): string { + let processedValue = String(value); + processedValue = processedValue.replace(/\n/g, "\\n"); + processedValue = processedValue.includes("\\n") + ? `"${processedValue}"` + : processedValue; + return processedValue; +}