This commit is contained in:
Rizky 2023-10-14 22:22:42 +07:00
parent 3a897090c6
commit 415f42cefc
11 changed files with 110 additions and 35 deletions

61
app/srv/api/site-dts.ts Normal file
View File

@ -0,0 +1,61 @@
import { apiContext } from "service-srv";
import ts from "typescript";
import { createHash } from "crypto";
const dts = {} as Record<string, { etag: string; dts: string }>;
export const _ = {
url: "/site-dts/:site_id",
async api(site_id: string) {
const { req, res } = apiContext(this);
let sent = false;
if (dts[site_id]) {
res.setHeader("etag", dts[site_id].etag);
if (dts[site_id].etag === req.headers.get("if-none-match")) {
res.sendStatus(304);
sent = true;
}
if (!sent) {
sent = true;
res.send(dts[site_id].dts);
}
}
const site = await db.site.findFirst({
where: { id: site_id },
select: { js: true },
});
if (site && site.js) {
const options = {
emitDeclarationOnly: true,
declaration: true,
};
let dtsrc = "";
const host = ts.createCompilerHost(options);
host.writeFile = (fileName, contents) => (dtsrc = contents);
host.readFile = () =>
(site.js || "") + "\n\nexport const ______: string;";
const program = ts.createProgram(["sitedts"], options, host);
program.emit();
const etag = createHash("md5").update(dtsrc).digest("hex");
if (!sent) res.setHeader("etag", etag);
dts[site_id] = { etag, dts: dtsrc };
if (sent) {
return "";
}
return dtsrc;
}
res.setHeader("etag", "empty");
return "";
},
};

13
app/srv/exports.d.ts vendored
View File

