checkpoint

This commit is contained in:
Rizky 2024-05-07 00:27:29 +07:00
parent 0c96971a8f
commit 2af0e9932e
27 changed files with 426 additions and 193 deletions

View File

@ -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 {

View File

@ -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;
}
},
};

View File

@ -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());

View File

@ -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

View File

@ -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 {

View File

@ -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;
};

View File

@ -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,

View File

@ -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) {

View File

@ -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);
}
};

View File

@ -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) {

View File

@ -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 };
}
}
};

View File

@ -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>

View File

@ -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;
}

View File

@ -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");

View File

@ -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 {};
};

View File

@ -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({

View File

@ -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();
},

View File

@ -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);

View File

@ -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);
};

View File

@ -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";

View File

@ -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({

BIN
bun.lockb

Binary file not shown.

View File

@ -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",

View File

@ -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 (

View File

@ -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: {

View File

@ -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;
};