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>;
};
}
declare module "api/site-dts" {
export const _: {
url: string;
api(site_id: string): Promise<string>;
};
}
declare module "exports" {
export const login: {
name: string;
@ -73,6 +79,13 @@ declare module "exports" {
args: string[];
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: {
name: string;
url: string;

View File

@ -19,6 +19,13 @@ export const npm = {
args: ["mode","id"],
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 = {
name: "_upload",
url: "/_upload",

View File

@ -1,18 +1,22 @@
import { Websocket } from "hyper-express";
import { ServerWebSocket } from "bun";
import { compress } from "lz-string";
import { validate } from "uuid";
import { syncronize } from "y-pojo";
import * as Y from "yjs";
import { WSData } from "../../../../../pkgs/core/server/create";
import { MPage } from "../../../../web/src/utils/types/general";
import {
WS_MSG_GET_PAGE,
WS_MSG_SET_PAGE,
WS_MSG_SV_LOCAL,
} from "../../../web/src/utils/types/ws";
import { MPage } from "../../../web/src/utils/types/general";
} from "../../../../web/src/utils/types/ws";
import { eg } from "../edit-global";
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;
if (!validate(page_id)) return;
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;
let root = ydoc.getMap("map");
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 broadcast = () => {
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];
// 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);
const sent: WS_MSG_SET_PAGE = {

View File

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

View File

@ -20,11 +20,12 @@ export const defaultLoader: Loader = {
const cgroups = await db.site_use_comp.findMany({
where: { id_site: site.id },
select: { use_id_site: true },
});
if (cgroups) {
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);
}
}

View File

@ -1,5 +1,5 @@
import { FC } 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";
@ -55,7 +55,10 @@ export type LSite = {
config?: any;
};
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>;
pages: (p: PG, site_id: string) => Promise<LPage[]>;
npm: (p: PG, type: "site" | "page", id: string) => string;

View File

@ -81,7 +81,7 @@ export const _ = {
export const getApiEntry = () => {
const res: any = {};
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}` };
}
@ -108,7 +108,8 @@ const getPrisma = async (path: string) => {
if (path === "prisma")
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`)
);
@ -121,7 +122,9 @@ const getPrisma = async (path: string) => {
if (path === "library")
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({});

View File

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

View File

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

View File

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