This commit is contained in:
Rizky 2024-04-25 15:32:14 +07:00
parent 9771281430
commit 98333a82a8
4 changed files with 104 additions and 25 deletions

View File

@ -1,10 +1,11 @@
import { $ } from "execa"; import { $ } from "execa";
import * as fs from "fs"; 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 { apiContext } from "service-srv";
import { deploy } from "utils/deploy"; import { deploy } from "utils/deploy";
import { dir } from "utils/dir"; import { dir } from "utils/dir";
import { g } from "utils/global"; import { g } from "utils/global";
import { parse } from "utils/parse-env";
import { restartServer } from "utils/restart"; import { restartServer } from "utils/restart";
export const _ = { export const _ = {
@ -55,30 +56,39 @@ DATABASE_URL="${action.url}"
return "ok"; return "ok";
case "db-pull": case "db-pull":
{ {
await writeAsync( const env = await readAsync(dir("app/db/.env"));
dir("app/db/prisma/schema.prisma"), if (env) {
`\ const ENV = parse(env);
generator client { if (typeof ENV.DATABASE_URL === "string") {
provider = "prisma-client-js" 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 { try {
provider = "postgresql" await $({ cwd: dir("app/db") })`bun install`;
url = env("DATABASE_URL") 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`; res.send("ok");
await $({ cwd: dir("app/db") })`bun prisma db pull --force`; setTimeout(() => {
await $({ cwd: dir("app/db") })`bun prisma generate`; restartServer();
} catch (e) { }, 300);
console.error(e); }
}
} }
res.send("ok");
setTimeout(() => {
restartServer();
}, 300);
} }
break; break;
case "restart": case "restart":

View File

@ -72,13 +72,12 @@ export const createServer = async () => {
} }
} }
await g.deploy.server?.init?.();
g.server = Bun.serve({ g.server = Bun.serve({
port: g.port, port: g.port,
maxRequestBodySize: 1024 * 1024 * 128, maxRequestBodySize: 1024 * 1024 * 128,
async fetch(req) { async fetch(req) {
const url = new URL(req.url) as URL; const url = new URL(req.url) as URL;
const prasi = {};
const handle = async (req: Request) => { const handle = async (req: Request) => {
const api = await serveAPI(url, req); const api = await serveAPI(url, req);
@ -146,6 +145,7 @@ export const createServer = async () => {
server: g.server, server: g.server,
url: { pathname: url.pathname, raw: url }, url: { pathname: url.pathname, raw: url },
index: g.deploy.index, index: g.deploy.index,
prasi,
}); });
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -163,3 +163,5 @@ export const createServer = async () => {
g.log.info(`Started at port: ${g.server.port}`); g.log.info(`Started at port: ${g.server.port}`);
} }
}; };
await g.deploy.server?.init?.({ port: g.server.port });

View File

@ -32,6 +32,7 @@ type PrasiServer = {
mode: "dev" | "prod"; mode: "dev" | "prod";
handle: (req: Request) => Promise<Response>; handle: (req: Request) => Promise<Response>;
index: { head: string[]; body: string[]; render: () => string }; index: { head: string[]; body: string[]; render: () => string };
prasi: { page_id?: string };
}) => Promise<Response>; }) => Promise<Response>;
init?: (arg: { port: number }) => Promise<void>; init?: (arg: { port: number }) => Promise<void>;
}; };

66
pkgs/utils/parse-env.ts Normal file
View File

@ -0,0 +1,66 @@
/** We don't normalize anything, so it is just strings and strings. */
export type Data = Record<string, string>;
/** We typecast the value as a string so that it is compatible with envfiles. */
export type Input = Record<string, any>;
// 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;
}