wip fix code
This commit is contained in:
parent
34a356ccbd
commit
d6d62c7df0
|
|
@ -1,5 +1,5 @@
|
|||
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||
import { code } from "../ws/sync/editor/code/util-code";
|
||||
import { code } from "../ws/sync/code/code";
|
||||
|
||||
export const _ = {
|
||||
url: "/nova-load/:mode/:id_site/**",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { apiContext } from "service-srv";
|
||||
import { code } from "../ws/sync/editor/code/util-code";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { gzipAsync } from "../ws/sync/entity/zlib";
|
||||
import { validate } from "uuid";
|
||||
import { dir } from "dir";
|
||||
import { existsAsync, readAsync } from "fs-jetpack";
|
||||
import { code } from "../ws/sync/code/code";
|
||||
|
||||
export const _ = {
|
||||
url: "/prod-zip/:site_id",
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { dir } from "dir";
|
|||
import { apiContext } from "service-srv";
|
||||
import { validate } from "uuid";
|
||||
import { prodIndex } from "../util/prod-index";
|
||||
import { code } from "../ws/sync/editor/code/util-code";
|
||||
import { gzipAsync } from "../ws/sync/entity/zlib";
|
||||
import { code } from "../ws/sync/code/code";
|
||||
|
||||
export const _ = {
|
||||
url: "/prod/:site_id/**",
|
||||
|
|
@ -20,6 +20,8 @@ export const _ = {
|
|||
if (!validate(site_id))
|
||||
return new Response("site not found", { status: 403 });
|
||||
|
||||
code;
|
||||
|
||||
if (pathname.startsWith("_prasi")) {
|
||||
const action = pathname.split("/")[1];
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -119,7 +119,7 @@ export const SyncActions = {
|
|||
| { type: "startup-check" }
|
||||
| { type: "startup-run" }
|
||||
| { type: "startup-stop" }
|
||||
| { type: "push-typings"; body: Uint8Array; hash: number }
|
||||
// | { type: "push-typings"; body: Uint8Array; hash: number }
|
||||
| { type: "check-typings"; hash: number }
|
||||
))
|
||||
| { type: "flush-page-cache"; page_id: string }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Subprocess, spawn } from "bun";
|
||||
import { waitUntil } from "web-utils";
|
||||
import { SAction } from "../actions";
|
||||
import { code, codeGlobalTypings } from "../editor/code/util-code";
|
||||
import { docs } from "../entity/docs";
|
||||
import { snapshot } from "../entity/snapshot";
|
||||
import { SyncConnection } from "../type";
|
||||
|
|
@ -9,6 +8,7 @@ import { dirAsync } from "fs-jetpack";
|
|||
import path from "path";
|
||||
import { gunzipAsync } from "../entity/zlib";
|
||||
import { prismaExtendType } from "../../../../web/src/utils/script/prisma-extend";
|
||||
import { code } from "../code/code";
|
||||
|
||||
const decoder = new TextDecoder();
|
||||
const code_startup = {
|
||||
|
|
@ -84,41 +84,41 @@ export const code_action: SAction["code"]["action"] = async function (
|
|||
} catch (e) {}
|
||||
return { type: "check-typings", hash: false };
|
||||
}
|
||||
case "push-typings": {
|
||||
const dir = code.path(arg.site_id, "site", "src", "typings");
|
||||
await dirAsync(dir);
|
||||
await dirAsync(path.join(dir, "runtime"));
|
||||
Bun.write(Bun.file(path.join(dir, "hash")), arg.hash.toString());
|
||||
const res = JSON.parse(decoder.decode(await gunzipAsync(arg.body)));
|
||||
await Bun.write(Bun.file(path.join(dir, "api.d.ts")), res.api);
|
||||
await Bun.write(
|
||||
Bun.file(path.join(dir, "prisma.d.ts")),
|
||||
res.prisma["prisma.d.ts"]
|
||||
);
|
||||
await Bun.write(
|
||||
Bun.file(path.join(dir, "runtime/index.d.ts")),
|
||||
res.prisma["runtime/index.d.ts"]
|
||||
);
|
||||
await Bun.write(
|
||||
Bun.file(path.join(dir, "runtime/library.d.ts")),
|
||||
res.prisma["runtime/library.d.ts"]
|
||||
);
|
||||
await Bun.write(
|
||||
Bun.file(path.join(dir, "global.d.ts")),
|
||||
codeGlobalTypings.replace(
|
||||
`declare global {`,
|
||||
`declare global {
|
||||
const db: prisma.PrismaClient & ${prismaExtendType};
|
||||
`
|
||||
)
|
||||
);
|
||||
// case "push-typings": {
|
||||
// const dir = code.path(arg.site_id, "site", "src", "typings");
|
||||
// await dirAsync(dir);
|
||||
// await dirAsync(path.join(dir, "runtime"));
|
||||
// Bun.write(Bun.file(path.join(dir, "hash")), arg.hash.toString());
|
||||
// const res = JSON.parse(decoder.decode(await gunzipAsync(arg.body)));
|
||||
// await Bun.write(Bun.file(path.join(dir, "api.d.ts")), res.api);
|
||||
// await Bun.write(
|
||||
// Bun.file(path.join(dir, "prisma.d.ts")),
|
||||
// res.prisma["prisma.d.ts"]
|
||||
// );
|
||||
// await Bun.write(
|
||||
// Bun.file(path.join(dir, "runtime/index.d.ts")),
|
||||
// res.prisma["runtime/index.d.ts"]
|
||||
// );
|
||||
// await Bun.write(
|
||||
// Bun.file(path.join(dir, "runtime/library.d.ts")),
|
||||
// res.prisma["runtime/library.d.ts"]
|
||||
// );
|
||||
// await Bun.write(
|
||||
// Bun.file(path.join(dir, "global.d.ts")),
|
||||
// codeGlobalTypings.replace(
|
||||
// `declare global {`,
|
||||
// `declare global {
|
||||
// const db: prisma.PrismaClient & ${prismaExtendType};
|
||||
// `
|
||||
// )
|
||||
// );
|
||||
|
||||
Bun.spawn({
|
||||
cmd: ["chmod", "-R", "777", "."],
|
||||
cwd: code.path(arg.site_id, "site", "src"),
|
||||
});
|
||||
// Bun.spawn({
|
||||
// cmd: ["chmod", "-R", "777", "."],
|
||||
// cwd: code.path(arg.site_id, "site", "src"),
|
||||
// });
|
||||
|
||||
break;
|
||||
}
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { SAction } from "../actions";
|
||||
import { prepCodeSnapshot } from "../editor/code/prep-code";
|
||||
import { SyncConnection } from "../type";
|
||||
|
||||
export const code_load: SAction["code"]["load"] = async function (
|
||||
|
|
@ -7,7 +6,5 @@ export const code_load: SAction["code"]["load"] = async function (
|
|||
site_id,
|
||||
type
|
||||
) {
|
||||
const snap = await prepCodeSnapshot(site_id, "site");
|
||||
|
||||
return { id: site_id };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { validate } from "uuid";
|
|||
import { ESite } from "../../../../web/src/nova/ed/logic/ed-global";
|
||||
import { SAction } from "../actions";
|
||||
import { SyncConnection } from "../type";
|
||||
import { prepCodeSnapshot } from "../editor/code/prep-code";
|
||||
import { code } from "../code/code";
|
||||
|
||||
export const site_load: SAction["site"]["load"] = async function (
|
||||
this: SyncConnection,
|
||||
|
|
@ -13,6 +13,8 @@ export const site_load: SAction["site"]["load"] = async function (
|
|||
if (site) {
|
||||
if (this.conf) this.conf.site_id = site.id;
|
||||
|
||||
code.init(site.id, "init site_load");
|
||||
|
||||
const config =
|
||||
typeof site.config === "object" && site.config
|
||||
? { api_url: (site.config as any).api_url || "" }
|
||||
|
|
@ -43,8 +45,6 @@ export const site_load: SAction["site"]["load"] = async function (
|
|||
}
|
||||
}
|
||||
|
||||
const code = await prepCodeSnapshot(site.id, "site");
|
||||
|
||||
return {
|
||||
id: site.id,
|
||||
name: site.name,
|
||||
|
|
@ -58,7 +58,6 @@ export const site_load: SAction["site"]["load"] = async function (
|
|||
meta: undefined,
|
||||
entry: [],
|
||||
},
|
||||
code_ts: code.ts,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
import { dir } from "dir";
|
||||
import { initFrontEnd } from "./parts/init/frontend";
|
||||
import { initServer } from "./parts/init/server";
|
||||
import { initTypings } from "./parts/init/typings";
|
||||
import { codeInternal } from "./parts/internal";
|
||||
import { ensureLib } from "./utlis/ensure-lib";
|
||||
import { ensure } from "./utlis/ensure";
|
||||
|
||||
export const code = {
|
||||
internal: codeInternal,
|
||||
async init(id_site: string, note: string) {
|
||||
const { frontend, server, typings } = this.internal;
|
||||
if (!frontend[id_site] || !server[id_site] || !typings[id_site]) {
|
||||
const root = `/code/${id_site}/site/src`;
|
||||
|
||||
if (!frontend[id_site]) await initFrontEnd(root, id_site);
|
||||
if (!server[id_site]) await initServer(root, id_site);
|
||||
if (!typings[id_site]) await initTypings(root, id_site);
|
||||
|
||||
await ensureLib(root, id_site);
|
||||
await ensure(`${root}/index.tsx`, ``);
|
||||
}
|
||||
},
|
||||
path(
|
||||
id_site: string,
|
||||
mode: "site" | "server",
|
||||
type: "src" | "build" | "build_cache",
|
||||
path?: string
|
||||
) {
|
||||
let file_path = "";
|
||||
if (path) {
|
||||
file_path = path[0] === "/" ? path : `/${path}`;
|
||||
}
|
||||
|
||||
return dir.data(`/code/${id_site}/${mode}/${type}${file_path}`);
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { code } from "../../code";
|
||||
|
||||
export const initFrontEnd = async (root: string, id_site: string) => {
|
||||
const existing = code.internal.frontend[id_site];
|
||||
if (existing) {
|
||||
await existing.dispose();
|
||||
}
|
||||
|
||||
code.internal.frontend[id_site] = true as any;
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import { context } from "esbuild";
|
||||
import { code } from "../../code";
|
||||
import { ensure } from "../../utlis/ensure";
|
||||
import { dir } from "dir";
|
||||
import { dirAsync, removeAsync, existsAsync, writeAsync } from "fs-jetpack";
|
||||
|
||||
export const initServer = async (root: string, id_site: string) => {
|
||||
const existing = code.internal.server[id_site];
|
||||
if (existing) {
|
||||
await existing.dispose();
|
||||
}
|
||||
|
||||
const build_path = code.path(id_site, "server", "build");
|
||||
await removeAsync(build_path);
|
||||
await dirAsync(build_path);
|
||||
|
||||
const build_file = `${build_path}/index.js`;
|
||||
if (!(await existsAsync(build_file))) {
|
||||
await writeAsync(build_file, "");
|
||||
}
|
||||
|
||||
code.internal.server[id_site] = await context({
|
||||
absWorkingDir: dir.data(root),
|
||||
entryPoints: ["server.ts"],
|
||||
bundle: true,
|
||||
outfile: build_file,
|
||||
platform: "node",
|
||||
treeShaking: true,
|
||||
format: "cjs",
|
||||
logLevel: "silent",
|
||||
banner: {
|
||||
js: `\
|
||||
const _fs = require('node:fs/promises');
|
||||
const console =
|
||||
typeof global.server_hook === "function"
|
||||
? { ...global.console }
|
||||
: global.console;
|
||||
|
||||
let db = new Proxy({}, {
|
||||
get(_, key) {
|
||||
const runtime = global.server_runtime["${id_site}"];
|
||||
if (runtime && runtime.db) {
|
||||
return runtime.db[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
let api = {};
|
||||
if (typeof global.server_hook === "function") {
|
||||
const log = global.console.log;
|
||||
console.log = function (...arg) {
|
||||
const out = "${code.path(id_site, "site", "src", "server.log")}";
|
||||
_fs.appendFile(out, arg.map((e)=>{
|
||||
const ancestors = [];
|
||||
if (typeof e === 'object') return JSON.stringify(e, function (key, val) {
|
||||
if (val) {
|
||||
if (typeof val === 'function') {
|
||||
return '[function]';
|
||||
}
|
||||
if (typeof val === 'object') {
|
||||
while (ancestors.length > 0 && ancestors.at(-1) !== this) {
|
||||
ancestors.pop();
|
||||
}
|
||||
if (ancestors.includes(val)) {
|
||||
return "[circular]";
|
||||
}
|
||||
ancestors.push(val);
|
||||
|
||||
if (val.constructor &&
|
||||
!['Object', 'Array'].includes(val.constructor.name)) {
|
||||
if (val.constructor.name === 'Error') {
|
||||
return '[Error] ' + val.message;
|
||||
}
|
||||
return '[Class] ' + val.constructor.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}, 2);
|
||||
return e;
|
||||
}).join(" ") + "\\n");
|
||||
}.bind(console);
|
||||
} else {
|
||||
db = global.db;
|
||||
api = global.api;
|
||||
}`,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { code } from "../../code";
|
||||
|
||||
export const initTypings = async (root_dir: string, id_site: string) => {
|
||||
code.internal.typings[id_site] = true as any;
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { Subprocess } from "bun";
|
||||
import type { BuildContext } from "esbuild";
|
||||
|
||||
const g = global as unknown as {
|
||||
prasi_code: any;
|
||||
};
|
||||
type SITE_ID = string;
|
||||
|
||||
export const codeInternal = {
|
||||
get server() {
|
||||
if (!g.prasi_code) g.prasi_code = {};
|
||||
if (!g.prasi_code.server) g.prasi_code.server = {};
|
||||
return g.prasi_code.server as Record<SITE_ID, BuildContext>;
|
||||
},
|
||||
get frontend() {
|
||||
if (!g.prasi_code) g.prasi_code = {};
|
||||
if (!g.prasi_code.frontend) g.prasi_code.frontend = {};
|
||||
return g.prasi_code.frontend as Record<SITE_ID, BuildContext>;
|
||||
},
|
||||
get typings() {
|
||||
if (!g.prasi_code) g.prasi_code = {};
|
||||
if (!g.prasi_code.typings) g.prasi_code.typings = {};
|
||||
return g.prasi_code.typings as Record<SITE_ID, Subprocess>;
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export * from "@/data";
|
||||
export * from "@/exports";
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import type {} from "./typings/global";
|
||||
|
||||
export const server: PrasiServer = {
|
||||
async http({ req, handle, mode, url, index, server }) {
|
||||
return await handle(req);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./lib/*"],
|
||||
"app/*": ["./app/*"],
|
||||
"server/*": ["./server/*"]
|
||||
},
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"declaration": true,
|
||||
"outFile": "types.d.ts",
|
||||
"emitDeclarationOnly": true,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react-jsx",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": true,
|
||||
"typeRoots": ["./node_modules/@types", "./lib/types"]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
//@ts-ignore
|
||||
import type * as SRVAPI from "gen/srv/api/srv";
|
||||
import { Server, WebSocketHandler } from "bun";
|
||||
import prisma from "./prisma";
|
||||
|
||||
declare global {
|
||||
type Api = typeof SRVAPI;
|
||||
type ApiName = keyof Api;
|
||||
const api: { [k in ApiName]: Awaited<Api[k]["handler"]>["_"]["api"] } & {
|
||||
_raw: any;
|
||||
};
|
||||
const db: prisma.PrismaClient & {
|
||||
_batch: {
|
||||
update: (
|
||||
batch: {
|
||||
table: string;
|
||||
data: any;
|
||||
where: any;
|
||||
}[]
|
||||
) => Promise<void>;
|
||||
};
|
||||
_schema: {
|
||||
tables: () => Promise<string[]>;
|
||||
columns: (table: string) => Promise<
|
||||
Record<
|
||||
string,
|
||||
{
|
||||
is_pk: boolean;
|
||||
type: string;
|
||||
optional: boolean;
|
||||
db_type: string;
|
||||
default?: any;
|
||||
}
|
||||
>
|
||||
>;
|
||||
rels: (table: string) => Promise<
|
||||
Record<
|
||||
string,
|
||||
{
|
||||
type: "has-many" | "has-one";
|
||||
to: {
|
||||
table: string;
|
||||
fields: string[];
|
||||
};
|
||||
from: {
|
||||
table: string;
|
||||
fields: string[];
|
||||
};
|
||||
}
|
||||
>
|
||||
>;
|
||||
};
|
||||
};
|
||||
|
||||
type PrasiServer = {
|
||||
ws?: WebSocketHandler<{ url: string }>;
|
||||
http: (arg: {
|
||||
url: { raw: URL; pathname: string };
|
||||
req: Request;
|
||||
server: Server;
|
||||
mode: "dev" | "prod";
|
||||
handle: (req: Request) => Promise<Response>;
|
||||
index: { head: string[]; body: string[]; render: () => string };
|
||||
prasi: { page_id?: string; params?: Record<string, any> };
|
||||
}) => Promise<Response>;
|
||||
init: (arg: { port?: number }) => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { $ } from "bun";
|
||||
import { dir } from "dir";
|
||||
import { exists, dirAsync } from "fs-jetpack";
|
||||
|
||||
export const ensureLib = async (src_dir: string, id_site: string) => {
|
||||
if (!exists(dir.data(src_dir))) {
|
||||
await dirAsync(dir.data(src_dir));
|
||||
}
|
||||
|
||||
if (!exists(dir.data(`${src_dir}/lib`))) {
|
||||
console.log(`${src_dir}/lib not found.`);
|
||||
const _ = $.cwd(dir.data(src_dir));
|
||||
await _`git clone https://github.com/avolut/prasi-lib lib`;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { exists, dirAsync } from "fs-jetpack";
|
||||
import { dirname } from "path";
|
||||
import { dir } from "dir";
|
||||
|
||||
export const ensure = async (path: string, content: string) => {
|
||||
const _path = dir.data(path);
|
||||
const _dir = dirname(_path);
|
||||
if (!exists(_dir)) {
|
||||
await dirAsync(_dir);
|
||||
}
|
||||
if (!exists(_path)) {
|
||||
await Bun.write(_path, content);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,22 +1,7 @@
|
|||
import globalExternals from "@fal-works/esbuild-plugin-global-externals";
|
||||
import { style } from "@hyrious/esbuild-plugin-style";
|
||||
import { context } from "esbuild";
|
||||
import {
|
||||
dirAsync,
|
||||
existsAsync,
|
||||
removeAsync,
|
||||
writeAsync,
|
||||
moveAsync,
|
||||
} from "fs-jetpack";
|
||||
import { server } from "./server-main";
|
||||
import { code } from "./util-code";
|
||||
import { user } from "../../entity/user";
|
||||
import { conns } from "../../entity/conn";
|
||||
import { SyncType } from "../../type";
|
||||
import { Packr } from "msgpackr";
|
||||
import { ServerWebSocket } from "bun";
|
||||
import { Packr } from "msgpackr";
|
||||
import { WSData } from "../../../../../../pkgs/core/server/create";
|
||||
import { g } from "utils/global";
|
||||
import { code } from "../../code/code";
|
||||
|
||||
const packr = new Packr({ structuredClone: true });
|
||||
|
||||
|
|
@ -25,267 +10,240 @@ const sendWS = (ws: ServerWebSocket<WSData>, msg: any) => {
|
|||
};
|
||||
|
||||
export const codeBuild = async (id_site: any) => {
|
||||
const src_path = code.path(id_site, "site", "src");
|
||||
if (!(await existsAsync(src_path))) return;
|
||||
if (!code.esbuild[id_site]) {
|
||||
code.esbuild[id_site] = { site: null, server: null, site_ts: Date.now() };
|
||||
}
|
||||
return;
|
||||
// const src_path = code.path(id_site, "site", "src");
|
||||
// if (!(await existsAsync(src_path))) return;
|
||||
// if (!code.esbuild[id_site]) {
|
||||
// code.esbuild[id_site] = { site: null, server: null, site_ts: Date.now() };
|
||||
// }
|
||||
|
||||
if (!code.esbuild[id_site].server) {
|
||||
const server_main = code.path(id_site, "site", "src", "server.ts");
|
||||
if (!(await existsAsync(server_main))) {
|
||||
await writeAsync(
|
||||
server_main,
|
||||
`\
|
||||
import type {} from "./typings/global";
|
||||
// if (!code.esbuild[id_site].server) {
|
||||
// const server_main = code.path(id_site, "site", "src", "server.ts");
|
||||
// if (!(await existsAsync(server_main))) {
|
||||
// await writeAsync(
|
||||
// server_main,
|
||||
// `\
|
||||
// import type {} from "./typings/global";
|
||||
|
||||
export const server: PrasiServer = {
|
||||
async http({ req, handle, mode, url, index, server }) {
|
||||
return await handle(req);
|
||||
}
|
||||
// export const server: PrasiServer = {
|
||||
// async http({ req, handle, mode, url, index, server }) {
|
||||
// return await handle(req);
|
||||
// }
|
||||
// };
|
||||
// `
|
||||
// );
|
||||
// const bun_types = Bun.spawn({
|
||||
// cmd: ["npm", "i", "-D", "@types/bun"],
|
||||
// cwd: code.path(id_site, "site", "src"),
|
||||
// });
|
||||
// await bun_types.exited;
|
||||
// }
|
||||
|
||||
// const build_path = code.path(id_site, "server", "build");
|
||||
// await removeAsync(build_path);
|
||||
// await dirAsync(build_path);
|
||||
|
||||
// const build_file = `${build_path}/index.js`;
|
||||
// if (!(await existsAsync(build_file))) {
|
||||
// await writeAsync(build_file, "");
|
||||
// }
|
||||
|
||||
// code.esbuild[id_site].server = await context({
|
||||
// absWorkingDir: src_path,
|
||||
// entryPoints: ["server.ts"],
|
||||
// bundle: true,
|
||||
// outfile: build_file,
|
||||
// platform: "node",
|
||||
// treeShaking: true,
|
||||
// format: "cjs",
|
||||
// logLevel: "silent",
|
||||
// banner: {
|
||||
// js: `\
|
||||
// const _fs = require('node:fs/promises');
|
||||
// const console =
|
||||
// typeof global.server_hook === "function"
|
||||
// ? { ...global.console }
|
||||
// : global.console;
|
||||
|
||||
// let db = new Proxy({}, {
|
||||
// get(_, key) {
|
||||
// const runtime = global.server_runtime["${id_site}"];
|
||||
// if (runtime && runtime.db) {
|
||||
// return runtime.db[key];
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// let api = {};
|
||||
// if (typeof global.server_hook === "function") {
|
||||
// const log = global.console.log;
|
||||
// console.log = function (...arg) {
|
||||
// const out = "${code.path(id_site, "site", "src", "server.log")}";
|
||||
// _fs.appendFile(out, arg.map((e)=>{
|
||||
// const ancestors = [];
|
||||
// if (typeof e === 'object') return JSON.stringify(e, function (key, val) {
|
||||
// if (val) {
|
||||
// if (typeof val === 'function') {
|
||||
// return '[function]';
|
||||
// }
|
||||
// if (typeof val === 'object') {
|
||||
// while (ancestors.length > 0 && ancestors.at(-1) !== this) {
|
||||
// ancestors.pop();
|
||||
// }
|
||||
// if (ancestors.includes(val)) {
|
||||
// return "[circular]";
|
||||
// }
|
||||
// ancestors.push(val);
|
||||
|
||||
// if (val.constructor &&
|
||||
// !['Object', 'Array'].includes(val.constructor.name)) {
|
||||
// if (val.constructor.name === 'Error') {
|
||||
// return '[Error] ' + val.message;
|
||||
// }
|
||||
// return '[Class] ' + val.constructor.name;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return val;
|
||||
// }, 2);
|
||||
// return e;
|
||||
// }).join(" ") + "\\n");
|
||||
// }.bind(console);
|
||||
// } else {
|
||||
// db = global.db;
|
||||
// api = global.api;
|
||||
// }`,
|
||||
// },
|
||||
// plugins: [
|
||||
// style(),
|
||||
// globalExternals({
|
||||
// react: {
|
||||
// varName: "window.React",
|
||||
// type: "cjs",
|
||||
// },
|
||||
// "react-dom": {
|
||||
// varName: "window.ReactDOM",
|
||||
// type: "cjs",
|
||||
// },
|
||||
// }),
|
||||
// {
|
||||
// name: "prasi",
|
||||
// setup(setup) {
|
||||
// const reinit = () => {
|
||||
// setup.onEnd((res) => {
|
||||
// if (res.errors.length > 0) {
|
||||
// Bun.write(
|
||||
// Bun.file(code.path(id_site, "site", "src", "server.log")),
|
||||
// JSON.stringify(res.errors, null, 2)
|
||||
// );
|
||||
// }
|
||||
// server.init(id_site);
|
||||
// });
|
||||
// };
|
||||
// reinit();
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// const esbuild = code.esbuild[id_site].server;
|
||||
// esbuild?.watch();
|
||||
// }
|
||||
|
||||
// if (!code.esbuild[id_site].site) {
|
||||
// const build_path = code.path(id_site, "site", "build_cache");
|
||||
// await removeAsync(build_path);
|
||||
// await dirAsync(build_path);
|
||||
// const build_file = `${build_path}/index.js`;
|
||||
// await writeAsync(build_file, "");
|
||||
|
||||
// const index_path = code.path(id_site, "site", "src", "index.tsx");
|
||||
// if (!(await existsAsync(index_path))) {
|
||||
// await writeAsync(index_path, 'export const hello = "world"');
|
||||
// }
|
||||
// console.log("running ");
|
||||
|
||||
// code.esbuild[id_site].site = await context({
|
||||
// absWorkingDir: src_path,
|
||||
// entryPoints: ["index.tsx"],
|
||||
// bundle: true,
|
||||
// outdir: build_path,
|
||||
// minify: true,
|
||||
// treeShaking: true,
|
||||
// format: "esm",
|
||||
// splitting: true,
|
||||
// logLevel: "silent",
|
||||
// sourcemap: true,
|
||||
// plugins: [
|
||||
// style(),
|
||||
// globalExternals({
|
||||
// react: {
|
||||
// varName: "window.React",
|
||||
// type: "cjs",
|
||||
// },
|
||||
// "react-dom": {
|
||||
// varName: "window.ReactDOM",
|
||||
// type: "cjs",
|
||||
// },
|
||||
// }),
|
||||
// {
|
||||
// name: "prasi",
|
||||
// setup(setup) {
|
||||
// setup.onEnd(async (res) => {
|
||||
// if (res.errors.length > 0) {
|
||||
// await codeError(
|
||||
// id_site,
|
||||
// res.errors.map((e) => e.text).join("\n\n"),
|
||||
// "site"
|
||||
// );
|
||||
// } else {
|
||||
// codeBuildType(id_site);
|
||||
// await removeAsync(code.path(id_site, "site", "build"));
|
||||
// await moveAsync(
|
||||
// code.path(id_site, "site", "build_cache"),
|
||||
// code.path(id_site, "site", "build")
|
||||
// );
|
||||
// await removeAsync(
|
||||
// code.path(id_site, "site", "src", "index.log")
|
||||
// );
|
||||
|
||||
// code.esbuild[id_site].site_ts = Date.now();
|
||||
// const client_ids = new Set<string>();
|
||||
// user.active.findAll({ site_id: id_site }).forEach((e) => {
|
||||
// client_ids.add(e.client_id);
|
||||
// });
|
||||
|
||||
// client_ids.forEach((client_id) => {
|
||||
// const ws = conns.get(client_id)?.ws;
|
||||
// if (ws) {
|
||||
// sendWS(ws, {
|
||||
// type: SyncType.Event,
|
||||
// event: "code_changes",
|
||||
// data: { ts: code.esbuild[id_site].site_ts },
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// const esbuild = code.esbuild[id_site].site;
|
||||
// esbuild?.watch();
|
||||
// }
|
||||
// for (const _mode of ["site", "server"]) {
|
||||
// const mode = _mode as "site" | "server";
|
||||
|
||||
// const esbuild = code.esbuild[id_site][mode];
|
||||
// if (esbuild) {
|
||||
// try {
|
||||
// await esbuild.rebuild();
|
||||
// } catch (e: any) {
|
||||
// await codeError(id_site, e.message, mode);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
};
|
||||
`
|
||||
);
|
||||
const bun_types = Bun.spawn({
|
||||
cmd: ["npm", "i", "-D", "@types/bun"],
|
||||
cwd: code.path(id_site, "site", "src"),
|
||||
});
|
||||
await bun_types.exited;
|
||||
}
|
||||
|
||||
const build_path = code.path(id_site, "server", "build");
|
||||
await removeAsync(build_path);
|
||||
await dirAsync(build_path);
|
||||
|
||||
const build_file = `${build_path}/index.js`;
|
||||
if (!(await existsAsync(build_file))) {
|
||||
await writeAsync(build_file, "");
|
||||
}
|
||||
|
||||
code.esbuild[id_site].server = await context({
|
||||
absWorkingDir: src_path,
|
||||
entryPoints: ["server.ts"],
|
||||
bundle: true,
|
||||
outfile: build_file,
|
||||
platform: "node",
|
||||
treeShaking: true,
|
||||
format: "cjs",
|
||||
logLevel: "silent",
|
||||
banner: {
|
||||
js: `\
|
||||
const _fs = require('node:fs/promises');
|
||||
const console =
|
||||
typeof global.server_hook === "function"
|
||||
? { ...global.console }
|
||||
: global.console;
|
||||
|
||||
let db = new Proxy({}, {
|
||||
get(_, key) {
|
||||
const runtime = global.server_runtime["${id_site}"];
|
||||
if (runtime && runtime.db) {
|
||||
return runtime.db[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
let api = {};
|
||||
if (typeof global.server_hook === "function") {
|
||||
const log = global.console.log;
|
||||
console.log = function (...arg) {
|
||||
const out = "${code.path(id_site, "site", "src", "server.log")}";
|
||||
_fs.appendFile(out, arg.map((e)=>{
|
||||
const ancestors = [];
|
||||
if (typeof e === 'object') return JSON.stringify(e, function (key, val) {
|
||||
if (val) {
|
||||
if (typeof val === 'function') {
|
||||
return '[function]';
|
||||
}
|
||||
if (typeof val === 'object') {
|
||||
while (ancestors.length > 0 && ancestors.at(-1) !== this) {
|
||||
ancestors.pop();
|
||||
}
|
||||
if (ancestors.includes(val)) {
|
||||
return "[circular]";
|
||||
}
|
||||
ancestors.push(val);
|
||||
|
||||
if (val.constructor &&
|
||||
!['Object', 'Array'].includes(val.constructor.name)) {
|
||||
if (val.constructor.name === 'Error') {
|
||||
return '[Error] ' + val.message;
|
||||
}
|
||||
return '[Class] ' + val.constructor.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}, 2);
|
||||
return e;
|
||||
}).join(" ") + "\\n");
|
||||
}.bind(console);
|
||||
} else {
|
||||
db = global.db;
|
||||
api = global.api;
|
||||
}`,
|
||||
},
|
||||
plugins: [
|
||||
style(),
|
||||
globalExternals({
|
||||
react: {
|
||||
varName: "window.React",
|
||||
type: "cjs",
|
||||
},
|
||||
"react-dom": {
|
||||
varName: "window.ReactDOM",
|
||||
type: "cjs",
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "prasi",
|
||||
setup(setup) {
|
||||
const reinit = () => {
|
||||
setup.onEnd((res) => {
|
||||
if (res.errors.length > 0) {
|
||||
Bun.write(
|
||||
Bun.file(code.path(id_site, "site", "src", "server.log")),
|
||||
JSON.stringify(res.errors, null, 2)
|
||||
);
|
||||
}
|
||||
server.init(id_site);
|
||||
});
|
||||
};
|
||||
reinit();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const esbuild = code.esbuild[id_site].server;
|
||||
esbuild?.watch();
|
||||
}
|
||||
|
||||
if (!code.esbuild[id_site].site) {
|
||||
const build_path = code.path(id_site, "site", "build_cache");
|
||||
await removeAsync(build_path);
|
||||
await dirAsync(build_path);
|
||||
const build_file = `${build_path}/index.js`;
|
||||
await writeAsync(build_file, "");
|
||||
|
||||
const index_path = code.path(id_site, "site", "src", "index.tsx");
|
||||
if (!(await existsAsync(index_path))) {
|
||||
await writeAsync(index_path, 'export const hello = "world"');
|
||||
}
|
||||
|
||||
code.esbuild[id_site].site = await context({
|
||||
absWorkingDir: src_path,
|
||||
entryPoints: ["index.tsx"],
|
||||
bundle: true,
|
||||
outdir: build_path,
|
||||
minify: true,
|
||||
treeShaking: true,
|
||||
format: "esm",
|
||||
splitting: true,
|
||||
logLevel: "silent",
|
||||
sourcemap: true,
|
||||
plugins: [
|
||||
style(),
|
||||
globalExternals({
|
||||
react: {
|
||||
varName: "window.React",
|
||||
type: "cjs",
|
||||
},
|
||||
"react-dom": {
|
||||
varName: "window.ReactDOM",
|
||||
type: "cjs",
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "prasi",
|
||||
setup(setup) {
|
||||
setup.onEnd(async (res) => {
|
||||
if (res.errors.length > 0) {
|
||||
await codeError(
|
||||
id_site,
|
||||
res.errors.map((e) => e.text).join("\n\n"),
|
||||
"site"
|
||||
);
|
||||
} else {
|
||||
await removeAsync(code.path(id_site, "site", "build"));
|
||||
await moveAsync(
|
||||
code.path(id_site, "site", "build_cache"),
|
||||
code.path(id_site, "site", "build")
|
||||
);
|
||||
await removeAsync(
|
||||
code.path(id_site, "site", "src", "index.log")
|
||||
);
|
||||
|
||||
code.esbuild[id_site].site_ts = Date.now();
|
||||
const client_ids = new Set<string>();
|
||||
user.active.findAll({ site_id: id_site }).forEach((e) => {
|
||||
client_ids.add(e.client_id);
|
||||
});
|
||||
|
||||
client_ids.forEach((client_id) => {
|
||||
const ws = conns.get(client_id)?.ws;
|
||||
if (ws) {
|
||||
sendWS(ws, {
|
||||
type: SyncType.Event,
|
||||
event: "code_changes",
|
||||
data: { ts: code.esbuild[id_site].site_ts },
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const esbuild = code.esbuild[id_site].site;
|
||||
esbuild?.watch();
|
||||
}
|
||||
for (const _mode of ["site", "server"]) {
|
||||
const mode = _mode as "site" | "server";
|
||||
|
||||
const esbuild = code.esbuild[id_site][mode];
|
||||
if (esbuild) {
|
||||
try {
|
||||
await esbuild.rebuild();
|
||||
} catch (e: any) {
|
||||
await codeError(id_site, e.message, mode);
|
||||
}
|
||||
}
|
||||
|
||||
// const build_file = code.path(id_site, mode, "build", "index.js");
|
||||
// const out = Bun.file(build_file);
|
||||
// const src = (await out.text()).replace(
|
||||
// "//# sourceMappingURL=index.js.map",
|
||||
// `//# sourceMappingURL=/nova-load/code/${id_site}/${mode}/index.js.map`
|
||||
// );
|
||||
// // await Bun.write(out, src);
|
||||
}
|
||||
};
|
||||
|
||||
// const codeApplyChanges = (path: string, doc: DCode) => {
|
||||
// const map = doc.getMap("map");
|
||||
|
||||
// const files = map.get("files");
|
||||
|
||||
// const dirs = readDirectoryRecursively(path);
|
||||
// doc.transact(() => {
|
||||
// files?.forEach((v, k) => {
|
||||
// if (!dirs[k]) {
|
||||
// files?.delete(k);
|
||||
// }
|
||||
// });
|
||||
// for (const [k, v] of Object.entries(dirs)) {
|
||||
// if (files) {
|
||||
// files.set(k, v);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// return doc;
|
||||
// };
|
||||
|
||||
const codeError = async (
|
||||
id_site: string,
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
import { g } from "utils/global";
|
||||
import { codeBuild } from "./build-code";
|
||||
import { CodeMode, code, codeGlobalTypings } from "./util-code";
|
||||
|
||||
export const prepCodeSnapshot = async (id_site: string, mode: CodeMode) => {
|
||||
await code
|
||||
.prep(id_site, mode)
|
||||
.new_file("index.tsx", "export const sample = 'hello_world'")
|
||||
.new_file(
|
||||
"package.json",
|
||||
JSON.stringify({ name: `${mode}-${id_site}`, dependencies: {} }, null, 2)
|
||||
)
|
||||
.new_file("typings/global.d.ts", codeGlobalTypings)
|
||||
.await();
|
||||
|
||||
await codeBuild(id_site);
|
||||
|
||||
return { ts: code.esbuild[id_site].site_ts };
|
||||
};
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
import type { Server, WebSocketHandler, ServerWebSocket } from "bun";
|
||||
import type { Server, WebSocketHandler } from "bun";
|
||||
import { existsAsync } from "fs-jetpack";
|
||||
import _fs from "node:fs/promises";
|
||||
import { g } from "utils/global";
|
||||
import { waitUntil } from "web-utils";
|
||||
import { code } from "./util-code";
|
||||
import { WSData } from "../../../../../../pkgs/core/server/create";
|
||||
import { codeBuild } from "./build-code";
|
||||
import { prodIndex } from "../../../../util/prod-index";
|
||||
|
||||
import { code } from "../../code/code";
|
||||
import "./server-runtime";
|
||||
|
||||
const serverMain = () => ({
|
||||
|
|
@ -61,10 +60,9 @@ const serverMain = () => ({
|
|||
site_id: string,
|
||||
arg: Parameters<Exclude<(typeof g)["server_hook"], undefined>>[0]
|
||||
) {
|
||||
if (!code.esbuild[site_id]) {
|
||||
await codeBuild(site_id);
|
||||
if (arg.url.pathname.endsWith("main.js")) {
|
||||
code.init(site_id, "init http");
|
||||
}
|
||||
|
||||
if (typeof this.handler[site_id] === "undefined") {
|
||||
if (
|
||||
await existsAsync(code.path(site_id, "server", "build", "index.js"))
|
||||
|
|
@ -130,13 +128,11 @@ type PrasiServer = {
|
|||
index: { head: string[]; body: string[]; render: () => string };
|
||||
prasi: { page_id?: string; params?: Record<string, any> };
|
||||
}) => Promise<Response>;
|
||||
init?: () => Promise<void>;
|
||||
init?: (arg: { port?: number }) => Promise<void>;
|
||||
};
|
||||
|
||||
const glb = global as unknown as {
|
||||
_server: ReturnType<typeof serverMain>;
|
||||
};
|
||||
if (!glb._server) {
|
||||
glb._server = serverMain();
|
||||
}
|
||||
glb._server = serverMain();
|
||||
export const server = glb._server;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { dir } from "dir";
|
|||
import { BuildContext } from "esbuild";
|
||||
import { dirAsync, exists, existsAsync, writeAsync } from "fs-jetpack";
|
||||
import { dirname } from "path";
|
||||
import { prismaExtendType } from "../../../../../web/src/utils/script/prisma-extend";
|
||||
|
||||
export type CodeBuild = {
|
||||
server: BuildContext | null;
|
||||
|
|
@ -11,13 +12,13 @@ export type CodeBuild = {
|
|||
};
|
||||
export type CodeMode = keyof CodeBuild;
|
||||
|
||||
export const code = {
|
||||
const code = {
|
||||
path(
|
||||
id_site: string,
|
||||
mode: CodeMode,
|
||||
type: "src" | "build" | "build_cache",
|
||||
path?: string
|
||||
) {
|
||||
) {
|
||||
let file_path = "";
|
||||
if (path) {
|
||||
file_path = path[0] === "/" ? path : `/${path}`;
|
||||
|
|
@ -69,6 +70,8 @@ declare global {
|
|||
type Api = typeof SRVAPI;
|
||||
type ApiName = keyof Api;
|
||||
const api: { [k in ApiName]: Awaited<Api[k]["handler"]>["_"]["api"] } & { _raw: any };
|
||||
const db: prisma.PrismaClient & ${prismaExtendType};
|
||||
|
||||
|
||||
type PrasiServer = {
|
||||
ws?: WebSocketHandler<{ url: string }>;
|
||||
|
|
@ -81,7 +84,7 @@ declare global {
|
|||
index: { head: string[]; body: string[]; render: () => string };
|
||||
prasi: { page_id?: string; params?: Record<string, any> };
|
||||
}) => Promise<Response>;
|
||||
init: () => Promise<void>;
|
||||
init: (arg: { port?: number }) => Promise<void>;
|
||||
};
|
||||
}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export const EmptySite = {
|
|||
meta: undefined as void | Record<string, IMeta>,
|
||||
entry: [] as string[],
|
||||
},
|
||||
code_ts: 0,
|
||||
};
|
||||
|
||||
export type ESite = typeof EmptySite;
|
||||
|
|
@ -150,6 +149,7 @@ export const EDGlobal = {
|
|||
sync: null as null | Awaited<ReturnType<typeof clientStartSync>>,
|
||||
sync_assigned: false,
|
||||
site: deepClone(EmptySite),
|
||||
site_tstamp: Date.now(),
|
||||
site_exports: {} as Record<string, any>,
|
||||
site_dts: "",
|
||||
script: {
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ export const applyEnv = async (p: PG) => {
|
|||
w.api = apiProxy(p.site.config.api_url);
|
||||
}
|
||||
|
||||
const url = `/prod/${p.site.id}/_prasi/code/index.js?ts=${p.site.code_ts}`;
|
||||
const url = `/prod/${p.site.id}/_prasi/code/index.js?ts=${p.site_tstamp}`;
|
||||
const fn = new Function("callback", `import("${url}").then(callback)`);
|
||||
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
fn((exports: any) => {
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ export const createViLocal = (
|
|||
const [_, set] = useState({});
|
||||
const local = ref.current;
|
||||
local.render = () => {
|
||||
if ((window as any).prasiContext?.render) {
|
||||
(window as any).prasiContext?.render();
|
||||
if ((window as any).prasiContext.render) {
|
||||
(window as any).prasiContext.render();
|
||||
} else {
|
||||
set({});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"module": "src/index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun run ./pkgs/core/index.ts dev",
|
||||
"dev": "bun run --hot ./pkgs/core/index.ts dev",
|
||||
"clean": "rm -rf data/lmdb && rm -rf app/static && rm -rf app/web/.parcel-cache",
|
||||
"build": "bun run --silent ./pkgs/core/build.ts",
|
||||
"build-site": "bun run --silent ./pkgs/core/build-site.ts",
|
||||
|
|
@ -19,9 +19,6 @@
|
|||
"app/*",
|
||||
"pkgs/*"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"brotli-wasm": "^2.0.1",
|
||||
"fdir": "^6.1.0",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
"pino-pretty": "^10.2.3",
|
||||
"radash": "^11.0.0",
|
||||
"radix3": "^1.1.0",
|
||||
"typescript": "^5.2.2",
|
||||
"unzipper": "^0.10.14"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue