checkpoint
This commit is contained in:
parent
0c96971a8f
commit
2af0e9932e
|
|
@ -132,15 +132,6 @@ model site {
|
|||
page_folder page_folder[]
|
||||
org org? @relation(fields: [id_org], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "site_id_organization_fkey")
|
||||
user user @relation(fields: [id_user], references: [id], onDelete: NoAction, onUpdate: NoAction)
|
||||
site_query site_query[]
|
||||
}
|
||||
|
||||
model site_query {
|
||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||
id_site String? @db.Uuid
|
||||
name String?
|
||||
query String?
|
||||
site site? @relation(fields: [id_site], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "site")
|
||||
}
|
||||
|
||||
model site_use_comp {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,54 @@
|
|||
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||
|
||||
const g = global as unknown as {
|
||||
_font_cache: Record<string, { body: any; headers: any }>;
|
||||
};
|
||||
|
||||
if (!g._font_cache) {
|
||||
g._font_cache = {};
|
||||
}
|
||||
|
||||
export const _ = {
|
||||
url: "/_font/**",
|
||||
async api() {
|
||||
const { req } = apiContext(this);
|
||||
const pathname = req.url.split("/_font").pop();
|
||||
const f = await fetch(`https://api.fonts.coollabs.io${pathname}`);
|
||||
const body = await f.arrayBuffer();
|
||||
const res = new Response(body);
|
||||
const pathname = req.url.split("/_font").pop() || "";
|
||||
const cache = g._font_cache[pathname];
|
||||
if (cache) {
|
||||
if (req.headers.get("accept-encoding")?.includes("gzip")) {
|
||||
return new Response(Bun.gzipSync(cache.body), {
|
||||
headers: {
|
||||
"content-type": cache.headers["content-type"],
|
||||
"content-encoding": "gzip",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return new Response(cache.body, {
|
||||
headers: {
|
||||
"content-type": cache.headers["content-type"],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
let f: Response = null as any;
|
||||
if (pathname?.startsWith("/s/")) {
|
||||
f = await fetch(`https://fonts.gstatic.com${pathname}`);
|
||||
} else {
|
||||
f = await fetch(`https://fonts.googleapis.com${pathname}`);
|
||||
}
|
||||
if (f) {
|
||||
const body = await f.text();
|
||||
g._font_cache[pathname] = { body, headers: {} };
|
||||
f.headers.forEach((v, k) => {
|
||||
g._font_cache[pathname].headers[k] = v;
|
||||
});
|
||||
|
||||
res.headers.set("content-type", f.headers.get("content-type") || "");
|
||||
return res;
|
||||
const res = new Response(
|
||||
body.replaceAll("https://fonts.gstatic.com", "/_font")
|
||||
);
|
||||
|
||||
res.headers.set("content-type", f.headers.get("content-type") || "");
|
||||
return res;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { parseFile } from "@swc/core";
|
||||
import { dir } from "dir";
|
||||
import { apiContext } from "service-srv";
|
||||
import { validate } from "uuid";
|
||||
import { prodIndex } from "../util/prod-index";
|
||||
import { gzipAsync } from "../ws/sync/entity/zlib";
|
||||
import { code } from "../ws/sync/code/code";
|
||||
import { initFrontEnd } from "../ws/sync/code/parts/init/frontend";
|
||||
import { gzipAsync } from "../ws/sync/entity/zlib";
|
||||
import { visit } from "woodpile";
|
||||
import { parseTypeDef } from "../util/parse-type-def";
|
||||
import { Glob, build } from "bun";
|
||||
import { removeAsync } from "fs-jetpack";
|
||||
|
||||
export const _ = {
|
||||
url: "/prod/:site_id/**",
|
||||
|
|
@ -25,16 +30,85 @@ export const _ = {
|
|||
const action = pathname.split("/")[1];
|
||||
|
||||
switch (action) {
|
||||
case "code": {
|
||||
const arr = pathname.split("/").slice(2);
|
||||
const codepath = arr.join("/");
|
||||
const build_path = code.path(site_id, "site", "build", codepath);
|
||||
case "type_def": {
|
||||
const path = dir.data(`/code/${site_id}/site/typings.d.ts`);
|
||||
const file = Bun.file(path);
|
||||
if (await file.exists()) {
|
||||
const glob = new Glob("type_def*");
|
||||
for await (const item of glob.scan(
|
||||
dir.data(`/code/${site_id}/site`)
|
||||
)) {
|
||||
const stamp = parseInt(item.split(".")[1]);
|
||||
if (file.lastModified !== stamp) {
|
||||
await removeAsync(dir.data(`/code/${site_id}/site/${item}`));
|
||||
} else {
|
||||
return new Response(
|
||||
Bun.gzipSync(
|
||||
await Bun.file(
|
||||
dir.data(`/code/${site_id}/site/${item}`)
|
||||
).arrayBuffer()
|
||||
),
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"content-encoding": "gzip",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const res = JSON.stringify(await parseTypeDef(path));
|
||||
await Bun.write(
|
||||
dir.data(
|
||||
`/code/${site_id}/site/type_def.${file.lastModified}.json`
|
||||
),
|
||||
res
|
||||
);
|
||||
|
||||
return new Response(Bun.gzipSync(res), {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"content-encoding": "gzip",
|
||||
},
|
||||
});
|
||||
}
|
||||
return new Response("{}", {
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}
|
||||
case "typings.d.ts": {
|
||||
const build_path = dir.data(`/code/${site_id}/site/typings.d.ts`);
|
||||
const file = Bun.file(build_path);
|
||||
|
||||
if (!(await file.exists())) {
|
||||
const root = `/code/${site_id}/site/src`;
|
||||
await initFrontEnd(root, site_id);
|
||||
return new Response("", { status: 403 });
|
||||
}
|
||||
const body = Bun.gzipSync(await file.arrayBuffer());
|
||||
|
||||
return new Response(body, {
|
||||
headers: { "content-type": file.type, "content-encoding": "gzip" },
|
||||
});
|
||||
}
|
||||
case "code": {
|
||||
const arr = pathname.split("/").slice(2);
|
||||
const codepath = arr.join("/");
|
||||
const build_path = code.path(site_id, "site", "build", codepath);
|
||||
let file = Bun.file(build_path);
|
||||
|
||||
if (!(await file.exists())) {
|
||||
const root = `/code/${site_id}/site/src`;
|
||||
await initFrontEnd(root, site_id, true);
|
||||
await new Promise<void>((resolve) => {
|
||||
const ival = setInterval(async () => {
|
||||
file = Bun.file(build_path);
|
||||
if (await file.exists()) {
|
||||
clearInterval(ival);
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
const body = Bun.gzipSync(await file.arrayBuffer());
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { apiContext } from "service-srv";
|
|||
import { code } from "../ws/sync/code/code";
|
||||
import { initFrontEnd } from "../ws/sync/code/parts/init/frontend";
|
||||
import { initServer } from "../ws/sync/code/parts/init/server";
|
||||
import { initTypings } from "../ws/sync/code/parts/init/typings";
|
||||
|
||||
export const _ = {
|
||||
url: "/rebuild/:id_site",
|
||||
|
|
@ -13,6 +14,7 @@ export const _ = {
|
|||
delete server[id_site];
|
||||
await initFrontEnd(root, id_site, true);
|
||||
await initServer(root, id_site, true);
|
||||
await initTypings(root, id_site, true);
|
||||
|
||||
return "ok";
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -34,10 +34,13 @@ glb.server_hook = async (arg) => {
|
|||
if (arr.length >= 3 && validate(site_id)) {
|
||||
try {
|
||||
if (!g.server_runtime[site_id]) {
|
||||
await g.createServerRuntime(site_id);
|
||||
if (g.server_runtime[site_id] !== null) {
|
||||
await g.createServerRuntime(site_id);
|
||||
}
|
||||
}
|
||||
|
||||
const res = await server.http(site_id, arg);
|
||||
|
||||
if (res instanceof Response) {
|
||||
return res;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import { parseFile, TsModuleDeclaration } from "@swc/core";
|
||||
import { visit } from "woodpile";
|
||||
|
||||
type SingleExport = {
|
||||
type: "all" | "named" | "default";
|
||||
kind: "const" | "type";
|
||||
val: string;
|
||||
};
|
||||
export const parseTypeDef = async (path: string) => {
|
||||
const ast = await parseFile(path, { syntax: "typescript" });
|
||||
|
||||
const exports = {} as Record<string, SingleExport[]>;
|
||||
|
||||
visit(ast, {
|
||||
visitWithPath: {
|
||||
visitDecl(node, path) {
|
||||
const t = node as TsModuleDeclaration;
|
||||
if (t.type === "TsModuleDeclaration") {
|
||||
if (t.body) {
|
||||
exports[t.id.value] = [];
|
||||
|
||||
if (Array.isArray(t.body.body)) {
|
||||
for (const body of t.body.body) {
|
||||
if (body.type === "ExportAllDeclaration") {
|
||||
exports[t.id.value].push({
|
||||
type: "all",
|
||||
kind: "const",
|
||||
val: body.source.value,
|
||||
});
|
||||
} else if (body.type === "ExportDeclaration") {
|
||||
if (body.declaration.type === "FunctionDeclaration") {
|
||||
exports[t.id.value].push({
|
||||
type: "named",
|
||||
kind: "const",
|
||||
val: body.declaration.identifier.value,
|
||||
});
|
||||
} else if (body.declaration.type === "VariableDeclaration") {
|
||||
for (const dec of body.declaration.declarations) {
|
||||
if (dec.type === "VariableDeclarator") {
|
||||
const id = dec.id as unknown as Map<string, any>;
|
||||
if (id.get("type") === "Identifier") {
|
||||
exports[t.id.value].push({
|
||||
type: "named",
|
||||
kind: "const",
|
||||
val: id.get("value"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
body.declaration.type === "TsTypeAliasDeclaration"
|
||||
) {
|
||||
if (body.declaration.id.type === "Identifier") {
|
||||
exports[t.id.value].push({
|
||||
type: "named",
|
||||
kind: "type",
|
||||
val: body.declaration.id.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (body.type === "ExportNamedDeclaration") {
|
||||
for (const s of body.specifiers) {
|
||||
if (s.type === "ExportSpecifier") {
|
||||
if (s.exported) {
|
||||
exports[t.id.value].push({
|
||||
type: "named",
|
||||
kind: "const",
|
||||
val: s.exported.value,
|
||||
});
|
||||
} else if (s.orig) {
|
||||
exports[t.id.value].push({
|
||||
type: "named",
|
||||
kind: "const",
|
||||
val: s.orig.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = {} as Record<string, "const" | "type">;
|
||||
const traverse = (items: SingleExport[]) => {
|
||||
for (const item of items) {
|
||||
if (item.type === "all") {
|
||||
const found = exports[item.val];
|
||||
traverse(found);
|
||||
} else {
|
||||
result[item.val] = item.kind;
|
||||
}
|
||||
}
|
||||
};
|
||||
traverse(exports.index);
|
||||
return result;
|
||||
};
|
||||
|
|
@ -4,6 +4,7 @@ import { initServer } from "./parts/init/server";
|
|||
import { codeInternal } from "./parts/internal";
|
||||
import { ensureFiles } from "./utlis/ensure-files";
|
||||
import { ensureLib } from "./utlis/ensure-lib";
|
||||
import { initTypings } from "./parts/init/typings";
|
||||
|
||||
export const code = {
|
||||
internal: codeInternal,
|
||||
|
|
@ -15,6 +16,7 @@ export const code = {
|
|||
|
||||
await initFrontEnd(root, id_site);
|
||||
await initServer(root, id_site);
|
||||
await initTypings(root, id_site);
|
||||
},
|
||||
path(
|
||||
id_site: string,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { cleanPlugin } from "esbuild-clean-plugin";
|
|||
import isEqual from "lodash.isequal";
|
||||
import { appendFile } from "node:fs/promises";
|
||||
import { code } from "../../code";
|
||||
import { buildTypes } from "./typings";
|
||||
|
||||
const decoder = new TextDecoder();
|
||||
export const initFrontEnd = async (
|
||||
root: string,
|
||||
|
|
@ -74,7 +74,6 @@ export const initFrontEnd = async (
|
|||
await installDeps(root, res, id_site);
|
||||
} else {
|
||||
await codeError(id_site, "");
|
||||
await buildTypes(root, id_site);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,32 @@
|
|||
import { dir } from "dir";
|
||||
import { code } from "../../code";
|
||||
|
||||
export const buildTypes = async (root: string, id_site: string) => {
|
||||
// console.log(root);
|
||||
export const initTypings = async (
|
||||
root: string,
|
||||
id_site: string,
|
||||
force?: boolean
|
||||
) => {
|
||||
let existing = code.internal.typings[id_site];
|
||||
if (existing) {
|
||||
if (force) {
|
||||
existing.kill();
|
||||
await existing.exited;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
code.internal.typings[id_site] = Bun.spawn({
|
||||
cmd: [
|
||||
...`tsc --watch --moduleResolution node --emitDeclarationOnly --outFile ../typings.d.ts --declaration --noEmit false`.split(
|
||||
" "
|
||||
),
|
||||
],
|
||||
cwd: dir.data(`/code/${id_site}/site/src`),
|
||||
stdio: ["ignore", "ignore", "ignore"],
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ if (!g.server_main_handler) {
|
|||
}
|
||||
|
||||
const serverMain = () => ({
|
||||
handler: g.server_main_handler as Record<string, PrasiServer>,
|
||||
handler: g.server_main_handler as Record<string, null | PrasiServer>,
|
||||
init_timeout: null as any,
|
||||
ws(action: keyof WebSocketHandler<WSData>, ...arg: any[]) {
|
||||
const id = arg[0].data.site_id;
|
||||
if (this.handler[id]) {
|
||||
const handler = this.handler[id].ws;
|
||||
const handler = this.handler[id]?.ws;
|
||||
|
||||
if (handler) {
|
||||
const fn = handler[action] as any;
|
||||
|
|
@ -30,49 +30,47 @@ const serverMain = () => ({
|
|||
}
|
||||
}
|
||||
},
|
||||
init(site_id: string) {
|
||||
clearTimeout(this.init_timeout);
|
||||
this.init_timeout = setTimeout(async () => {
|
||||
const server_src_path = code.path(site_id, "server", "build", "index.js");
|
||||
const file = Bun.file(server_src_path);
|
||||
if (!this.handler[site_id] && (await file.exists()) && file.length) {
|
||||
try {
|
||||
delete require.cache[server_src_path];
|
||||
const svr = require(server_src_path);
|
||||
if (svr && typeof svr.server === "object") {
|
||||
this.handler[site_id] = svr.server;
|
||||
this.handler[site_id].site_id = site_id;
|
||||
if (typeof svr.server.init === "function") {
|
||||
svr.server.init({});
|
||||
}
|
||||
Bun.write(
|
||||
Bun.file(code.path(site_id, "site", "src", "server.log")),
|
||||
""
|
||||
);
|
||||
} else {
|
||||
const file = await Bun.file(server_src_path).text();
|
||||
const log_path = code.path(site_id, "site", "src", "server.log");
|
||||
if (file.length === 0) {
|
||||
await Bun.write(Bun.file(log_path), "server.ts is empty");
|
||||
} else {
|
||||
await Bun.write(
|
||||
Bun.file(log_path),
|
||||
"server.ts does not return server object"
|
||||
);
|
||||
}
|
||||
async init(site_id: string) {
|
||||
this.handler[site_id] = null;
|
||||
const server_src_path = code.path(site_id, "server", "build", "index.js");
|
||||
const file = Bun.file(server_src_path);
|
||||
if (!this.handler[site_id] && (await file.exists()) && file.length) {
|
||||
try {
|
||||
delete require.cache[server_src_path];
|
||||
const svr = require(server_src_path);
|
||||
if (svr && typeof svr.server === "object") {
|
||||
this.handler[site_id] = svr.server;
|
||||
svr.server.site_id = site_id;
|
||||
if (typeof svr.server.init === "function") {
|
||||
svr.server.init({});
|
||||
}
|
||||
} catch (e: any) {
|
||||
Bun.write(
|
||||
Bun.file(code.path(site_id, "site", "src", "server.log")),
|
||||
""
|
||||
);
|
||||
} else {
|
||||
const file = await Bun.file(server_src_path).text();
|
||||
const log_path = code.path(site_id, "site", "src", "server.log");
|
||||
if (file.length === 0) {
|
||||
await Bun.write(Bun.file(log_path), "server.ts is empty");
|
||||
} else {
|
||||
await Bun.write(Bun.file(log_path), e.message);
|
||||
console.log(`Failed to init server ${site_id}\n`, log_path);
|
||||
await Bun.write(
|
||||
Bun.file(log_path),
|
||||
"server.ts does not return server object"
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
const file = await Bun.file(server_src_path).text();
|
||||
const log_path = code.path(site_id, "site", "src", "server.log");
|
||||
if (file.length === 0) {
|
||||
await Bun.write(Bun.file(log_path), "server.ts is empty");
|
||||
} else {
|
||||
await Bun.write(Bun.file(log_path), e.message);
|
||||
console.log(`Failed to init server ${site_id}\n`, log_path);
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
async http(
|
||||
site_id: string,
|
||||
|
|
@ -81,14 +79,15 @@ const serverMain = () => ({
|
|||
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"))
|
||||
) {
|
||||
this.init(site_id);
|
||||
await waitUntil(200);
|
||||
await this.init(site_id);
|
||||
}
|
||||
}
|
||||
|
||||
const handler = this.handler[site_id];
|
||||
|
||||
if (handler) {
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ if (!g.createServerRuntime) {
|
|||
db: dbProxy((site.config as any).api_url),
|
||||
api: null as any,
|
||||
};
|
||||
} catch (e) { }
|
||||
} catch (e) {
|
||||
g.server_runtime[site_id] = null;
|
||||
}
|
||||
} else {
|
||||
g.server_runtime[site_id] = { db: null as any, api: null }
|
||||
g.server_runtime[site_id] = { db: null as any, api: null };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@
|
|||
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>Prasi: App Builder</title>
|
||||
<link rel="stylesheet" href="/index.css">
|
||||
<script>window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
|
||||
<style>
|
||||
@import url('/_font/css2?family=Source+Sans+3:wght@400;600&display=swap');
|
||||
@import url('/_font/css2?family=JetBrains+Mono&display=swap');
|
||||
</style>
|
||||
<script>
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
|
||||
isDisabled: true,
|
||||
_renderers: {}
|
||||
};</script>
|
||||
|
|
|
|||
|
|
@ -1,50 +1,46 @@
|
|||
@import url('https://prasi.avolut.com/_font/css2?family=Source+Sans+3:wght@400;600&display=swap');
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import url('https://prasi.avolut.com/_font/css2?family=JetBrains+Mono&display=swap');
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
overscroll-behavior-y: none;
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
body {
|
||||
font-family: "Source Sans 3", system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
overscroll-behavior-y: none;
|
||||
}
|
||||
.JsxText {
|
||||
color: #5c6773;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Source Sans 3", system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
.JsxSelfClosingElement,
|
||||
.JsxOpeningElement,
|
||||
.JsxClosingElement,
|
||||
.tagName-of-JsxOpeningElement,
|
||||
.tagName-of-JsxClosingElement,
|
||||
.tagName-of-JsxSelfClosingElement {
|
||||
color: #41a6d9;
|
||||
}
|
||||
|
||||
.JsxText {
|
||||
color: #5c6773;
|
||||
}
|
||||
.name-of-JsxAttribute {
|
||||
color: #f08c36;
|
||||
}
|
||||
|
||||
.JsxSelfClosingElement,
|
||||
.JsxOpeningElement,
|
||||
.JsxClosingElement,
|
||||
.tagName-of-JsxOpeningElement,
|
||||
.tagName-of-JsxClosingElement,
|
||||
.tagName-of-JsxSelfClosingElement {
|
||||
color: #41a6d9;
|
||||
}
|
||||
.name-of-PropertyAssignment {
|
||||
color: #86b300;
|
||||
}
|
||||
|
||||
.name-of-JsxAttribute {
|
||||
color: #f08c36;
|
||||
}
|
||||
|
||||
.name-of-PropertyAssignment {
|
||||
color: #86b300;
|
||||
}
|
||||
|
||||
.name-of-PropertyAccessExpression {
|
||||
color: #f08c36;
|
||||
}
|
||||
.name-of-PropertyAccessExpression {
|
||||
color: #f08c36;
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { useGlobal } from "web-utils";
|
||||
import { jscript } from "../../utils/script/jscript";
|
||||
import { Loading } from "../../utils/ui/loading";
|
||||
import { EdLeft } from "./ed-left";
|
||||
import { EdMid } from "./ed-mid";
|
||||
|
|
@ -8,6 +9,7 @@ import { edInit } from "./logic/ed-init";
|
|||
import { edRoute } from "./logic/ed-route";
|
||||
import { edUndoManager } from "./logic/ed-undo";
|
||||
import { EdMain } from "./panel/main/main";
|
||||
import { EdPageHistoryMain } from "./panel/main/main-history";
|
||||
import { EdPane } from "./panel/main/pane-resize";
|
||||
import { EdPopApi } from "./panel/popup/api/api-server";
|
||||
import { EdPopCode } from "./panel/popup/code/code";
|
||||
|
|
@ -16,9 +18,6 @@ import { EdPopComp } from "./panel/popup/comp/comp-popup";
|
|||
import { EdPopPage } from "./panel/popup/page/page-popup";
|
||||
import { EdPopScript } from "./panel/popup/script/pop-script";
|
||||
import { EdPopSite } from "./panel/popup/site/site-popup";
|
||||
import { EdPageHistoryMain } from "./panel/main/main-history";
|
||||
import { jscript } from "../../utils/script/jscript";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const EdBase = () => {
|
||||
const p = useGlobal(EDGlobal, "EDITOR");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
export const loadCode = async (id_site: string, ts?: number) => {
|
||||
import { PG } from "./ed-global";
|
||||
|
||||
export const loadCode = async (p: PG, ts?: number) => {
|
||||
const id_site = p.site.id;
|
||||
const url = `/prod/${id_site}/_prasi/code/index.js?ts=${ts}`;
|
||||
const fn = new Function(
|
||||
"callback",
|
||||
|
|
@ -8,9 +11,24 @@ import("${url}")
|
|||
.then(callback)`
|
||||
);
|
||||
try {
|
||||
fetch(`/prod/${id_site}/_prasi/typings.d.ts`)
|
||||
.catch(() => {})
|
||||
.then(async (res) => {
|
||||
if (res) {
|
||||
p.site_dts = await res.text();
|
||||
p.render();
|
||||
}
|
||||
});
|
||||
|
||||
return await new Promise<any>((resolve) => {
|
||||
try {
|
||||
fn((exports: any) => {
|
||||
const w = window as any;
|
||||
|
||||
for (const [k, v] of Object.entries(exports)) {
|
||||
w[k] = v;
|
||||
p.site_exports[k] = v;
|
||||
}
|
||||
resolve(exports);
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
@ -20,5 +38,6 @@ import("${url}")
|
|||
} catch (e) {
|
||||
console.log("Failed to load site code", e);
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import { ESite, PG } from "./ed-global";
|
|||
export const loadSite = async (p: PG, site: ESite, note: string) => {
|
||||
p.site = site;
|
||||
|
||||
|
||||
|
||||
if (!p.script.db && !p.script.api) {
|
||||
if (!location.pathname.startsWith("/ed/")) {
|
||||
await viLoadLegacy({
|
||||
|
|
|
|||
|
|
@ -184,13 +184,7 @@ export const edInitSync = (p: PG) => {
|
|||
p.render();
|
||||
},
|
||||
async code_changes({ ts }) {
|
||||
const w = window as any;
|
||||
|
||||
const exports = await loadCode(p.site.id, ts);
|
||||
for (const [k, v] of Object.entries(exports)) {
|
||||
w[k] = v;
|
||||
p.site_exports[k] = v;
|
||||
}
|
||||
await loadCode(p, ts);
|
||||
await treeRebuild(p);
|
||||
p.render();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ export const EdScriptMonaco: FC<{}> = () => {
|
|||
if (p.ui.popup.script.mode === "js") {
|
||||
const w = window as any;
|
||||
const types: any = {};
|
||||
const values: any = {};
|
||||
for (const prop_name of p.global_prop) {
|
||||
if (prop_name === "_types") continue;
|
||||
types[prop_name] = "any";
|
||||
|
|
@ -110,10 +109,6 @@ export const EdScriptMonaco: FC<{}> = () => {
|
|||
}
|
||||
}
|
||||
|
||||
for (const [k, v] of Object.entries(p.site_exports)) {
|
||||
values[k] = v;
|
||||
}
|
||||
|
||||
let component = { id: "", props: {} as Record<string, FNCompDef> };
|
||||
if (meta?.item.component?.id && meta.item.component.props) {
|
||||
component.id = meta.item.component.id;
|
||||
|
|
@ -185,6 +180,7 @@ export const EdScriptMonaco: FC<{}> = () => {
|
|||
await monacoTypings(
|
||||
{
|
||||
site_dts: p.site_dts,
|
||||
site_exports: p.site_exports,
|
||||
script: {
|
||||
siteTypes: p.script.site_types,
|
||||
},
|
||||
|
|
@ -193,7 +189,7 @@ export const EdScriptMonaco: FC<{}> = () => {
|
|||
monaco,
|
||||
{
|
||||
types,
|
||||
values,
|
||||
values: {},
|
||||
}
|
||||
);
|
||||
await jsMount(editor, monaco, p);
|
||||
|
|
|
|||
|
|
@ -17,30 +17,6 @@ export const viLoadSnapshot = async (p: PG) => {
|
|||
if (api_url && apiURL.hostname) {
|
||||
await loadApiProxyDef(api_url, true);
|
||||
|
||||
// const api = w.prasiApi[api_url];
|
||||
// if (api && api.apiTypes && api.prismaTypes) {
|
||||
// const zip = JSON.stringify({
|
||||
// api: api.apiTypes,
|
||||
// prisma: api.prismaTypes,
|
||||
// });
|
||||
|
||||
// const hash = simpleHash(zip);
|
||||
// const res = await p.sync?.code.action({
|
||||
// type: "check-typings",
|
||||
// site_id: p.site.id,
|
||||
// hash,
|
||||
// });
|
||||
// if (res?.type === "check-typings" && !res.hash) {
|
||||
// const body = Buffer.from(compress(encoder.encode(zip)));
|
||||
// p.sync?.code.action({
|
||||
// type: "push-typings",
|
||||
// site_id: p.site.id,
|
||||
// body,
|
||||
// hash,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
if (!p.script.db) p.script.db = dbProxy(api_url);
|
||||
if (!p.script.api) p.script.api = apiProxy(api_url);
|
||||
}
|
||||
|
|
@ -48,7 +24,6 @@ export const viLoadSnapshot = async (p: PG) => {
|
|||
if (e && !e.message.toLowerCase().includes("invalid url")) {
|
||||
console.warn("Failed to load API [Snapshot]:", api_url);
|
||||
} else {
|
||||
// console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,5 +38,5 @@ export const applyEnv = async (p: PG) => {
|
|||
w.api = apiProxy(p.site.config.api_url);
|
||||
}
|
||||
|
||||
await loadCode(p.site.id, p.site_tstamp);
|
||||
await loadCode(p, p.site_tstamp);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const cssFont = (
|
|||
if (glbFont.loadedFonts.indexOf(font.family) < 0) {
|
||||
glbFont.loadedFonts.push(font.family);
|
||||
const doc = document;
|
||||
const _href = `https://prasi.avolut.com/_font/css2?family=${fontName}${weight}`;
|
||||
const _href = `/_font/css2?family=${fontName}${weight}`;
|
||||
if (!doc.querySelector(`link[href="${_href}]`)) {
|
||||
const link = doc.createElement("link");
|
||||
link.type = "text/css";
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import type { OnMount } from "@monaco-editor/react";
|
||||
import { w } from "../types/general";
|
||||
import { prismaExtendType } from "./prisma-extend";
|
||||
import { baseTypings } from "./types/base";
|
||||
import { extractProp } from "./types/prop";
|
||||
import { prismaExtendType } from "./prisma-extend";
|
||||
import { propPopover } from "../../nova/ed/panel/side/prop-master/prop-form";
|
||||
export type MonacoEditor = Parameters<OnMount>[0];
|
||||
type Monaco = Parameters<OnMount>[1];
|
||||
|
||||
|
|
@ -13,34 +12,33 @@ export const monacoTypings = async (
|
|||
p: {
|
||||
site_dts: string;
|
||||
site: { api_url: string };
|
||||
site_exports: Record<string, any>;
|
||||
script: { siteTypes: Record<string, string> };
|
||||
},
|
||||
monaco: Monaco,
|
||||
prop: { values: Record<string, any>; types: Record<string, string> }
|
||||
) => {
|
||||
register(
|
||||
monaco,
|
||||
`
|
||||
declare module "momo" {
|
||||
export type MO = "123";
|
||||
export const MUU = "123";
|
||||
}
|
||||
`,
|
||||
"ts: momo.d.ts"
|
||||
);
|
||||
|
||||
register(
|
||||
monaco,
|
||||
`
|
||||
declare global {
|
||||
import * as _ from "momo"
|
||||
const MUU = _.MUU;
|
||||
}
|
||||
export {}
|
||||
`,
|
||||
"ts: coba.d.ts"
|
||||
);
|
||||
|
||||
if (p.site_dts) {
|
||||
register(monaco, p.site_dts, "ts: site.d.ts");
|
||||
register(
|
||||
monaco,
|
||||
`
|
||||
declare global {
|
||||
import * as _ from "index"
|
||||
type MOKA = _.MOKA;
|
||||
|
||||
${Object.keys(p.site_exports)
|
||||
.map((v) => {
|
||||
return `
|
||||
const ${v} = _.${v};`;
|
||||
})
|
||||
.join("\n")}
|
||||
}
|
||||
export {}
|
||||
`,
|
||||
"ts: active_global.d.ts"
|
||||
);
|
||||
}
|
||||
|
||||
if (!map.has(prop.values)) {
|
||||
map.set(prop.values, true);
|
||||
|
|
@ -107,10 +105,6 @@ declare module "ts:prisma" {
|
|||
"https://cdn.jsdelivr.net/npm/@types/react@18.2.0/jsx-runtime.d.ts"
|
||||
),
|
||||
},
|
||||
{
|
||||
filePath: "site.d.ts",
|
||||
content: p.site_dts.replaceAll("export declare const", "declare const"),
|
||||
},
|
||||
]);
|
||||
|
||||
const propText = extractProp({
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@surfy/multipart-parser": "^1.0.2",
|
||||
"@swc/core": "^1.3.95",
|
||||
"@swc/core": "^1.4.17",
|
||||
"woodpile": "^0.0.5",
|
||||
"@types/mime": "^3.0.3",
|
||||
"@types/unzipper": "^0.10.8",
|
||||
"esbuild": "^0.20.2",
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ export const cache = {
|
|||
|
||||
export type WSData = { url: URL };
|
||||
|
||||
export const createServer = async () => {
|
||||
await serveAPI.init();
|
||||
export const createServer = async () => {
|
||||
await serveAPI.init();
|
||||
await serveStatic.init();
|
||||
const { wsHandler } = await import("../../../app/srv/ws/handler");
|
||||
|
||||
|
|
@ -28,6 +28,7 @@ export const createServer = async () => {
|
|||
async fetch(req, server) {
|
||||
const url = new URL(req.url) as URL;
|
||||
const prasi = {};
|
||||
|
||||
const handle = async (req: Request) => {
|
||||
if (wsHandler[url.pathname]) {
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -18,15 +18,25 @@ const web = {
|
|||
else return "static";
|
||||
},
|
||||
};
|
||||
|
||||
if (!g.static_cache) {
|
||||
g.static_cache = {};
|
||||
}
|
||||
|
||||
const cache = {
|
||||
static: {} as Record<
|
||||
static: g.static_cache as Record<
|
||||
string,
|
||||
{ type: string; content: any; compression: "" | "br" }
|
||||
>,
|
||||
};
|
||||
|
||||
export const serveStatic: any = {
|
||||
export const serveStatic = {
|
||||
async init() {
|
||||
if (g.mode === "dev") {
|
||||
for (const k of Object.keys(cache.static)) {
|
||||
delete cache.static[k];
|
||||
}
|
||||
}
|
||||
await this.walk();
|
||||
if (g.mode === "dev") {
|
||||
watch(dir.path(`app/static`), async (_, filename) => {
|
||||
|
|
@ -42,7 +52,7 @@ export const serveStatic: any = {
|
|||
};
|
||||
}
|
||||
} catch (e: any) {
|
||||
cache.static = {}
|
||||
cache.static = {};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -89,11 +99,12 @@ export const serveStatic: any = {
|
|||
});
|
||||
}
|
||||
|
||||
if (g.mode === 'dev' && url.pathname.endsWith('.js')) {
|
||||
if (g.mode === "dev" && url.pathname.endsWith(".js")) {
|
||||
await this.walk();
|
||||
}
|
||||
|
||||
file = cache.static["/index.html"];
|
||||
|
||||
if (file) {
|
||||
return new Response(file.content, {
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export const g = global as unknown as {
|
|||
}) => Promise<Response | undefined>;
|
||||
server_runtime: Record<
|
||||
string,
|
||||
{
|
||||
null | {
|
||||
api: ReturnType<typeof apiProxy>;
|
||||
db: ReturnType<typeof dbProxy>;
|
||||
}
|
||||
|
|
@ -56,4 +56,5 @@ export const g = global as unknown as {
|
|||
apiPrepared: boolean;
|
||||
Y: typeof Y;
|
||||
syncronize: typeof syncronize;
|
||||
static_cache: any;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue