From bfcbb0f7a8f739575cf903399e65e876371d6ba5 Mon Sep 17 00:00:00 2001 From: Rizky Date: Sat, 14 Oct 2023 21:32:41 +0700 Subject: [PATCH] fix prasi --- app/srv/api/npm.ts | 83 ++++++++++++++++++ app/srv/exports.d.ts | 37 +++++++- app/srv/exports.ts | 16 ++-- app/srv/global.ts | 26 ++++++ app/web/src/base/page/all.tsx | 9 +- app/web/src/base/page/auth/login.tsx | 6 +- app/web/src/base/page/editor.tsx | 8 +- app/web/src/base/pages.ts | 5 ++ app/web/src/base/root.tsx | 18 ++-- app/web/src/index.tsx | 4 +- app/web/src/render/editor/logic/global.ts | 2 +- .../editor/panel/script/monaco/monaco-el.tsx | 2 +- .../editor/panel/script/monaco/mount.tsx | 2 +- app/web/src/utils/types/general.ts | 5 +- app/web/tsconfig.json | 5 ++ bun.lockb | Bin 280588 -> 280992 bytes package.json | 2 +- pkgs/core/api/_file.ts | 6 +- pkgs/core/api/_prasi.ts | 10 +-- pkgs/core/api/_upload.ts | 2 +- pkgs/core/api/_web.ts | 79 ----------------- pkgs/core/server/api-ctx.ts | 2 + pkgs/core/server/api-scan.ts | 6 +- pkgs/core/server/create.ts | 13 ++- pkgs/core/server/prep-api-ts.ts | 10 +-- pkgs/core/upgrade.ts | 6 +- pkgs/core/utils/config.ts | 8 +- pkgs/core/utils/dev-watcher.ts | 6 +- pkgs/core/utils/dir.ts | 6 +- pkgs/core/utils/parcel.ts | 12 +-- pkgs/core/utils/prisma.ts | 6 +- pkgs/core/utils/session.ts | 2 +- tsconfig.json | 3 + 33 files changed, 253 insertions(+), 154 deletions(-) create mode 100644 app/srv/api/npm.ts create mode 100644 app/srv/global.ts delete mode 100644 pkgs/core/api/_web.ts diff --git a/app/srv/api/npm.ts b/app/srv/api/npm.ts new file mode 100644 index 00000000..32384d81 --- /dev/null +++ b/app/srv/api/npm.ts @@ -0,0 +1,83 @@ +import crypto from "crypto"; +import { dir } from "dir"; +import { readAsync } from "fs-jetpack"; +import mime from "mime-types"; +import { apiContext } from "service-srv"; +import { glb } from "../global"; + +export const _ = { + url: "/npm/:mode/:id/*", + async api(mode: "site" | "page", id: string) { + const { req, res, mode: _mode } = apiContext(this); + let path = dir.path(`../npm/${mode}/${id}/${req.params._}`); + + res.setHeader("Access-Control-Allow-Origin", "*"); + + if (!glb.npm) { + glb.npm = { page: {}, site: {} }; + } + + const contentType = mime.lookup(path); + if (contentType) res.setHeader("content-type", contentType); + + if (path.endsWith(`${mode}.js`)) { + path = path.substring(0, path.length - `${mode}.js`.length) + `index.js`; + + if (glb.npm[mode][id]) { + const npm = glb.npm[mode][id]; + if (npm) { + res.setHeader("etag", npm.etag); + res.setHeader("content-length", npm.file.byteLength.toString()); + + if (npm.etag === req.headers.get("if-none-match")) { + res.sendStatus(304); + return; + } + + res.send(npm.file); + + readAsync(path, "buffer").then((file) => { + if (file && path.endsWith("index.js")) { + glb.npm[mode][id] = { + file, + etag: crypto.createHash("md5").update(file).digest("hex"), + }; + } + }); + return; + } + } + } + + if (path.length > dir.path(`../npm/${mode}/${id}`).length) { + const file = await readAsync(path, "buffer"); + + if (file) { + if (path.endsWith("index.js")) { + glb.npm[mode][id] = { + file, + etag: crypto.createHash("md5").update(file).digest("hex"), + }; + const npm = glb.npm[mode][id]; + if (npm) { + res.setHeader("etag", npm.etag); + + if (npm.etag === req.headers.get("if-none-match")) { + res.sendStatus(304); + return; + } + } + } + + res.setHeader("content-length", file.byteLength.toString()); + res.send(file); + return; + } else { + glb.npm[mode][id] = null; + } + } + res.setHeader("etag", "empty"); + + res.send(""); + }, +}; diff --git a/app/srv/exports.d.ts b/app/srv/exports.d.ts index b8cd9aaa..c6129284 100644 --- a/app/srv/exports.d.ts +++ b/app/srv/exports.d.ts @@ -1,3 +1,4 @@ +/// declare module "api/auth/login" { export const _: { url: string; @@ -18,6 +19,38 @@ declare module "api/session" { api(): Promise; }; } +declare module "global" { + import { site, user } from "dbgen"; + import { ExecaChildProcess } from "execa"; + export const glb: { + lastUpdate: Record; + prasiSrv: { + status: Record; + running: Record; + }; + npm: { + page: Record; + site: Record; + }; + }; + export type Session = { + user: user & { + site: site[]; + }; + }; +} +declare module "api/npm" { + export const _: { + url: string; + api(mode: "site" | "page", id: string): Promise; + }; +} declare module "exports" { export const login: { name: string; @@ -33,12 +66,12 @@ declare module "exports" { args: any[]; handler: Promise; }; - export const _web: { + export const npm: { name: string; url: string; path: string; args: string[]; - handler: Promise; + handler: Promise; }; export const _upload: { name: string; diff --git a/app/srv/exports.ts b/app/srv/exports.ts index 1522ea0e..aeef854d 100644 --- a/app/srv/exports.ts +++ b/app/srv/exports.ts @@ -12,12 +12,12 @@ export const session = { args: [], handler: import("./api/session") } -export const _web = { - name: "_web", - url: "/_web/:id/**", - path: "app/srv/api/_web.ts", - args: ["id","_"], - handler: import("./api/_web") +export const npm = { + name: "npm", + url: "/npm/:mode/:id/*", + path: "app/srv/api/npm.ts", + args: ["mode","id"], + handler: import("./api/npm") } export const _upload = { name: "_upload", @@ -28,14 +28,14 @@ export const _upload = { } export const _prasi = { name: "_prasi", - url: "/_prasi/**", + url: "/_prasi/*", path: "app/srv/api/_prasi.ts", args: [], handler: import("./api/_prasi") } export const _file = { name: "_file", - url: "/_file/**", + url: "/_file/*", path: "app/srv/api/_file.ts", args: [], handler: import("./api/_file") diff --git a/app/srv/global.ts b/app/srv/global.ts new file mode 100644 index 00000000..229d4065 --- /dev/null +++ b/app/srv/global.ts @@ -0,0 +1,26 @@ +import { site, user } from "dbgen"; +import { ExecaChildProcess } from "execa"; + +export const glb = global as unknown as { + lastUpdate: Record; + prasiSrv: { + status: Record< + string, + | "unavailable" + | "installing" + | "starting" + | "started" + | "stopped" + | "destroying" + >; + running: Record; + }; + npm: { + page: Record; + site: Record; + }; +}; + +export type Session = { + user: user & { site: site[] }; +}; diff --git a/app/web/src/base/page/all.tsx b/app/web/src/base/page/all.tsx index d25b2346..c8a38d09 100644 --- a/app/web/src/base/page/all.tsx +++ b/app/web/src/base/page/all.tsx @@ -1,12 +1,17 @@ import { useEffect } from "react"; import { page } from "web-utils"; +import { Loading } from "../../utils/ui/loading"; export default page({ url: "**", component: ({}) => { useEffect(() => { - navigate("/login"); + if (localStorage.getItem("prasi-session")) { + navigate("/editor/_/_"); + } else { + navigate("/login"); + } }, []); - return
Loading...
; + return ; }, }); diff --git a/app/web/src/base/page/auth/login.tsx b/app/web/src/base/page/auth/login.tsx index 47637ead..500e50ee 100644 --- a/app/web/src/base/page/auth/login.tsx +++ b/app/web/src/base/page/auth/login.tsx @@ -21,7 +21,9 @@ export default page({ if (rto) { navigate(rto); } else { - navigate("/editor"); + console.log("navigate to"); + localStorage.setItem("prasi-session", JSON.stringify(s)); + navigate("/editor/_/_"); } } else { form.init = true; @@ -50,7 +52,7 @@ export default page({ if (rto) { navigate(rto); } else { - navigate("/editor"); + navigate("/editor/_/_"); } } }} diff --git a/app/web/src/base/page/editor.tsx b/app/web/src/base/page/editor.tsx index 00323375..90d56ed8 100644 --- a/app/web/src/base/page/editor.tsx +++ b/app/web/src/base/page/editor.tsx @@ -1,7 +1,6 @@ -import { page } from "web-utils"; -import { useLocal } from "web-utils"; -import { Loading } from "../../utils/ui/loading"; import { Suspense, lazy, useEffect } from "react"; +import { page, useLocal } from "web-utils"; +import { Loading } from "../../utils/ui/loading"; const Editor = lazy(async () => ({ default: (await import("../../render/editor/editor")).Editor, @@ -35,7 +34,8 @@ export default page({ let e = await api.session(); if (!e) { (window as any).redirectTo = location.pathname; - navigate("/login"); + console.log("session not found"); + // navigate("/login"); localStorage.removeItem("prasi-session"); } else { localStorage.setItem("prasi-session", JSON.stringify(e)); diff --git a/app/web/src/base/pages.ts b/app/web/src/base/pages.ts index 81a84dca..d6e25181 100644 --- a/app/web/src/base/pages.ts +++ b/app/web/src/base/pages.ts @@ -6,3 +6,8 @@ export const login = { url: "/login", page: () => import("./page/auth/login"), }; + +export const editor = { + url: "/editor/:site_id/:page_id", + page: () => import("./page/editor"), +}; diff --git a/app/web/src/base/root.tsx b/app/web/src/base/root.tsx index afbac143..2c156cbd 100644 --- a/app/web/src/base/root.tsx +++ b/app/web/src/base/root.tsx @@ -2,22 +2,25 @@ import { createRouter } from "radix3"; import { FC, Suspense, lazy } from "react"; import { GlobalContext, useLocal } from "web-utils"; import { Loading } from "../utils/ui/loading"; +import { w } from "../utils/types/general"; export const Root: FC<{}> = ({}) => { const local = useLocal( { - router: createRouter({ strictTrailingSlash: true }), + router: createRouter<{ url: string; Page: FC }>({ + strictTrailingSlash: true, + }), Page: null as any, }, async () => { const pages = await import("./pages"); for (const [_, v] of Object.entries(pages)) { - local.router.insert( - v.url, - lazy(async () => { + local.router.insert(v.url, { + url: v.url, + Page: lazy(async () => { return { default: (await v.page()).default.component as any }; - }) - ); + }), + }); } local.render(); } @@ -28,7 +31,8 @@ export const Root: FC<{}> = ({}) => { const found = local.router.lookup(location.pathname); if (found) { - local.Page = found; + w.params = found.params; + local.Page = found.Page; } if (!local.Page) { diff --git a/app/web/src/index.tsx b/app/web/src/index.tsx index 1263c66b..85507c13 100644 --- a/app/web/src/index.tsx +++ b/app/web/src/index.tsx @@ -3,14 +3,14 @@ import { defineReact, defineWindow } from "web-utils"; import { Root } from "./base/root"; import "./index.css"; import { createAPI, createDB, reloadDBAPI } from "./utils/script/init-api"; +import { w } from "./utils/types/general"; const start = async () => { registerServiceWorker(); defineReact(); await defineWindow(false); - const w = window as any; const base = `${location.protocol}//${location.host}`; - + w.serverurl = base; await reloadDBAPI(base); w.api = createAPI(base); w.db = createDB(base); diff --git a/app/web/src/render/editor/logic/global.ts b/app/web/src/render/editor/logic/global.ts index 34d80dec..7245c962 100644 --- a/app/web/src/render/editor/logic/global.ts +++ b/app/web/src/render/editor/logic/global.ts @@ -1,5 +1,5 @@ import { FC, ReactElement, ReactNode } from "react"; -import { createRouter } from "web-utils"; +import { createRouter } from "radix3"; import { CompDoc } from "../../../base/global/content-editor"; import { IContent, MContent, MPage } from "../../../utils/types/general"; import { IItem, MItem } from "../../../utils/types/item"; diff --git a/app/web/src/render/editor/panel/script/monaco/monaco-el.tsx b/app/web/src/render/editor/panel/script/monaco/monaco-el.tsx index bc7fed90..e4d7d55a 100644 --- a/app/web/src/render/editor/panel/script/monaco/monaco-el.tsx +++ b/app/web/src/render/editor/panel/script/monaco/monaco-el.tsx @@ -91,7 +91,7 @@ export const ScriptMonacoElement: FC<{ } if (!w.importCache.prettier_parser) w.importCache.prettier_parser = await import( - "prettier/parser-typescript" + "prettier/plugins/typescript" ); if (!w.importCache.prettier) diff --git a/app/web/src/render/editor/panel/script/monaco/mount.tsx b/app/web/src/render/editor/panel/script/monaco/mount.tsx index d3a9f32c..14ee8509 100644 --- a/app/web/src/render/editor/panel/script/monaco/mount.tsx +++ b/app/web/src/render/editor/panel/script/monaco/mount.tsx @@ -56,7 +56,7 @@ export const jsMount = async (p: PG, editor: MonacoEditor, monaco: Monaco) => { } if (!w.importCache.prettier_parser) w.importCache.prettier_parser = await import( - "prettier/parser-typescript" + "prettier/plugins/typescript" ); if (!w.importCache.prettier) diff --git a/app/web/src/utils/types/general.ts b/app/web/src/utils/types/general.ts index a5ea9130..efdd1eb8 100644 --- a/app/web/src/utils/types/general.ts +++ b/app/web/src/utils/types/general.ts @@ -1,6 +1,5 @@ import { page as dbpage } from "dbgen"; import { TypedDoc, TypedMap } from "yjs-types"; -import { loadSite } from "../../../../srv/edit/tools/load-site"; import { IItem, MItem } from "./item"; import { IRoot, MRoot } from "./root"; import { ISection, MSection } from "./section"; @@ -31,6 +30,9 @@ export const w = window as unknown as { params: any; editorGlbDefault: string; ts: number; + serverurl: string; + api: any; + db: any; }; export type Page = { @@ -47,7 +49,6 @@ export type MPage = TypedDoc<{ } >; }>; -export type Site = Exclude>, null>; export type IContent = ISection | IItem | IText; export type MContent = MSection | MItem | MText; diff --git a/app/web/tsconfig.json b/app/web/tsconfig.json index f5832eec..283fd92c 100644 --- a/app/web/tsconfig.json +++ b/app/web/tsconfig.json @@ -20,5 +20,10 @@ "isolatedModules": true, // "noEmit": true, "jsx": "react-jsx", + "paths": { + "dbgen": [ + "../../node_modules/.prisma/client/index.d.ts" + ], + } }, } \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 93dd0eedae72c88056cf8e88b857d9a015e6d630..46f913d217cac2a3084c9c6e586b7104bc17a1c5 100755 GIT binary patch delta 53208 zcmeFad7O>)|Nno^#nfD*!B{e5Un-=*Smw+a&e+1pknC#)6N9l0F_mVt8d7nk7a|Eo z(k>J!OBtD@RMcDhLZwnED)qZRuIoC?w|DQppWpX=`z?QTZXWY|J@2o5xn9@nTr=mm zzjg z_ksa+3X-;2uH*fN_z4V8$wcuN^H46x=@WHLv>iA=@DyTgb+Sp{Q8kFe!eWE=+H9Kq6 zG?>9x!<&&<=~wyjW3%$cCgx4g9W!at$n2?sz^J^uY59}01D%OiN19^`st|ac(qpl8 z0Tr=TuqyE3a-M%LRwEGMGqOigZ6I)n#HuiVT%PMs$QjvOfrm(}^70cWPZ~EV5STta zXSDb}(yQDZSas;>ih*WsOBz@93d*~749Nq5t@uhni(Ma^IBjZn_P8oej8(hfDL;B$ zRWIAfNs}gw%*x9iJt=qkw44cfE8xmL?!rKzJa(vWvnNi=nU<5Cr{ZRe&6>8(uXY($ z?Oj8=lzu)o9_tQpVou&I`0D411b1Qz3TF|hRw}_g_>58E$4s9(I1yhXJbL2j#8H!` zW>3u?J$)wq`j&N~3esu@0@PX9iFBHP$KXmoz%Tb&zadkzM(50I83>HWSNTm@7Ucs4 zfx_AZV1-%yP*0;+i0Z-QsoB%$;nc~KCgjh^%FFFUyp~cMta^}$Rl53E6|t@mMt=3#$VA zVO2p7pHItU@i0O|FZPCh^vE&U6Y)o9P0LQaW@27C=~UkShW?seN`TQS?1g1|3m?8D z5MbI1pT=i&3va-x=h;|IRjQw^tZ%Dhb@hHlK9zG2t8`njn){ov7hzlY6_>%P9xj>! zch0_LJT!Nk61|o!!m0sdntCJg7V)~8Z))a^!07CelcrA`l|3F`74`LPSFCzAFv+Xn zEv!bgD^?@d3ab$dV>N=Ktv&xeta|!VvRCc}Aus>4q*p`N7ZA`~=S?3qm8&k$Al0jAa?Vs{ zD=(0H9TUgvBwXpHjm@5zb4`BWOW&`ARnNvunB?vwJ<`02CNVn7H)CqnqJn$|RE8Xi@#gERp<{HK9z*obw zrjBtFZuaA|*tL{(Exy*)V&Be@)%8Eq2Sc!GX=I4=vvMb>q#NsQUb+kYf@85tmzzCxOm+)~+vm0Vcs;!)D{tBq@=wj4o~O3G57!i~= zSA7}(3V>KY!{`aus=h!OzonzbP8y#xI&11RdD+);!^z_&GJ15*)XDYwdky^r8%O@E ziTSx%(?*Sr4E+yWW*TaT-o#_a4fGm546DnIloQ5N&mDspfAyGEnRv~FtTD3(c|+EB zu$OQZRzuznuIoE-h!>xPuQgEe=6@Na^3hcN>s5X(C%epyx1e#5!Qr zkgp0zs2=pfs(_ipy@)fu{RXQMx|7;eVP1CbwK{+F9pM#}pEY4ZPTsUYZr+&5S);~J zjmq+S&TeoS>Bsms726a)*7rXoT_S$LlLXkr3KwAOV$Y*swQTgHY1tE*jZqUOP0Xg{ zzg+D#;7S(vg~W5MW=+T%o!tpv>6>A-=o(=Je*JIV-!Pt7(w%FR(T7G;PtoDPW zl%tJmKQ;mTG`1#o3AVbf|9J#7^l#BJ_2fkwAUh$K11qmb7;g3KUf&jCH3AcSe*ji% zpgmR{X@OOF7x^|avXQkDsc&-D)KS?5v~o=LG!A!Dr(MHvtAH!8YHUiP#=;B>xM&cWH<8u{fW z#$N?|aFbWy4y@+*L9FKXHmoYl#j3!ou&Ou(TOC^utA>3@!HVC3)f!lXRXLMy_cj~{ zzY_jTtn!b*s@^N|yLodL0=TQ!w-vG4skH57O~?yWpX*J*uQR>$UtpE~4d357(-|Cl zNkRWRytSJgYfq7hmJl$BpM=YDYjzVaXD2BpTtXpo&-(^b;*r zL2vp!-ifV*OrjRt{c{bfbA^C}rhMOd{Gb72+Cy`Jh*Kt5sf^KjJHGgzxs-Fw;3u zp<0Xc*LaKR_-b!#wi2rrJb+bCu7AjDX;xnT#8KmOraivQsa~;mf$@|1C#k~e6LY4h zfz#J|l}8RxkvD)7CaIZ$z_>g%1kx2f;$0LoG|s##ulEL~0Iq@S<;PE(+A3M`_xtga z;WTS-VU`ytJo%`XA&ehK#-r=JUbnJ%KL z47KDHtmgjDM>BR%U6O&u&w6$B_D4Q)s*aqVBZuK>*;Dg$7k+e;H-zOjd*$DYub!Nm z@0BxoItQasc}}xRc0r_!$O-&xSvk3RZ2p1cft&+%5X6;sQRryDn>V^9u?q z5YU#|VwYFY8EV&_{grPIVpY)#SQWG$s|uE4Rl%)Tt(VEZz1rv9u*#Q=Re5!>%6|b? z_5Db%-S+_p2o55x2?|*Q>8-=&9S}ixc;Z?p1U!!ui5sqE8VQPA92Dg~j-4!3J_`%w?<1QP${Ra_sd zgq%#LDJ>atM)73hLbxiLoHcE1;`r?R7~c}v!G*!znb;q&fTj|oOyZ8 z#D_LEnU#3y_RdeQz3}exPj|cc#q+JafHQYx*m@%1>|GhQzo52G6ks`VEko9&K_@0L z9QCag2wd&NCZagkvVp)5H#CG$wv*YsZCL_dhB{G^(2az=tnU#T zsxOss!G}`H&6pnf{IuK~-WG1Br zKX8hZ((M!mv<)pU>ns==vZmTj_ZH#k4ZswjN%}C@d|_gA@H3~lMY>fz#))Yej=qvH zPgiWc6ic!8U4RY%%jumI3LbHaTc%s_<(!ySVQWY^r#og-IcILGaPYKK+$!B_cYzbr z`o`c#PEqT0t45r&w{_T>9_Pd)hpngMobJit;7O+_Io(d?GH*_?wzHsh$hxMI6B7#C z4+Gl*gU*2!DNa!+-D*+U*&7O56Dm6~DdFgsS<#A*G|sZBICE3NR*Ndm-juLCg9X~r z%^sH$vbI!lx~GPN-#bOA>DHxHoxQ1HYgAPyrcKy>iWRPLv77_@Q_jb6$0O3?i&*yp zWt`rJQ-T*dF==7@8CYj8M<^71%Je1Thf<<()cYvsKwJ8S*9tF4FH_3mgq_$n zX;E!Cvvzh$($b;|33XG*+Ed%<-Z5-fs^d*eS*JJSG8#{#RK|%*3t7wRI5C~V!Glgl zr*ykxU2n)(0BIrn20YCt%lGw^vN&NC8vM=4=$vl1sYfMlWbaVOz6r03=TXBRy!M{Q z$Vb=rRt*EtGGuqgQ(tHc`R1JU7O-UY)pugLgze}CrHj52FMKw`op@eF3z9=o2k|

5Gwqn+NJLe{K{ow?n@*5emD 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 delta 51885 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 { if (path === "prisma") return JSON.stringify( ( - (await readAsync(dir("node_modules/.prisma/client/index.d.ts"))) || "" + (await readAsync(dir.path("node_modules/.prisma/client/index.d.ts"))) || "" ).replace(`@prisma/client/runtime/library`, `./runtime/library`) ); if (path === "runtime") return JSON.stringify( await readAsync( - dir("node_modules/@prisma/client/runtime/index-browser.d.ts") + dir.path("node_modules/@prisma/client/runtime/index-browser.d.ts") ) ); if (path === "library") return JSON.stringify( - await readAsync(dir("node_modules/@prisma/client/runtime/library.d.ts")) + await readAsync(dir.path("node_modules/@prisma/client/runtime/library.d.ts")) ); return JSON.stringify({}); diff --git a/pkgs/core/api/_upload.ts b/pkgs/core/api/_upload.ts index 24d9912a..d583963d 100644 --- a/pkgs/core/api/_upload.ts +++ b/pkgs/core/api/_upload.ts @@ -21,7 +21,7 @@ export const _ = { .toLowerCase()}`; url = `/_file/${path}`; - await writeAsync(dir(`../data/upload/${path}`), part.buffer); + await writeAsync(dir.path(`../data/upload/${path}`), part.buffer); } return url; diff --git a/pkgs/core/api/_web.ts b/pkgs/core/api/_web.ts deleted file mode 100644 index c3bd8dc2..00000000 --- a/pkgs/core/api/_web.ts +++ /dev/null @@ -1,79 +0,0 @@ -import mime from "mime"; -import { apiContext } from "../server/api-ctx"; -import { g } from "../utils/global"; -import { getApiEntry } from "./_prasi"; - -export const _ = { - url: "/_web/:id/**", - async api(id: string, _: string) { - const { req, res } = apiContext(this); - - const web = g.web[id]; - if (web) { - const cache = web.cache; - if (cache) { - const parts = _.split("/"); - - switch (parts[0]) { - case "site": { - res.setHeader("content-type", "application/json"); - if (req.query_parameters["prod"]) { - return { - site: cache.site, - pages: cache.pages.map((e) => { - return { - id: e.id, - url: e.url, - }; - }), - api: getApiEntry(), - }; - } else { - return cache.site; - } - } - case "pages": { - res.setHeader("content-type", "application/json"); - return cache.pages.map((e) => { - return { - id: e.id, - url: e.url, - }; - }); - } - case "page": { - res.setHeader("content-type", "application/json"); - return cache.pages.find((e) => e.id === parts[1]); - } - case "npm-site": { - let path = parts.slice(1).join("/"); - res.setHeader("content-type", mime.getType(path) || "text/plain"); - - if (path === "site.js") { - path = "index.js"; - } - return cache.npm.site[path]; - } - case "npm-page": { - const page_id = parts[1]; - if (cache.npm.pages[page_id]) { - let path = parts.slice(2).join("/"); - res.setHeader("content-type", mime.getType(path) || "text/plain"); - - if (path === "page.js") { - path = "index.js"; - } - return cache.npm.pages[page_id][path]; - } - res.setHeader("content-type", "text/javascript"); - } - case "comp": { - res.setHeader("content-type", "application/json"); - return cache.comps.find((e) => e.id === parts[1]); - } - } - } - } - return req.params; - }, -}; diff --git a/pkgs/core/server/api-ctx.ts b/pkgs/core/server/api-ctx.ts index c3e1c189..9cb0c35c 100644 --- a/pkgs/core/server/api-ctx.ts +++ b/pkgs/core/server/api-ctx.ts @@ -1,3 +1,4 @@ +import { g } from "utils/global"; const parseQueryParams = (ctx: any) => { const pageHref = ctx.req.url; @@ -15,6 +16,7 @@ export const apiContext = (ctx: any) => { ctx.req.params = ctx.params; ctx.req.query_parameters = parseQueryParams(ctx); return { + mode: g.mode, req: ctx.req as Request & { params: any; query_parameters: any }, res: { ...ctx.res, diff --git a/pkgs/core/server/api-scan.ts b/pkgs/core/server/api-scan.ts index 7a9833af..a8b78ade 100644 --- a/pkgs/core/server/api-scan.ts +++ b/pkgs/core/server/api-scan.ts @@ -22,7 +22,7 @@ export const prepareApiRoutes = async () => { path: importPath.substring((root || path).length + 1), }; g.api[filename] = route; - g.router.insert(route.url, g.api[filename]); + g.router.insert(route.url.replace(/\*/gi, "**"), g.api[filename]); } catch (e) { g.log.warn( `Failed to import app/srv/api${importPath.substring( @@ -46,6 +46,6 @@ export const prepareApiRoutes = async () => { } } }; - await scan(dir(`app/srv/api`)); - await scan(dir(`pkgs/core/api`)); + await scan(dir.path(`app/srv/api`)); + await scan(dir.path(`pkgs/core/api`)); }; diff --git a/pkgs/core/server/create.ts b/pkgs/core/server/create.ts index 243b0755..70d1ac82 100644 --- a/pkgs/core/server/create.ts +++ b/pkgs/core/server/create.ts @@ -3,6 +3,7 @@ import { dir } from "../utils/dir"; import { g } from "../utils/global"; import { serveAPI } from "./serve-api"; +const cache = { static: {} as Record }; export const createServer = async () => { g.api = {}; g.router = createRouter({ strictTrailingSlash: true }); @@ -22,15 +23,21 @@ export const createServer = async () => { } try { - const file = Bun.file(dir(`app/static${url.pathname}`)); - if (file.type !== "application/octet-stream") { + if (cache.static[url.pathname]) { + return new Response(cache.static[url.pathname]); + } + + const file = Bun.file(dir.path(`app/static${url.pathname}`)); + if ((await file.exists()) && file.type !== "application/octet-stream") { + cache.static[url.pathname] = file; return new Response(file as any); } } catch (e) { g.log.error(e); } + try { - return new Response(Bun.file(dir(`app/static/index.html`)) as any); + return new Response(Bun.file(dir.path(`app/static/index.html`)) as any); } catch (e) { g.log.error(e); return new Response("Loading..."); diff --git a/pkgs/core/server/prep-api-ts.ts b/pkgs/core/server/prep-api-ts.ts index 63f68e89..8c881060 100644 --- a/pkgs/core/server/prep-api-ts.ts +++ b/pkgs/core/server/prep-api-ts.ts @@ -16,20 +16,20 @@ export const ${name} = { handler: import("./api/${v.path.substring(0, v.path.length - 3)}") }`); } - await Bun.write(dir(`app/srv/exports.ts`), out.join(`\n`)); + await Bun.write(dir.path(`app/srv/exports.ts`), out.join(`\n`)); - const targetFile = dir("app/srv/exports.d.ts"); + const targetFile = dir.path("app/srv/exports.d.ts"); const tsc = spawn( [ - dir("node_modules/.bin/tsc"), - dir("app/srv/exports.ts"), + dir.path("node_modules/.bin/tsc"), + dir.path("app/srv/exports.ts"), "--declaration", "--emitDeclarationOnly", "--outFile", targetFile, ], { - cwd: dir(`node_modules/.bin`), + cwd: dir.path(`node_modules/.bin`), } ); diff --git a/pkgs/core/upgrade.ts b/pkgs/core/upgrade.ts index 885c4d2d..9b4a661c 100644 --- a/pkgs/core/upgrade.ts +++ b/pkgs/core/upgrade.ts @@ -11,15 +11,15 @@ const res = await fetch( const data = await unzipper.Open.buffer(Buffer.from(await res.arrayBuffer())); const promises: Promise[] = []; -await removeAsync(dir("pkgs")); +await removeAsync(dir.path("pkgs")); for (const file of data.files) { if (file.type === "File") { const path = file.path.split("/").slice(1).join("/"); if (path === "tsconfig.json" || path.startsWith("pkgs")) { promises.push( new Promise(async (done) => { - await dirAsync(dirname(dir(path))); - await Bun.write(dir(path), await file.buffer()); + await dirAsync(dirname(dir.path(path))); + await Bun.write(dir.path(path), await file.buffer()); done(); }) ); diff --git a/pkgs/core/utils/config.ts b/pkgs/core/utils/config.ts index 36bea182..578744a6 100644 --- a/pkgs/core/utils/config.ts +++ b/pkgs/core/utils/config.ts @@ -5,11 +5,11 @@ const _internal = { config: {} as any, writeTimeout: null as any }; export const config = { init: async () => { - await dirAsync(dir("../data/config")); - await dirAsync(dir("../data/files")); + await dirAsync(dir.path("../data/config")); + await dirAsync(dir.path("../data/files")); _internal.config = - (await readAsync(dir("../data/config/conf.json"), "json")) || {}; + (await readAsync(dir.path("../data/config/conf.json"), "json")) || {}; }, get all() { return _internal.config; @@ -27,7 +27,7 @@ export const config = { _internal.config[key] = value; clearTimeout(_internal.writeTimeout); _internal.writeTimeout = setTimeout(() => { - Bun.write(dir("../data/config/conf.json"), _internal.config); + Bun.write(dir.path("../data/config/conf.json"), _internal.config); }, 100); }, }; diff --git a/pkgs/core/utils/dev-watcher.ts b/pkgs/core/utils/dev-watcher.ts index 1b3da892..f7bc1851 100644 --- a/pkgs/core/utils/dev-watcher.ts +++ b/pkgs/core/utils/dev-watcher.ts @@ -4,9 +4,9 @@ import { dir } from "./dir"; import { dirAsync } from "fs-jetpack"; export const startDevWatcher = async () => { - await dirAsync(dir(`app/srv/api`)); - watch(dir(`app/srv/api`), async (event, filename) => { - const s = file(dir(`app/srv/api/${filename}`)); + await dirAsync(dir.path(`app/srv/api`)); + watch(dir.path(`app/srv/api`), async (event, filename) => { + const s = file(dir.path(`app/srv/api/${filename}`)); if (s.size === 0) { await Bun.write( `app/srv/api/${filename}`, diff --git a/pkgs/core/utils/dir.ts b/pkgs/core/utils/dir.ts index e49f156f..c9eb33a8 100644 --- a/pkgs/core/utils/dir.ts +++ b/pkgs/core/utils/dir.ts @@ -1,5 +1,7 @@ import { join } from "path"; -export const dir = (path: string) => { - return join(process.cwd(), path); +export const dir = { + path: (path: string) => { + return join(process.cwd(), path); + }, }; diff --git a/pkgs/core/utils/parcel.ts b/pkgs/core/utils/parcel.ts index 6a6c5f06..0f352fb6 100644 --- a/pkgs/core/utils/parcel.ts +++ b/pkgs/core/utils/parcel.ts @@ -7,28 +7,28 @@ export const parcelBuild = async () => { await dirAsync("app/static"); const args = [ "node", - dir("node_modules/.bin/parcel"), + dir.path("node_modules/.bin/parcel"), g.mode === "dev" ? "watch" : "build", "./src/index.tsx", g.mode === "dev" ? "--no-hmr" : "--no-optimize", "--dist-dir", - dir(`app/static`), + dir.path(`app/static`), ]; g.log.info(`Building web with parcel`); if (g.mode !== "dev") { - await removeAsync(dir("app/static")); - await removeAsync(dir("app/web/.parcel-cache")); + await removeAsync(dir.path("app/static")); + await removeAsync(dir.path("app/web/.parcel-cache")); const parcel = spawn({ cmd: args, - cwd: dir("app/web"), + cwd: dir.path("app/web"), stdio: ["ignore", "inherit", "inherit"], }); await parcel.exited; } else { const parcel = spawn({ cmd: args, - cwd: dir("app/web"), + cwd: dir.path("app/web"), stdio: ["ignore", "pipe", "pipe"], }); diff --git a/pkgs/core/utils/prisma.ts b/pkgs/core/utils/prisma.ts index e82c55ea..0ea8a307 100644 --- a/pkgs/core/utils/prisma.ts +++ b/pkgs/core/utils/prisma.ts @@ -4,9 +4,9 @@ import { $ } from "execa"; import { g } from "./global"; export const preparePrisma = async () => { - if (await existsAsync(dir("app/db/.env"))) { - if (!(await existsAsync(dir("node_modules/.prisma")))) { - await $({ cwd: dir(`app/db`) })`bun prisma generate`; + if (await existsAsync(dir.path("app/db/.env"))) { + if (!(await existsAsync(dir.path("node_modules/.prisma")))) { + await $({ cwd: dir.path(`app/db`) })`bun prisma generate`; } const { PrismaClient } = await import("../../../app/db/db"); g.db = new PrismaClient(); diff --git a/pkgs/core/utils/session.ts b/pkgs/core/utils/session.ts index 57addce2..7c0d1452 100644 --- a/pkgs/core/utils/session.ts +++ b/pkgs/core/utils/session.ts @@ -14,7 +14,7 @@ export const createCache = () => ({ lmdb: null as unknown as RootDatabase>, cookieKey: "", async init(arg: { cookieKey: string; dbname?: string }) { - const dbpath = dir(join(g.datadir, (arg.dbname || "session") + ".lmdb")); + const dbpath = dir.path(join(g.datadir, (arg.dbname || "session") + ".lmdb")); await dirAsync(dirname(dbpath)); self(this).lmdb = open({ path: dbpath, diff --git a/tsconfig.json b/tsconfig.json index 2042d68e..b7a3b708 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,9 @@ "forceConsistentCasingInFileNames": true, "allowJs": true, "paths": { + "dir": [ + "./pkgs/core/utils/dir.ts" + ], "dbgen": [ "./node_modules/.prisma/client/index.d.ts" ],