@ -51,6 +51,12 @@ declare module "api/npm" {
api(mode: "site" | "page", id: string): Promise<void>; api(mode: "site" | "page", id: string): Promise<void>;
}; };
} }
declare module "api/site-dts" {
export const _: {
url: string;
api(site_id: string): Promise<string>;
};
}
declare module "exports" { declare module "exports" {
export const login: { export const login: {
name: string; name: string;
@ -73,6 +79,13 @@ declare module "exports" {
args: string[]; args: string[];
handler: Promise<typeof import("api/npm")>; handler: Promise<typeof import("api/npm")>;
}; };
export const site_dts: {
name: string;
url: string;
path: string;
args: string[];
handler: Promise<typeof import("api/site-dts")>;
};
export const _upload: { export const _upload: {
name: string; name: string;
url: string; url: string;

View File

@ -19,6 +19,13 @@ export const npm = {
args: ["mode","id"], args: ["mode","id"],
handler: import("./api/npm") handler: import("./api/npm")
} }
export const site_dts = {
name: "site_dts",
url: "/site-dts/:site_id",
path: "app/srv/api/site-dts.ts",
args: ["site_id"],
handler: import("./api/site-dts")
}
export const _upload = { export const _upload = {
name: "_upload", name: "_upload",
url: "/_upload", url: "/_upload",

View File

@ -1,18 +1,22 @@
import { Websocket } from "hyper-express"; import { ServerWebSocket } from "bun";
import { compress } from "lz-string"; import { compress } from "lz-string";
import { validate } from "uuid";
import { syncronize } from "y-pojo"; import { syncronize } from "y-pojo";
import * as Y from "yjs"; import * as Y from "yjs";
import { WSData } from "../../../../../pkgs/core/server/create";
import { MPage } from "../../../../web/src/utils/types/general";
import { import {
WS_MSG_GET_PAGE, WS_MSG_GET_PAGE,
WS_MSG_SET_PAGE, WS_MSG_SET_PAGE,
WS_MSG_SV_LOCAL, WS_MSG_SV_LOCAL,
} from "../../../web/src/utils/types/ws"; } from "../../../../web/src/utils/types/ws";
import { MPage } from "../../../web/src/utils/types/general";
import { eg } from "../edit-global"; import { eg } from "../edit-global";
import { loadPage } from "../tools/load-page"; import { loadPage } from "../tools/load-page";
import { validate } from "uuid";
export const getPage = async (ws: Websocket, msg: WS_MSG_GET_PAGE) => { export const getPage = async (
ws: ServerWebSocket<WSData>,
msg: WS_MSG_GET_PAGE
) => {
const page_id = msg.page_id; const page_id = msg.page_id;
if (!validate(page_id)) return; if (!validate(page_id)) return;
if (!eg.edit.page[page_id]) { if (!eg.edit.page[page_id]) {
@ -22,7 +26,7 @@ export const getPage = async (ws: Websocket, msg: WS_MSG_GET_PAGE) => {
const ydoc = new Y.Doc() as MPage; const ydoc = new Y.Doc() as MPage;
let root = ydoc.getMap("map"); let root = ydoc.getMap("map");
syncronize(root as any, rawPage); syncronize(root as any, rawPage);
const ws = new Set<Websocket>(); const ws = new Set<ServerWebSocket<WSData>>();
const um = new Y.UndoManager(root, { ignoreRemoteMapChanges: true }); const um = new Y.UndoManager(root, { ignoreRemoteMapChanges: true });
const broadcast = () => { const broadcast = () => {
const sv_local = compress(Y.encodeStateVector(ydoc as any).toString()); const sv_local = compress(Y.encodeStateVector(ydoc as any).toString());
@ -47,23 +51,6 @@ export const getPage = async (ws: Websocket, msg: WS_MSG_GET_PAGE) => {
} }
const page = eg.edit.page[page_id]; const page = eg.edit.page[page_id];
// let root = page.doc.getMap("map").get("content_tree") as unknown as MContent;
// if (root) {
// let changed = false;
// await page.doc.transact(async () => {
// changed = await validateTreePage(ws, root);
// });
// if (changed) {
// root = page.doc.getMap("map").get("content_tree") as unknown as MContent;
// await db.page.update({
// where: {
// id: page.id,
// },
// data: { content_tree: root.toJSON(), updated_at: new Date() },
// });
// }
// }
page.ws.add(ws); page.ws.add(ws);
const sent: WS_MSG_SET_PAGE = { const sent: WS_MSG_SET_PAGE = {

View File

@ -12,7 +12,6 @@ export const loadPage = async (page_id: string) => {
id_site: true, id_site: true,
url: true, url: true,
js_compiled: true, js_compiled: true,
updated_at: true,
content_tree: true, content_tree: true,
}, },
})) as unknown as null | Page; })) as unknown as null | Page;

View File

@ -20,11 +20,12 @@ export const defaultLoader: Loader = {
const cgroups = await db.site_use_comp.findMany({ const cgroups = await db.site_use_comp.findMany({
where: { id_site: site.id }, where: { id_site: site.id },
select: { use_id_site: true },
}); });
if (cgroups) { if (cgroups) {
site.cgroup_ids = []; site.cgroup_ids = [];
for (const id of cgroups.map((c) => c.use_id_site)) { for (const id of cgroups.map((c: any) => c.use_id_site)) {
site.cgroup_ids.push(id); site.cgroup_ids.push(id);
} }
} }

View File

@ -1,5 +1,5 @@
import { FC } from "react"; import { FC } from "react";
import { createRouter } from "web-utils"; import { createRouter } from "radix3";
import { CompDoc } from "../../../base/global/content-editor"; import { CompDoc } from "../../../base/global/content-editor";
import { IContent, MContent, MPage } from "../../../utils/types/general"; import { IContent, MContent, MPage } from "../../../utils/types/general";
import { IItem, MItem } from "../../../utils/types/item"; import { IItem, MItem } from "../../../utils/types/item";
@ -55,7 +55,10 @@ export type LSite = {
config?: any; config?: any;
}; };
export type Loader = { export type Loader = {
site: (p: PG, where: { domain: string } | { id: string }) => Promise<LSite>; site: (
p: PG,
where: { domain: string } | { id: string }
) => Promise<LSite | null>;
page: (p: PG, id: string) => Promise<LPage | null>; page: (p: PG, id: string) => Promise<LPage | null>;
pages: (p: PG, site_id: string) => Promise<LPage[]>; pages: (p: PG, site_id: string) => Promise<LPage[]>;
npm: (p: PG, type: "site" | "page", id: string) => string; npm: (p: PG, type: "site" | "page", id: string) => string;

View File

@ -81,7 +81,7 @@ export const _ = {
export const getApiEntry = () => { export const getApiEntry = () => {
const res: any = {}; const res: any = {};
for (const [k, v] of Object.entries(g.api)) { for (const [k, v] of Object.entries(g.api)) {
const name = k.substring(0, k.length - 3); const name = k.substring(0, k.length - 3).replace(/\W/gi, "_");
res[name] = { ...v, name, path: `app/srv/api/${v.path}` }; res[name] = { ...v, name, path: `app/srv/api/${v.path}` };
} }
@ -108,7 +108,8 @@ const getPrisma = async (path: string) => {
if (path === "prisma") if (path === "prisma")
return JSON.stringify( return JSON.stringify(
( (
(await readAsync(dir.path("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`) ).replace(`@prisma/client/runtime/library`, `./runtime/library`)
); );
@ -121,7 +122,9 @@ const getPrisma = async (path: string) => {
if (path === "library") if (path === "library")
return JSON.stringify( return JSON.stringify(
await readAsync(dir.path("node_modules/@prisma/client/runtime/library.d.ts")) await readAsync(
dir.path("node_modules/@prisma/client/runtime/library.d.ts")
)
); );
return JSON.stringify({}); return JSON.stringify({});

View File

@ -15,7 +15,7 @@ export const createServer = async () => {
g.server = Bun.serve({ g.server = Bun.serve({
port: g.port, port: g.port,
websocket: { websocket: {
maxPayloadLength: 99999999, maxPayloadLength: 9999999,
close(ws, code, reason) { close(ws, code, reason) {
const pathname = ws.data.url.pathname; const pathname = ws.data.url.pathname;
if (wsHandler[pathname]) { if (wsHandler[pathname]) {

View File

@ -20,9 +20,9 @@ export const apiClient = (
if (!api || !api[actionName]) { if (!api || !api[actionName]) {
resolve(null); resolve(null);
console.error( console.error(
`API ${actionName.toString()} not found, existing API: ${Object.keys( `API ${actionName.toString()} not found, existing API: \n - ${Object.keys(
api api
)}` ).join("\n - ")}`
); );
return; return;
} }

View File

@ -1,12 +1,13 @@
import goober from "goober"; import goober from "goober";
import type { PrismaClient } from "../../../app/db/db";
declare global { declare global {
const navigate: (path: string) => void; const navigate: (path: string) => void;
const params: any; const params: any;
const css: typeof goober.css; const css: typeof goober.css;
const cx: (...arg: string[]) => string; const cx: (...arg: string[]) => string;
const api: any; const api: any;
const db: any; const db: PrismaClient;
const prasiContext: any; const prasiContext: any;
const serverurl: string;
} }
export {}; export {};