wip check point
This commit is contained in:
parent
8cffe6fa69
commit
6ddbd121cb
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../../pkgs/core/server/api/api-ctx";
|
||||||
import argon from "@node-rs/argon2";
|
import argon from "@node-rs/argon2";
|
||||||
import { session } from "utils/session";
|
import { session } from "utils/session";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../../pkgs/core/server/api/api-ctx";
|
||||||
import { session } from "utils/session";
|
import { session } from "utils/session";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../../pkgs/core/server/api/api-ctx";
|
||||||
import { user } from "dbgen";
|
import { user } from "dbgen";
|
||||||
import { session } from "utils/session";
|
import { session } from "utils/session";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { dirAsync } from "fs-jetpack";
|
import { dirAsync } from "fs-jetpack";
|
||||||
import trim from "lodash.trim";
|
import trim from "lodash.trim";
|
||||||
import { dirname } from "path";
|
import { dirname } from "path";
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
import { baseTypings } from "../../web/src/utils/script/types/base";
|
import { baseTypings } from "../../web/src/utils/script/types/base";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
url: "/_web/comp/:id",
|
url: "/_web/comp/:id",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
url: "/_font/**",
|
url: "/_font/**",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
export const _ = {
|
export const _ = {
|
||||||
url: "/local-ip",
|
url: "/local-ip",
|
||||||
async api() {
|
async api() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { dir } from "dir";
|
import { dir } from "dir";
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { buildNpm } from "../util/build-npm";
|
import { buildNpm } from "../util/build-npm";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { dir } from "dir";
|
import { dir } from "dir";
|
||||||
import { stat } from "fs/promises";
|
import { stat } from "fs/promises";
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import crypto from "crypto";
|
||||||
import { dir } from "dir";
|
import { dir } from "dir";
|
||||||
import { readAsync } from "fs-jetpack";
|
import { readAsync } from "fs-jetpack";
|
||||||
import mime from "mime-types";
|
import mime from "mime-types";
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { glb } from "../global";
|
import { glb } from "../global";
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
url: "/_web/page/:id",
|
url: "/_web/page/:id",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import { session } from "utils/session";
|
import { session } from "utils/session";
|
||||||
import { user } from "dbgen";
|
import { user } from "dbgen";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
import { dir } from "dir";
|
import { dir } from "dir";
|
||||||
import { readAsync } from "fs-jetpack";
|
import { readAsync } from "fs-jetpack";
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
const cache = {
|
const cache = {
|
||||||
md5: "",
|
md5: "",
|
||||||
content: null as any,
|
content: null as any,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
import ts from "typescript";
|
import ts from "typescript";
|
||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "service-srv";
|
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
|
||||||
|
|
||||||
import { dir } from "dir";
|
import { dir } from "dir";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,19 @@ import { Loading } from "../../utils/ui/loading";
|
||||||
export default page({
|
export default page({
|
||||||
url: "/ed/:site_id/:page_id",
|
url: "/ed/:site_id/:page_id",
|
||||||
component: ({}) => {
|
component: ({}) => {
|
||||||
|
console.log("momoka");
|
||||||
|
setTimeout(() => {
|
||||||
|
(async () => {
|
||||||
|
console.log(
|
||||||
|
await fetch("/moka", {
|
||||||
|
method: "POST",
|
||||||
|
body: "{}",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
}, 2000);
|
||||||
|
return <>uwuw</>;
|
||||||
|
|
||||||
const p = useGlobal(EDGlobal, "EDITOR");
|
const p = useGlobal(EDGlobal, "EDITOR");
|
||||||
|
|
||||||
const w = window as any;
|
const w = window as any;
|
||||||
|
|
|
||||||
|
|
@ -2,197 +2,30 @@ import { Root as ReactRoot, createRoot } from "react-dom/client";
|
||||||
import { defineReact, defineWindow } from "web-utils";
|
import { defineReact, defineWindow } from "web-utils";
|
||||||
import { Root } from "./base/root";
|
import { Root } from "./base/root";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { createAPI, createDB, reloadDBAPI } from "./utils/script/init-api";
|
|
||||||
import { w } from "./utils/types/general";
|
|
||||||
import { registerMobile } from "./render/live/logic/mobile";
|
import { registerMobile } from "./render/live/logic/mobile";
|
||||||
import { isLocalhost } from "./utils/ui/is-localhost";
|
import { reloadDBAPI } from "./utils/script/init-api";
|
||||||
|
import { w } from "./utils/types/general";
|
||||||
|
import { sworkerAddCache, sworkerRegister } from "./sworker-boot";
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
const base = `${location.protocol}//${location.host}`;
|
const base = `${location.protocol}//${location.host}`;
|
||||||
let react = {
|
let react = {
|
||||||
root: null as null | ReactRoot,
|
root: null as null | ReactRoot,
|
||||||
};
|
};
|
||||||
(window as any).mobile = registerMobile();
|
w.mobile = registerMobile();
|
||||||
|
|
||||||
if (navigator.serviceWorker) {
|
|
||||||
if (!isLocalhost()) {
|
|
||||||
const sw = await registerServiceWorker();
|
|
||||||
const cacheCurrentPage = () => {
|
|
||||||
const swController = navigator.serviceWorker.controller;
|
|
||||||
if (swController) {
|
|
||||||
[location.href, "", "/", "/ed", "/ed/_/_", "/login"].forEach(
|
|
||||||
(url) => {
|
|
||||||
swController.postMessage({
|
|
||||||
type: "add-cache",
|
|
||||||
url: url,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
cacheCurrentPage();
|
|
||||||
navigator.serviceWorker.addEventListener("message", (e) => {
|
|
||||||
cacheCurrentPage();
|
|
||||||
if (react.root) {
|
|
||||||
if (e.data.type === "offline") {
|
|
||||||
w.offline = true;
|
|
||||||
const click = () => {
|
|
||||||
if (react.root) react.root.render(<Root />);
|
|
||||||
};
|
|
||||||
setTimeout(click, 5000);
|
|
||||||
react.root.render(
|
|
||||||
<>
|
|
||||||
<Root />
|
|
||||||
<div
|
|
||||||
className={cx(
|
|
||||||
css`
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
z-index: 999;
|
|
||||||
`,
|
|
||||||
"flex justify-center cursor-pointer"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="bg-orange-500 text-white px-4 py-2 rounded-full text-sm"
|
|
||||||
onClick={click}
|
|
||||||
>
|
|
||||||
Network Failed
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.data.type === "activated") {
|
|
||||||
if (e.data.shouldRefresh && sw) {
|
|
||||||
react.root.render(
|
|
||||||
<>
|
|
||||||
<Root />
|
|
||||||
<div
|
|
||||||
className={cx(
|
|
||||||
css`
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
z-index: 999;
|
|
||||||
`,
|
|
||||||
"flex justify-center"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="bg-blue-400 text-white px-4 py-2 rounded-full text-sm">
|
|
||||||
Updating App...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
sw.unregister().then(() => {
|
|
||||||
window.location.reload();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const localVersion = localStorage.getItem("prasi-version");
|
|
||||||
if (localVersion !== e.data.version) {
|
|
||||||
localStorage.setItem("prasi-version", e.data.version);
|
|
||||||
const click = () => {
|
|
||||||
if (react.root) react.root.render(<Root />);
|
|
||||||
};
|
|
||||||
setTimeout(click, 5000);
|
|
||||||
react.root.render(
|
|
||||||
<>
|
|
||||||
<Root />
|
|
||||||
<div
|
|
||||||
className={cx(
|
|
||||||
css`
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
z-index: 999;
|
|
||||||
`,
|
|
||||||
"flex justify-center cursor-pointer"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="bg-green-600 text-white px-4 py-2 rounded-full text-sm"
|
|
||||||
onClick={click}
|
|
||||||
>
|
|
||||||
Prasi Updated{" "}
|
|
||||||
<span className="opacity-50">{e.data.version}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
navigator.serviceWorker.getRegistrations().then(function (registrations) {
|
|
||||||
for (let registration of registrations) {
|
|
||||||
registration.unregister();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// sworkerRegister(react);
|
||||||
defineReact();
|
defineReact();
|
||||||
await defineWindow(false);
|
await defineWindow(false);
|
||||||
w.serverurl = base;
|
// await reloadDBAPI(base, "prod");
|
||||||
await reloadDBAPI(base, "prod");
|
// sworkerAddCache(base);
|
||||||
|
|
||||||
if (navigator.serviceWorker) {
|
|
||||||
const swc = navigator.serviceWorker.controller;
|
|
||||||
if (swc) {
|
|
||||||
[location.href, "", "/", "/ed", "/ed/_/_", "/login"].forEach((url) => {
|
|
||||||
swc.postMessage({
|
|
||||||
type: "add-cache",
|
|
||||||
url: url,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (w.prasiApi && w.prasiApi[base] && w.prasiApi[base].apiEntry) {
|
|
||||||
const routes = Object.entries(w.prasiApi[base].apiEntry).map(
|
|
||||||
([k, v]: any) => ({
|
|
||||||
url: v.url,
|
|
||||||
name: k,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
swc.postMessage({
|
|
||||||
type: "define-route",
|
|
||||||
routes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.api = createAPI(base);
|
|
||||||
w.db = createDB(base);
|
|
||||||
|
|
||||||
const el = document.getElementById("root");
|
const el = document.getElementById("root");
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
react.root = createRoot(el);
|
react.root = createRoot(el);
|
||||||
react.root.render(<Root />);
|
react.root.render(<Root />);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const registerServiceWorker = async () => {
|
|
||||||
if ("serviceWorker" in navigator) {
|
|
||||||
try {
|
|
||||||
return await navigator.serviceWorker.register(
|
|
||||||
new URL("./sworker.ts", import.meta.url),
|
|
||||||
{
|
|
||||||
type: "module",
|
|
||||||
scope: "/",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Registration failed with ${error}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import init from "wasm-gzip";
|
||||||
import { jscript } from "../../../utils/script/jscript";
|
import { jscript } from "../../../utils/script/jscript";
|
||||||
import { dbClient } from "../../vi/load/db/client-db";
|
import { dbClient } from "../../vi/load/db/client-db";
|
||||||
import { PG } from "./ed-global";
|
import { PG } from "./ed-global";
|
||||||
|
import { fetchViaProxy } from "../../vi/load/proxy";
|
||||||
|
|
||||||
let w = window as unknown as { db: ReturnType<typeof dbClient> };
|
let w = window as unknown as { db: ReturnType<typeof dbClient> };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ export const EdScriptSnippet: FC<{}> = ({}) => {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
`)}
|
`)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log(p.script.do_edit);
|
|
||||||
p.script.do_edit(
|
p.script.do_edit(
|
||||||
`\
|
`\
|
||||||
<div {...props}>
|
<div {...props}>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
import { Root as ReactRoot } from "react-dom/client";
|
||||||
|
import { Root } from "./base/root";
|
||||||
|
import { w } from "./utils/types/general";
|
||||||
|
import { isLocalhost } from "./utils/ui/is-localhost";
|
||||||
|
|
||||||
|
export const sworkerRegister = async (react: { root: null | ReactRoot }) => {
|
||||||
|
if (navigator.serviceWorker) {
|
||||||
|
if (!isLocalhost()) {
|
||||||
|
const sw = await registerServiceWorker();
|
||||||
|
const cacheCurrentPage = () => {
|
||||||
|
const swController = navigator.serviceWorker.controller;
|
||||||
|
if (swController) {
|
||||||
|
[location.href, "", "/", "/ed", "/ed/_/_", "/login"].forEach(
|
||||||
|
(url) => {
|
||||||
|
swController.postMessage({
|
||||||
|
type: "add-cache",
|
||||||
|
url: url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cacheCurrentPage();
|
||||||
|
navigator.serviceWorker.addEventListener("message", (e) => {
|
||||||
|
cacheCurrentPage();
|
||||||
|
if (react.root) {
|
||||||
|
if (e.data.type === "offline") {
|
||||||
|
w.offline = true;
|
||||||
|
const click = () => {
|
||||||
|
if (react.root) react.root.render(<Root />);
|
||||||
|
};
|
||||||
|
setTimeout(click, 5000);
|
||||||
|
react.root.render(
|
||||||
|
<>
|
||||||
|
<Root />
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
css`
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 999;
|
||||||
|
`,
|
||||||
|
"flex justify-center cursor-pointer"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="bg-orange-500 text-white px-4 py-2 rounded-full text-sm"
|
||||||
|
onClick={click}
|
||||||
|
>
|
||||||
|
Network Failed
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.data.type === "activated") {
|
||||||
|
if (e.data.shouldRefresh && sw) {
|
||||||
|
react.root.render(
|
||||||
|
<>
|
||||||
|
<Root />
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
css`
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 999;
|
||||||
|
`,
|
||||||
|
"flex justify-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="bg-blue-400 text-white px-4 py-2 rounded-full text-sm">
|
||||||
|
Updating App...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
sw.unregister().then(() => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const localVersion = localStorage.getItem("prasi-version");
|
||||||
|
if (localVersion !== e.data.version) {
|
||||||
|
localStorage.setItem("prasi-version", e.data.version);
|
||||||
|
const click = () => {
|
||||||
|
if (react.root) react.root.render(<Root />);
|
||||||
|
};
|
||||||
|
setTimeout(click, 5000);
|
||||||
|
react.root.render(
|
||||||
|
<>
|
||||||
|
<Root />
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
css`
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 999;
|
||||||
|
`,
|
||||||
|
"flex justify-center cursor-pointer"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="bg-green-600 text-white px-4 py-2 rounded-full text-sm"
|
||||||
|
onClick={click}
|
||||||
|
>
|
||||||
|
Prasi Updated{" "}
|
||||||
|
<span className="opacity-50">{e.data.version}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigator.serviceWorker.getRegistrations().then(function (registrations) {
|
||||||
|
for (let registration of registrations) {
|
||||||
|
registration.unregister();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerServiceWorker = async () => {
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
try {
|
||||||
|
return await navigator.serviceWorker.register(
|
||||||
|
new URL("./sworker.ts", import.meta.url),
|
||||||
|
{
|
||||||
|
type: "module",
|
||||||
|
scope: "/",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Registration failed with ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sworkerAddCache = (base: string) => {
|
||||||
|
if (navigator.serviceWorker) {
|
||||||
|
if (!isLocalhost()) {
|
||||||
|
const swc = navigator.serviceWorker.controller;
|
||||||
|
if (swc) {
|
||||||
|
[location.href, "", "/", "/ed", "/ed/_/_", "/login"].forEach((url) => {
|
||||||
|
swc.postMessage({
|
||||||
|
type: "add-cache",
|
||||||
|
url: url,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (w.prasiApi && w.prasiApi[base] && w.prasiApi[base].apiEntry) {
|
||||||
|
const routes = Object.entries(w.prasiApi[base].apiEntry).map(
|
||||||
|
([k, v]: any) => ({
|
||||||
|
url: v.url,
|
||||||
|
name: k,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
swc.postMessage({
|
||||||
|
type: "define-route",
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -27,6 +27,7 @@ export const w = window as unknown as {
|
||||||
prasiApi: Record<string, PrasiAPI>;
|
prasiApi: Record<string, PrasiAPI>;
|
||||||
loadedFonts: string[];
|
loadedFonts: string[];
|
||||||
prasiApiDbPull: boolean;
|
prasiApiDbPull: boolean;
|
||||||
|
mobile?: any;
|
||||||
params: any;
|
params: any;
|
||||||
editorGlbDefault: string;
|
editorGlbDefault: string;
|
||||||
ts: number;
|
ts: number;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "../server/api-ctx";
|
import { apiContext } from "../server/api/api-ctx";
|
||||||
import { g } from "../utils/global";
|
import { g } from "../utils/global";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiContext } from "../server/api-ctx";
|
import { apiContext } from "../server/api/api-ctx";
|
||||||
import { DBArg, execQuery } from "../utils/query";
|
import { DBArg, execQuery } from "../utils/query";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
import { apiContext } from "../server/api-ctx";
|
import { apiContext } from "../server/api/api-ctx";
|
||||||
import { dir } from "../utils/dir";
|
import { dir } from "../utils/dir";
|
||||||
|
|
||||||
export const _ = {
|
export const _ = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { readAsync } from "fs-jetpack";
|
import { readAsync } from "fs-jetpack";
|
||||||
import { apiContext } from "../server/api-ctx";
|
import { apiContext } from "../server/api/api-ctx";
|
||||||
import { g } from "../utils/global";
|
import { g } from "../utils/global";
|
||||||
import { dir } from "../utils/dir";
|
import { dir } from "../utils/dir";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import mp from "@surfy/multipart-parser";
|
||||||
|
|
||||||
import { writeAsync } from "fs-jetpack";
|
import { writeAsync } from "fs-jetpack";
|
||||||
import { g } from "utils/global";
|
import { g } from "utils/global";
|
||||||
import { apiContext } from "../server/api-ctx";
|
import { apiContext } from "../server/api/api-ctx";
|
||||||
import { dir } from "../utils/dir";
|
import { dir } from "../utils/dir";
|
||||||
export const _ = {
|
export const _ = {
|
||||||
url: "/_upload",
|
url: "/_upload",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { parcelBuild } from "utils/parcel";
|
import { parcelBuild } from "utils/parcel";
|
||||||
import { generateAPIFrm } from "./server/api-frm";
|
import { prepareAPITypes } from "./server/api/prep-api-ts";
|
||||||
import { prepareApiRoutes } from "./server/api-scan";
|
|
||||||
import { prepareAPITypes } from "./server/prep-api-ts";
|
|
||||||
import { startDevWatcher } from "./utils/dev-watcher";
|
import { startDevWatcher } from "./utils/dev-watcher";
|
||||||
import { ensureNotRunning } from "./utils/ensure";
|
import { ensureNotRunning } from "./utils/ensure";
|
||||||
import { g } from "./utils/global";
|
import { g } from "./utils/global";
|
||||||
|
|
@ -55,14 +53,11 @@ if (!g.apiPrepared) {
|
||||||
await syncActionDefinition();
|
await syncActionDefinition();
|
||||||
g.log.info("WS Action defined");
|
g.log.info("WS Action defined");
|
||||||
|
|
||||||
await generateAPIFrm();
|
|
||||||
await prepareAPITypes();
|
await prepareAPITypes();
|
||||||
g.log.info("API Prepared");
|
g.log.info("API Prepared");
|
||||||
g.apiPrepared = true;
|
g.apiPrepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await prepareApiRoutes();
|
|
||||||
|
|
||||||
if (!g.parcel) {
|
if (!g.parcel) {
|
||||||
await parcelBuild();
|
await parcelBuild();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
import { transform } from "@swc/core";
|
|
||||||
import { g } from "../utils/global";
|
|
||||||
import { createHash } from "crypto";
|
|
||||||
|
|
||||||
export const generateAPIFrm = async () => {
|
|
||||||
const res = await transform(
|
|
||||||
`
|
|
||||||
(BigInt.prototype).toJSON = function () {
|
|
||||||
return "BigInt::" + this.toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
const replacer = (key, value) => {
|
|
||||||
if (typeof value === "string" && value.startsWith('BigInt::')) {
|
|
||||||
return BigInt(value.substr(8));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('message', (e) => {
|
|
||||||
const msg = e.data;
|
|
||||||
const init = Object.assign({}, msg.init)
|
|
||||||
|
|
||||||
let input = msg.input;
|
|
||||||
let url = msg.input;
|
|
||||||
if (typeof msg.input === 'string') {
|
|
||||||
if (!input.startsWith('http')) {
|
|
||||||
url = new URL(\`\$\{location.origin\}\$\{input\}\`)
|
|
||||||
} else {
|
|
||||||
url = new URL(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (init && init.body && typeof init.body === 'object') {
|
|
||||||
if (Array.isArray(init.body)) {
|
|
||||||
const body = new FormData();
|
|
||||||
body.append("file", init.body[0]);
|
|
||||||
init.body = body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fetch(url.pathname, init)
|
|
||||||
.then(async (res) => {
|
|
||||||
if (res) {
|
|
||||||
const body = await res.text();
|
|
||||||
if (res.ok) {
|
|
||||||
try {
|
|
||||||
parent.postMessage({result: JSON.parse(body, replacer), id: msg.id }, '*')
|
|
||||||
} catch(e) {
|
|
||||||
parent.postMessage({result: body, id: msg.id }, '*')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
parent.postMessage({error: JSON.parse(body, replacer), id: msg.id }, '*')
|
|
||||||
} catch(e) {
|
|
||||||
parent.postMessage({error: body, id: msg.id }, '*')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
parent.postMessage('initialized', '*')`,
|
|
||||||
{ minify: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
g.frm = {
|
|
||||||
js: res.code,
|
|
||||||
etag: createHash("md5").update(res.code).digest("hex"),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { file } from "bun";
|
import { file } from "bun";
|
||||||
import { inspectAsync, listAsync } from "fs-jetpack";
|
import { inspectAsync, listAsync } from "fs-jetpack";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { dir } from "../utils/dir";
|
import { dir } from "../../utils/dir";
|
||||||
import { g } from "../utils/global";
|
import { g } from "../../utils/global";
|
||||||
import { parseArgs } from "./parse-args";
|
import { parseArgs } from "./parse-args";
|
||||||
|
|
||||||
export const prepareApiRoutes = async () => {
|
export const prepareApiRoutes = async () => {
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { spawn, spawnSync } from "bun";
|
import { spawn } from "bun";
|
||||||
import { existsAsync, readAsync } from "fs-jetpack";
|
import { existsAsync, readAsync } from "fs-jetpack";
|
||||||
import { dir } from "../utils/dir";
|
import { dir } from "../../utils/dir";
|
||||||
import { g } from "../utils/global";
|
import { g } from "../../utils/global";
|
||||||
|
|
||||||
export const prepareAPITypes = async () => {
|
export const prepareAPITypes = async () => {
|
||||||
const out: string[] = [];
|
const out: string[] = [];
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { WebSocketHandler } from "bun";
|
|
||||||
import { lookup } from "mime-types";
|
|
||||||
import { createRouter } from "radix3";
|
import { createRouter } from "radix3";
|
||||||
import { dir } from "../utils/dir";
|
|
||||||
import { g } from "../utils/global";
|
import { g } from "../utils/global";
|
||||||
|
import { serveWS } from "./serve-ws";
|
||||||
|
import { serveStatic } from "./serve-static";
|
||||||
import { serveAPI } from "./serve-api";
|
import { serveAPI } from "./serve-api";
|
||||||
|
|
||||||
export const cache = {
|
export const cache = {
|
||||||
|
|
@ -19,127 +18,24 @@ export const cache = {
|
||||||
export type WSData = { url: URL };
|
export type WSData = { url: URL };
|
||||||
|
|
||||||
export const createServer = async () => {
|
export const createServer = async () => {
|
||||||
g.router = createRouter({ strictTrailingSlash: false });
|
await serveAPI.init();
|
||||||
|
await serveStatic.init();
|
||||||
|
|
||||||
for (const route of Object.values(g.api)) {
|
|
||||||
g.router.insert(route.url.replace(/\*/gi, "**"), route);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { wsHandler } = await import("../../../app/srv/ws/handler");
|
|
||||||
g.server = Bun.serve({
|
g.server = Bun.serve({
|
||||||
port: g.port,
|
port: g.port,
|
||||||
websocket: {
|
maxRequestBodySize: 9999999,
|
||||||
maxPayloadLength: 9999999,
|
development: true,
|
||||||
closeOnBackpressureLimit: true,
|
websocket: await serveWS(),
|
||||||
drain(ws) {
|
|
||||||
// console.log("Backpressure relieved...");
|
|
||||||
},
|
|
||||||
close(ws, code, reason) {
|
|
||||||
const pathname = ws.data.url.pathname;
|
|
||||||
if (wsHandler[pathname]) {
|
|
||||||
const close = wsHandler[pathname].close;
|
|
||||||
if (close) {
|
|
||||||
close(ws, code, reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
message(ws, message) {
|
|
||||||
const pathname = ws.data.url.pathname;
|
|
||||||
if (wsHandler[pathname]) {
|
|
||||||
const msg = wsHandler[pathname].message;
|
|
||||||
if (msg) {
|
|
||||||
msg(ws, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
open(ws) {
|
|
||||||
const pathname = ws.data.url.pathname;
|
|
||||||
if (wsHandler[pathname]) {
|
|
||||||
const open = wsHandler[pathname].open;
|
|
||||||
if (open) {
|
|
||||||
open(ws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
} as WebSocketHandler<WSData>,
|
|
||||||
async fetch(req, server) {
|
async fetch(req, server) {
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
|
|
||||||
const response = async () => {
|
if (serveStatic.exists(url)) {
|
||||||
if (wsHandler[url.pathname]) {
|
return serveStatic.serve(url);
|
||||||
if (
|
|
||||||
server.upgrade(req, {
|
|
||||||
data: {
|
|
||||||
url: new URL(req.url),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return new Response("Upgrade failed :(", { status: 500 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
await serveAPI.serve(url, req);
|
||||||
const api = await serveAPI(url, req);
|
|
||||||
if (api) {
|
|
||||||
return api;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
g.log.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const webPath = "app/static";
|
return serveStatic.serve(url);
|
||||||
try {
|
|
||||||
const found = cache.static[url.pathname];
|
|
||||||
|
|
||||||
if (found && g.mode === "prod") {
|
|
||||||
return responseCached(req, found);
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = Bun.file(dir.path(`${webPath}${url.pathname}`));
|
|
||||||
if (
|
|
||||||
(await file.exists()) &&
|
|
||||||
file.type !== "application/octet-stream" // is not directory
|
|
||||||
) {
|
|
||||||
if (g.mode === "dev") {
|
|
||||||
return new Response(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cache.static[url.pathname]) {
|
|
||||||
cache.static[url.pathname] = {
|
|
||||||
type: lookup(url.pathname) || "text/plain",
|
|
||||||
content: await file.arrayBuffer(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const filebr = Bun.file(dir.path(`${webPath}-br${url.pathname}`));
|
|
||||||
if (
|
|
||||||
(await filebr.exists()) &&
|
|
||||||
filebr.type !== "application/octet-stream" // is not directory
|
|
||||||
) {
|
|
||||||
cache.static[url.pathname].br = await filebr.arrayBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
const found = cache.static[url.pathname];
|
|
||||||
if (found) {
|
|
||||||
return responseCached(req, found);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
g.log.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return new Response(
|
|
||||||
Bun.file(dir.path(`${webPath}/index.html`)) as any
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
g.log.error(e);
|
|
||||||
return new Response("Loading...");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const res = await response();
|
|
||||||
return res;
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -149,16 +45,3 @@ export const createServer = async () => {
|
||||||
g.log.info(`Started at port: ${g.server.port}`);
|
g.log.info(`Started at port: ${g.server.port}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const responseCached = (req: Request, found: (typeof cache.static)[string]) => {
|
|
||||||
if (req.headers.get("accept-encoding")?.includes("br") && found.br) {
|
|
||||||
const res = new Response(found.br);
|
|
||||||
res.headers.set("content-type", found.type);
|
|
||||||
res.headers.set("content-encoding", "br");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
const res = new Response(found.content);
|
|
||||||
res.headers.set("content-type", found.type);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
import { createResponse } from "./api-ctx";
|
import { createRouter } from "radix3";
|
||||||
import { g } from "../utils/global";
|
import { g } from "utils/global";
|
||||||
|
import { createResponse } from "./api/api-ctx";
|
||||||
|
import { prepareApiRoutes } from "./api/api-scan";
|
||||||
|
|
||||||
const replacer = (key: string, value: string) => {
|
export const serveAPI = {
|
||||||
if (typeof value === "string" && value.startsWith("BigInt::")) {
|
init: async () => {
|
||||||
return BigInt(value.substring(8));
|
g.router = createRouter({ strictTrailingSlash: false });
|
||||||
|
for (const route of Object.values(g.api)) {
|
||||||
|
g.router.insert(route.url.replace(/\*/gi, "**"), route);
|
||||||
}
|
}
|
||||||
return value;
|
await prepareApiRoutes();
|
||||||
};
|
},
|
||||||
|
serve: async (url: URL, req: Request) => {
|
||||||
export const serveAPI = async (url: URL, req: Request) => {
|
|
||||||
let found = g.router.lookup(url.pathname);
|
let found = g.router.lookup(url.pathname);
|
||||||
if (!found?.url) {
|
if (!found?.url) {
|
||||||
if (!url.pathname.endsWith("/")) {
|
if (!url.pathname.endsWith("/")) {
|
||||||
|
|
@ -28,7 +31,9 @@ export const serveAPI = async (url: URL, req: Request) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (req.method !== "GET") {
|
if (req.method !== "GET") {
|
||||||
if (!req.headers.get("content-type")?.startsWith("multipart/form-data")) {
|
if (
|
||||||
|
!req.headers.get("content-type")?.startsWith("multipart/form-data")
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const text = await req.text();
|
const text = await req.text();
|
||||||
const json = JSON.parse(text, replacer);
|
const json = JSON.parse(text, replacer);
|
||||||
|
|
@ -55,7 +60,7 @@ export const serveAPI = async (url: URL, req: Request) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
g.log.error({ pathname: url.pathname, error: e });
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,4 +98,12 @@ export const serveAPI = async (url: URL, req: Request) => {
|
||||||
|
|
||||||
return current.res;
|
return current.res;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const replacer = (key: string, value: string) => {
|
||||||
|
if (typeof value === "string" && value.startsWith("BigInt::")) {
|
||||||
|
return BigInt(value.substring(8));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { dir } from "dir";
|
||||||
|
import { inspectTreeAsync } from "fs-jetpack";
|
||||||
|
import { InspectTreeResult } from "fs-jetpack/types";
|
||||||
|
import { join } from "path";
|
||||||
|
import mime from "mime";
|
||||||
|
|
||||||
|
const webPath = "app/static";
|
||||||
|
const cache = {
|
||||||
|
static: {} as Record<string, { type: string; content: any }>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const serveStatic = {
|
||||||
|
init: async () => {
|
||||||
|
const list = await inspectTreeAsync(dir.path(`${webPath}`));
|
||||||
|
const walk = async (
|
||||||
|
list: InspectTreeResult,
|
||||||
|
parent?: InspectTreeResult[]
|
||||||
|
) => {
|
||||||
|
for (const item of list.children) {
|
||||||
|
if (item.type === "file") {
|
||||||
|
const path = join(
|
||||||
|
...(parent || [{ name: "static" }]).map((e) => e.name),
|
||||||
|
item.name
|
||||||
|
);
|
||||||
|
const file = await Bun.file(dir.path(`app/${path}`));
|
||||||
|
if (await file.exists()) {
|
||||||
|
cache.static[path.substring("static".length)] = {
|
||||||
|
type: mime.getType(path) || "application/octet-stream",
|
||||||
|
content: await file.arrayBuffer(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await walk(item, parent ? [...parent, list] : [list]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (list) {
|
||||||
|
await walk(list);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exists: (url: URL) => {
|
||||||
|
return !!cache.static[url.pathname];
|
||||||
|
},
|
||||||
|
serve: (url: URL) => {
|
||||||
|
const file = cache.static[url.pathname];
|
||||||
|
if (file) {
|
||||||
|
return new Response(file.content, {
|
||||||
|
headers: { "content-type": file.type },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = cache.static["/index.html"];
|
||||||
|
if (index) {
|
||||||
|
return new Response(index.content, {
|
||||||
|
headers: { "content-type": index.type },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { WebSocketHandler } from "bun";
|
||||||
|
import { WSData } from "./create";
|
||||||
|
|
||||||
|
export const serveWS: () => Promise<WebSocketHandler<WSData>> = async () => {
|
||||||
|
const { wsHandler } = await import("../../../app/srv/ws/handler");
|
||||||
|
|
||||||
|
return {
|
||||||
|
maxPayloadLength: 9999999,
|
||||||
|
closeOnBackpressureLimit: true,
|
||||||
|
drain(ws) {
|
||||||
|
// console.log("Backpressure relieved...");
|
||||||
|
},
|
||||||
|
close(ws, code, reason) {
|
||||||
|
const pathname = ws.data.url.pathname;
|
||||||
|
if (wsHandler[pathname]) {
|
||||||
|
const close = wsHandler[pathname].close;
|
||||||
|
if (close) {
|
||||||
|
close(ws, code, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
message(ws, message) {
|
||||||
|
const pathname = ws.data.url.pathname;
|
||||||
|
if (wsHandler[pathname]) {
|
||||||
|
const msg = wsHandler[pathname].message;
|
||||||
|
if (msg) {
|
||||||
|
msg(ws, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
open(ws) {
|
||||||
|
const pathname = ws.data.url.pathname;
|
||||||
|
if (wsHandler[pathname]) {
|
||||||
|
const open = wsHandler[pathname].open;
|
||||||
|
if (open) {
|
||||||
|
open(ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
} as WebSocketHandler<WSData>;
|
||||||
|
};
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
"./node_modules/.prisma/client/index.d.ts"
|
"./node_modules/.prisma/client/index.d.ts"
|
||||||
],
|
],
|
||||||
"service-srv": [
|
"service-srv": [
|
||||||
"./pkgs/core/server/api-ctx.ts"
|
"./pkgs/core/server/api/api-ctx.ts"
|
||||||
],
|
],
|
||||||
"utils/*": [
|
"utils/*": [
|
||||||
"./pkgs/core/utils/*"
|
"./pkgs/core/utils/*"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue