wip fix
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { dirAsync, readAsync } from "fs-jetpack";
|
||||
import { dir } from "./dir";
|
||||
import { g } from "./global";
|
||||
|
||||
const _internal = { config: {} as any, writeTimeout: null as any };
|
||||
|
||||
export const config = {
|
||||
init: async () => {
|
||||
await dirAsync(dir(`${g.datadir}/config`));
|
||||
await dirAsync(dir(`${g.datadir}/files`));
|
||||
|
||||
_internal.config =
|
||||
(await readAsync(dir(`${g.datadir}/config/conf.json`), "json")) || {};
|
||||
},
|
||||
get all() {
|
||||
return _internal.config;
|
||||
},
|
||||
get(key: string) {
|
||||
if (key.endsWith("url")) {
|
||||
if (!(_internal.config[key] instanceof URL)) {
|
||||
_internal.config[key] = new URL(_internal.config[key] || "");
|
||||
}
|
||||
}
|
||||
|
||||
return _internal.config[key];
|
||||
},
|
||||
set(key: string, value: any) {
|
||||
_internal.config[key] = value;
|
||||
clearTimeout(_internal.writeTimeout);
|
||||
_internal.writeTimeout = setTimeout(() => {
|
||||
Bun.write(dir(`${g.datadir}/config/conf.json`), _internal.config);
|
||||
}, 100);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { file } from "bun";
|
||||
import { watch } from "fs";
|
||||
import { dir } from "./dir";
|
||||
import { dirAsync } from "fs-jetpack";
|
||||
|
||||
export const startDevWatcher = async () => {
|
||||
await dirAsync(dir(`app/srv/api`));
|
||||
watch(dir(`app/srv/api`), async (event, filename) => {
|
||||
const s = file(dir(`app/srv/api/${filename}`));
|
||||
if (s.size === 0) {
|
||||
await Bun.write(
|
||||
`app/srv/api/${filename}`,
|
||||
`\
|
||||
import { apiContext } from "service-srv";
|
||||
|
||||
export const _ = {
|
||||
url: "/${filename?.substring(0, filename.length - 3)})}",
|
||||
async api() {
|
||||
const { req, res } = apiContext(this);
|
||||
return "This is ${filename}";
|
||||
}
|
||||
}`
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { join } from "path";
|
||||
|
||||
export const dir = (path: string) => {
|
||||
return join(process.cwd(), path);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
import { connect } from "bun";
|
||||
import { g } from "./global";
|
||||
|
||||
export const ensureNotRunning = async () => {
|
||||
await new Promise<void>(async (resolve) => {
|
||||
const checkPort = () => {
|
||||
return new Promise<boolean>(async (done) => {
|
||||
try {
|
||||
const s = await connect({
|
||||
hostname: "0.0.0.0",
|
||||
port: g.port,
|
||||
socket: {
|
||||
open(socket) {},
|
||||
data(socket, data) {},
|
||||
close(socket) {},
|
||||
drain(socket) {},
|
||||
error(socket, error) {},
|
||||
},
|
||||
});
|
||||
s.end();
|
||||
done(false);
|
||||
} catch (e) {
|
||||
done(true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (!(await checkPort())) {
|
||||
g.log.warn(`Port ${process.env.PORT} is used, waiting...`);
|
||||
setInterval(async () => {
|
||||
if (await checkPort()) resolve();
|
||||
}, 500);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
import { Server } from "bun";
|
||||
import { Logger } from "pino";
|
||||
import { RadixRouter } from "radix3";
|
||||
import { PrismaClient } from "../../app/db/db";
|
||||
|
||||
import admin from "firebase-admin";
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
type SingleRoute = {
|
||||
url: string;
|
||||
args: string[];
|
||||
fn: (...arg: any[]) => Promise<any>;
|
||||
path: string;
|
||||
};
|
||||
|
||||
export const g = global as unknown as {
|
||||
db: PrismaClient;
|
||||
dburl: string;
|
||||
datadir: string;
|
||||
mode: "dev" | "prod";
|
||||
server: Server;
|
||||
log: Logger;
|
||||
firebaseInit: boolean,
|
||||
firebase: admin.app.App;
|
||||
notif: {
|
||||
db: Database;
|
||||
};
|
||||
api: Record<string, SingleRoute>;
|
||||
domains: null | Record<string, string>;
|
||||
web: Record<
|
||||
string,
|
||||
{
|
||||
site_id: string;
|
||||
current: number;
|
||||
deploying: null | { status: string; received: number; total: number };
|
||||
deploys: number[];
|
||||
domains: string[];
|
||||
router: null | RadixRouter<{ id: string }>;
|
||||
cacheKey: number;
|
||||
cache: null | {
|
||||
site: {
|
||||
id: string;
|
||||
name: string;
|
||||
favicon: string;
|
||||
domain: string;
|
||||
id_user: string;
|
||||
created_at: Date | null;
|
||||
id_org: string | null;
|
||||
updated_at: Date | null;
|
||||
responsive: string;
|
||||
} | null;
|
||||
pages: {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
content_tree: any;
|
||||
id_site: string;
|
||||
created_at: Date | null;
|
||||
js_compiled: string | null;
|
||||
js: string | null;
|
||||
updated_at: Date | null;
|
||||
id_folder: string | null;
|
||||
is_deleted: boolean;
|
||||
}[];
|
||||
npm: {
|
||||
site: Record<string, string>;
|
||||
pages: Record<string, Record<string, string>>;
|
||||
};
|
||||
comps: {
|
||||
id: string;
|
||||
name: string;
|
||||
content_tree: any;
|
||||
created_at: Date | null;
|
||||
updated_at: Date | null;
|
||||
type: string;
|
||||
id_component_group: string | null;
|
||||
props: any;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
>;
|
||||
router: RadixRouter<SingleRoute>;
|
||||
port: number;
|
||||
frm: {
|
||||
js: string;
|
||||
etag: string;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
import { gzip, gunzip } from "zlib";
|
||||
|
||||
export const gzipAsync = (bin: Uint8Array) => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
gzip(bin, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const gunzipAsync = (bin: Uint8Array) => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
gunzip(bin, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import { pino } from "pino";
|
||||
import { g } from "./global";
|
||||
|
||||
export const createLogger = async () => {
|
||||
g.log = pino({
|
||||
transport: {
|
||||
target: "pino-pretty",
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { existsAsync } from "fs-jetpack";
|
||||
import { dir } from "./dir";
|
||||
import { $ } from "execa";
|
||||
import { g } from "./global";
|
||||
|
||||
export const preparePrisma = async () => {
|
||||
if (await existsAsync(dir("app/db/.env"))) {
|
||||
if (!(await existsAsync(dir("node_modules/.prisma")))) {
|
||||
await $({ cwd: dir(`app/db`) })`bun prisma generate`;
|
||||
}
|
||||
const { PrismaClient } = await import("../../app/db/db");
|
||||
g.db = new PrismaClient();
|
||||
}
|
||||
|
||||
g.dburl = process.env.DATABASE_URL || "";
|
||||
g.port = parseInt(process.env.PORT || "3000");
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
export type DBArg = {
|
||||
db: string;
|
||||
table: string;
|
||||
action: string;
|
||||
params: any[];
|
||||
};
|
||||
|
||||
export const execQuery = async (args: DBArg, prisma: any) => {
|
||||
const { table, action, params } = args;
|
||||
|
||||
const tableInstance = prisma[table];
|
||||
|
||||
if (tableInstance) {
|
||||
if (action === "query" && table.startsWith("$query")) {
|
||||
try {
|
||||
const q = params.shift();
|
||||
q.sql = true;
|
||||
Object.freeze(q);
|
||||
return await tableInstance.bind(prisma)(q, ...params);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
const method = tableInstance[action];
|
||||
|
||||
if (method) {
|
||||
try {
|
||||
const result = await method(...params);
|
||||
|
||||
if (!result) {
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (e: any) {
|
||||
throw new Error(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import { $ } from "execa";
|
||||
import { g } from "./global";
|
||||
|
||||
export const restartServer = () => {
|
||||
if (g.mode === "dev") {
|
||||
$`bun ${g.mode}`;
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
export const waitUntil = (
|
||||
condition: number | (() => any),
|
||||
timeout?: number
|
||||
) => {
|
||||
return new Promise<void>(async (resolve) => {
|
||||
if (typeof condition === "function") {
|
||||
let tout = null as any;
|
||||
if (timeout) {
|
||||
tout = setTimeout(resolve, timeout);
|
||||
}
|
||||
if (await condition()) {
|
||||
clearTimeout(tout);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
let count = 0;
|
||||
const c = setInterval(async () => {
|
||||
if (await condition()) {
|
||||
if (tout) clearTimeout(tout);
|
||||
clearInterval(c);
|
||||
resolve();
|
||||
}
|
||||
if (count > 100) {
|
||||
clearInterval(c);
|
||||
}
|
||||
}, 10);
|
||||
} else if (typeof condition === "number") {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, condition);
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user