This commit is contained in:
Rizky 2023-10-19 07:06:29 +00:00
parent b1682f5ab9
commit 86c8f16aee
26 changed files with 398 additions and 177 deletions

View File

@ -1,4 +1,3 @@
import { compress } from "lz-string";
import { syncronize } from "y-pojo";
import * as Y from "yjs";
import { MPage } from "../../web/src/utils/types/general";
@ -18,9 +17,7 @@ export const _ = {
syncronize(root as any, rawPage);
const um = new Y.UndoManager(root, { ignoreRemoteMapChanges: true });
const broadcast = () => {
const sv_local = compress(
Y.encodeStateVector(ydoc as any).toString()
);
const sv_local = Y.encodeStateVector(ydoc as any).toString();
const broadcast: WS_MSG_SV_LOCAL = {
type: "sv_local",
sv_local,
@ -40,7 +37,7 @@ export const _ = {
eg.edit.page[page_id].ws.forEach((w) => {
const sent: WS_MSG_SET_PAGE = {
type: "set_page",
changes: compress(Y.encodeStateAsUpdate(ydoc as any).toString()),
changes: Y.encodeStateAsUpdate(ydoc as any).toString(),
};
w.send(JSON.stringify(sent));
});

View File

@ -13,7 +13,7 @@ export const _ = {
const { req, res } = apiContext(this);
if (!cache.md5) {
const content = await readAsync(dir.path("srv/site.zip"), "buffer");
const content = await readAsync(dir.path("app/srv/site.zip"), "buffer");
if (content) {
cache.md5 = createHash("md5").update(content).digest("hex");

View File

@ -24,36 +24,36 @@ export const _ = {
}
}
const site = await db.site.findFirst({
where: { id: site_id },
select: { js: true },
});
// const site = await db.site.findFirst({
// where: { id: site_id },
// select: { js: true },
// });
if (site && site.js) {
const options = {
emitDeclarationOnly: true,
declaration: 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;";
// 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 program = ts.createProgram(["sitedts"], options, host);
// program.emit();
const etag = createHash("md5").update(dtsrc).digest("hex");
if (!sent) res.setHeader("etag", etag);
// const etag = createHash("md5").update(dtsrc).digest("hex");
// if (!sent) res.setHeader("etag", etag);
dts[site_id] = { etag, dts: dtsrc };
// dts[site_id] = { etag, dts: dtsrc };
if (sent) {
return "";
}
return dtsrc;
}
// if (sent) {
// return "";
// }
// return dtsrc;
// }
res.setHeader("etag", "empty");
return "";

View File

@ -7,9 +7,7 @@
"@node-rs/argon2": "^1.5.2",
"@paralleldrive/cuid2": "^2.2.2",
"@types/mime-types": "^2.1.2",
"brotli-wasm": "^2.0.1",
"esbuild": "^0.19.4",
"lz-string": "^1.5.0",
"mime-types": "^2.1.35",
"radix3": "^1.1.0"
}

BIN
app/srv/site.zip Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
app/srv/site/site.js Normal file
View File

@ -0,0 +1,2 @@
import{a as E,b as r,c as L,d as h,g as d,j as u,k as y,l as m,m as i}from"./chunk-DH54TKQS.js";var g=E(c=>{"use strict";var f=h();c.createRoot=f.createRoot,c.hydrateRoot=f.hydrateRoot;var b});var w=r(L()),R=r(g());var C=`/_web/${window.id_site}`,a={site:null,pages:[],api:null},_={async site(n,e){let t=await p("/site?prod=1");return a.site=t.site,a.pages=t.pages,a.api=t.api,i.serverurl=t.site.config.api_url,i.apiurl=t.site.config.api_url,i.prasiApi={[t.site.config.api_url]:{apiEntry:t.api}},t.site},async comp(n,e){let t=await p(`/comp/${e}`);return n.comps.all[e]=t,t},npm(n,e,t){return e==="site"?`/_web/${a.site.id}/npm-site/site.js`:`/_web/${a.site.id}/npm-page/${t}/page.js`},async page(n,e){let t=a.pages.find(o=>o.id===e);return t&&!t.content_tree?await p(`/page/${e}`):null},async pages(n,e){return a.pages}},p=async n=>{let t=await(await fetch(`${C}${n}`)).text();return JSON.parse(t)};var s=r(u()),l=window;l.prasiContext={global:{},render(){}};var x=({url:n,Live:e})=>{let[t,o]=(0,w.useState)({});l.prasiContext.render=()=>{o({})};let v=d.Provider;return(0,s.jsx)(v,{value:l.prasiContext,children:(0,s.jsx)(e,{domain:n.host,pathname:location.pathname,loader:_})})};(async()=>{let n=document.getElementById("root");if(n){let e=(0,R.createRoot)(n),t=new URL(location.href);await m(!1),y();let{Live:o}=await import("./live-4QMOJQZB.js");e.render((0,s.jsx)(x,{url:t,Live:o})),document.body.classList.contains("opacity-0")&&document.body.classList.remove("opacity-0")}})();
//# sourceMappingURL=site.js.map

View File

@ -1,17 +1,13 @@
import { Websocket } from "hyper-express";
import { decompress } from "lz-string";
import * as Y from "yjs";
import { eg } from "../edit-global";
export const diffLocal = (ws: Websocket, msg: any) => {
export const diffLocal = (ws: any, msg: any) => {
return new Promise<void>((resolve) => {
const diff_local = Uint8Array.from(
decompress(msg.diff_local)
.split(",")
.map((x) => parseInt(x, 10))
msg.diff_local.split(",").map((x: any) => parseInt(x, 10))
);
let doc = null as unknown as Y.Doc;
let wss: Set<Websocket> = null as any;
let wss: Set<any> = null as any;
let um: Y.UndoManager = null as any;
if (msg.mode === "page") {
doc = eg.edit.page[msg.id].doc as any;

View File

@ -1,15 +1,14 @@
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 { SingleComp, eg } from "../edit-global";
import {
WS_MSG_GET_COMP,
WS_MSG_SET_COMP,
WS_MSG_SV_LOCAL,
} from "../../../../web/src/utils/types/ws";
import { validate } from "uuid";
import { SingleComp, eg } from "../edit-global";
export const getComp = async (
ws: ServerWebSocket<WSData>,
msg: WS_MSG_GET_COMP
@ -52,7 +51,7 @@ export const getComp = async (
const ws = new Set<ServerWebSocket<WSData>>();
const um = new Y.UndoManager(map, { ignoreRemoteMapChanges: true });
const broadcast = () => {
const sv_local = compress(Y.encodeStateVector(ydoc as any).toString());
const sv_local = Y.encodeStateVector(ydoc as any).toString();
const broadcast: WS_MSG_SV_LOCAL = {
type: "sv_local",
sv_local,
@ -79,7 +78,7 @@ export const getComp = async (
const sent: WS_MSG_SET_COMP = {
type: "set_comp",
comp_id: comp_id,
changes: compress(Y.encodeStateAsUpdate(comp.doc as any).toString()),
changes: Y.encodeStateAsUpdate(comp.doc as any).toString(),
};
ws.send(JSON.stringify(sent));
}

View File

@ -1,5 +1,4 @@
import { ServerWebSocket } from "bun";
import { compress } from "lz-string";
import { validate } from "uuid";
import { syncronize } from "y-pojo";
import * as Y from "yjs";
@ -29,7 +28,7 @@ export const getPage = async (
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());
const sv_local = Y.encodeStateVector(ydoc as any).toString();
const broadcast: WS_MSG_SV_LOCAL = {
type: "sv_local",
sv_local,
@ -55,7 +54,7 @@ export const getPage = async (
page.ws.add(ws);
const sent: WS_MSG_SET_PAGE = {
type: "set_page",
changes: compress(Y.encodeStateAsUpdate(page.doc as any).toString()),
changes: Y.encodeStateAsUpdate(page.doc as any).toString(),
};
ws.send(JSON.stringify(sent));
};

View File

@ -1,19 +1,15 @@
import { Websocket } from "hyper-express";
import { compress, decompress } from "lz-string";
import * as Y from "yjs";
import {
WS_MSG_SVDIFF_REMOTE,
WS_MSG_SV_LOCAL,
} from "../../../web/src/utils/types/ws";
} from "../../../../web/src/utils/types/ws";
import { eg } from "../edit-global";
import { getComp } from "./get-comp";
import { getPage } from "./get-page";
export const svLocal = async (ws: Websocket, msg: WS_MSG_SV_LOCAL) => {
export const svLocal = async (ws: any, msg: WS_MSG_SV_LOCAL) => {
const changes = Uint8Array.from(
decompress(msg.sv_local)
.split(",")
.map((x) => parseInt(x, 10))
(msg.sv_local || '').split(",").map((x) => parseInt(x, 10))
);
let doc = null as any;
if (msg.mode === "page") {
@ -37,8 +33,8 @@ export const svLocal = async (ws: Websocket, msg: WS_MSG_SV_LOCAL) => {
const sv_remote = Y.encodeStateVector(doc);
const sendmsg: WS_MSG_SVDIFF_REMOTE = {
diff_remote: compress(diff_remote.toString()),
sv_remote: compress(sv_remote.toString()),
diff_remote: diff_remote.toString(),
sv_remote: sv_remote.toString(),
id: msg.id,
mode: msg.mode,
type: "svd_remote",

View File

@ -1,25 +1,16 @@
import { Websocket } from "hyper-express";
import { compress, decompress } from "lz-string";
import * as Y from "yjs";
import {
WS_MSG_DIFF_LOCAL,
WS_MSG_SVDIFF_REMOTE,
} from "../../../web/src/utils/types/ws";
} from "../../../../web/src/utils/types/ws";
import { eg } from "../edit-global";
export const svdiffRemote = async (
ws: Websocket,
msg: WS_MSG_SVDIFF_REMOTE
) => {
export const svdiffRemote = async (ws: any, msg: WS_MSG_SVDIFF_REMOTE) => {
const sv_remote = Uint8Array.from(
decompress(msg.sv_remote)
.split(",")
.map((x) => parseInt(x, 10))
msg.sv_remote.split(",").map((x) => parseInt(x, 10))
);
const diff_remote = Uint8Array.from(
decompress(msg.diff_remote)
.split(",")
.map((x) => parseInt(x, 10))
msg.diff_remote.split(",").map((x) => parseInt(x, 10))
);
let doc = null as any;
@ -39,7 +30,7 @@ export const svdiffRemote = async (
type: "diff_local",
mode: msg.mode,
id: msg.id,
diff_local: compress(diff_local.toString()),
diff_local: diff_local.toString(),
};
ws.send(JSON.stringify(sendmsg));
}

View File

@ -1,7 +1,5 @@
import { createId } from "@paralleldrive/cuid2";
import brotliPromise from "brotli-wasm";
import { WebSocketHandler } from "bun";
import { decompress } from "lz-string";
import { WSData } from "../../../pkgs/core/server/create";
import { WS_MSG } from "../../web/src/utils/types/ws";
import { diffLocal } from "./edit/action/diff-local";
@ -22,7 +20,6 @@ const site = {
saveTimeout: null as any,
};
const brotli = await brotliPromise;
export const wsHandler: Record<string, WebSocketHandler<WSData>> = {
"/edit": {
open(ws) {
@ -44,7 +41,7 @@ export const wsHandler: Record<string, WebSocketHandler<WSData>> = {
case "site-js":
clearTimeout(site.saveTimeout);
site.saveTimeout = setTimeout(async () => {
const js = JSON.parse(decompress(msg.src));
const js = JSON.parse(msg.src);
await db.site.update({
where: {
id: msg.id_site,

View File

@ -15,7 +15,6 @@
"@parcel/service-worker": "^2.10.0",
"@swc/wasm-web": "1.3.94-nightly-20231014.1",
"algoliasearch": "^4.20.0",
"brotli-dec-wasm": "^2.0.1",
"date-fns": "^2.30.0",
"dbgen": "workspace:*",
"downshift": "^8.2.2",
@ -37,7 +36,6 @@
"lodash.trim": "4.5.1",
"lodash.uniq": "^4.5.0",
"lodash.uniqby": "^4.7.0",
"lz-string": "1.5.0",
"monaco-jsx-syntax-highlight-v2": "^1.2.2",
"polywasm": "^0.1.4",
"prettier": "3.0.3",

View File

@ -1,7 +1,6 @@
import { PG } from "./global";
import throttle from "lodash.throttle";
import { compress, decompress } from "lz-string";
import * as Y from "yjs";
import { CompDoc } from "../../../base/global/content-editor";
import { MPage } from "../../../utils/types/general";
@ -15,7 +14,6 @@ import {
WS_MSG_SV_LOCAL,
} from "../../../utils/types/ws";
import { scanComponent } from "./comp";
import { execSiteJS } from "./init";
import { rebuildTree } from "./tree-logic";
const timeout = {
@ -134,9 +132,7 @@ export const editorWS = async (p: PG) => {
type: "sv_local",
mode: "page",
id,
sv_local: compress(
Y.encodeStateVector(doc as any).toString()
),
sv_local: Y.encodeStateVector(doc as any).toString(),
};
wsend(p, JSON.stringify(sendmsg));
}
@ -207,9 +203,9 @@ export const editorWS = async (p: PG) => {
type: "sv_local",
mode: "comp",
id,
sv_local: compress(
Y.encodeStateVector(doc as any).toString()
),
sv_local: Y.encodeStateVector(
doc as any
).toString(),
};
wsend(p, JSON.stringify(sendmsg));
}
@ -259,11 +255,7 @@ export const editorWS = async (p: PG) => {
};
const extract = (str: string) => {
return Uint8Array.from(
decompress(str)
.split(",")
.map((x) => parseInt(x, 10))
);
return Uint8Array.from(str.split(",").map((x) => parseInt(x, 10)));
};
const svLocal = async (arg: {
@ -287,8 +279,8 @@ const svLocal = async (arg: {
const sv_remote = Y.encodeStateVector(doc);
const sendmsg: any = {
diff_remote: compress(diff_remote.toString()),
sv_remote: compress(sv_remote.toString()),
diff_remote: diff_remote.toString(),
sv_remote: sv_remote.toString(),
id: id,
mode: mode,
type: type,
@ -304,14 +296,10 @@ const svdRemote = async (arg: {
const { bin, msg, p } = arg;
const { id, mode, type } = msg;
const sv_remote = Uint8Array.from(
decompress(msg.sv_remote)
.split(",")
.map((x) => parseInt(x, 10))
msg.sv_remote.split(",").map((x) => parseInt(x, 10))
);
const diff_remote = Uint8Array.from(
decompress(msg.diff_remote)
.split(",")
.map((x) => parseInt(x, 10))
msg.diff_remote.split(",").map((x) => parseInt(x, 10))
);
const sendDoc = async (doc: any) => {
@ -321,7 +309,7 @@ const svdRemote = async (arg: {
type: "diff_local",
mode: msg.mode,
id: msg.id,
diff_local: compress(diff_local.toString()),
diff_local: diff_local.toString(),
};
await wsend(p, JSON.stringify(sendmsg));
};
@ -354,9 +342,7 @@ export const wsend = async (local: PG, payload: string) => {
const setPage = async (msg: WS_MSG_SET_PAGE) => {
const page = Uint8Array.from(
decompress(msg.changes)
.split(",")
.map((x) => parseInt(x, 10))
msg.changes.split(",").map((x) => parseInt(x, 10))
);
const doc = new Y.Doc();

View File

@ -1,4 +1,3 @@
import { compress } from "lz-string";
import { useEffect } from "react";
import { useGlobal, useLocal } from "web-utils";
import { w } from "../../../../../utils/types/general";
@ -85,7 +84,7 @@ export const ToolbarCenter = () => {
JSON.stringify({
type: "site-js",
id_site: p.site.id,
src: compress(JSON.stringify({ src, compiled })),
src: JSON.stringify({ src, compiled }),
})
);
}}

View File

@ -5,7 +5,7 @@ const base = `/_web/${(window as any).id_site}`;
const cache = { site: null as any, pages: [] as any, api: null };
export const SiteLoader: Loader = {
export const siteLoader: Loader = {
async site(p, id) {
const res = (await load(`/site?prod=1`)) as {
site: any;

BIN
bun.lockb

Binary file not shown.

View File

@ -5,7 +5,6 @@ export const _ = {
url: "/_api_frm",
async api() {
const { req, res } = apiContext(this);
let allowUrl = req.headers.get("origin") || req.headers.get("referer");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT");

View File

@ -9,6 +9,7 @@ export const _ = {
try {
const result = await execQuery(req.params, db);
res.send(result);
} catch (e: any) {
res.sendStatus(500);
res.send(e.message);

View File

@ -1,52 +1,103 @@
import { spawn } from "bun";
import { dir } from "dir";
import { statSync } from "fs";
import { listAsync, removeAsync, writeAsync } from "fs-jetpack";
import brotliPromise from "brotli-wasm";
const brotli = await brotliPromise;
import { Plugin, context } from "esbuild";
import { $ } from "execa";
import { removeAsync, writeAsync } from "fs-jetpack";
await removeAsync(dir.path("app/static"));
await removeAsync(dir.path("app/web/.parcel-cache"));
await removeAsync(dir.path("app/static"));
// await removeAsync(dir.path("app/static"));
// await removeAsync(dir.path("app/web/.parcel-cache"));
// await removeAsync(dir.path("app/static"));
const args = [
"node",
dir.path("node_modules/.bin/parcel"),
"build",
"./src/index.tsx",
// "--no-optimize",
"--no-scope-hoist",
"--dist-dir",
dir.path(`app/static`),
];
// const args = [
// "node",
// dir.path("node_modules/.bin/parcel"),
// "build",
// "./src/index.tsx",
// // "--no-optimize",
// "--no-scope-hoist",
// "--dist-dir",
// dir.path(`app/static`),
// ];
const parcel = spawn({
cmd: args,
cwd: dir.path("app/web"),
stdio: ["ignore", "inherit", "inherit"],
});
await parcel.exited;
// const parcel = spawn({
// cmd: args,
// cwd: dir.path("app/web"),
// stdio: ["ignore", "inherit", "inherit"],
// });
// await parcel.exited;
listAsync(dir.path("app/static")).then(async (files) => {
if (files) {
await removeAsync(dir.path("app/static-br"));
await Promise.all(
files
.filter((e) => statSync(dir.path(`app/static/${e}`)).isFile())
.map(async (file) => {
const br = brotli.compress(
new Uint8Array(
await Bun.file(dir.path(`app/static/${file}`)).arrayBuffer()
)
);
if (br) {
console.log(`Compressing ${file}`);
await writeAsync(
dir.path(`app/static-br/${file}`),
Buffer.from(br)
);
}
})
);
}
});
// listAsync(dir.path("app/static")).then(async (files) => {
// if (files) {
// await removeAsync(dir.path("app/static-br"));
// await Promise.all(
// files
// .filter((e) => statSync(dir.path(`app/static/${e}`)).isFile())
// .map(async (file) => {
// const br = brotli.compress(
// new Uint8Array(
// await Bun.file(dir.path(`app/static/${file}`)).arrayBuffer()
// )
// );
// if (br) {
// console.log(`Compressing ${file}`);
// await writeAsync(
// dir.path(`app/static-br/${file}`),
// Buffer.from(br)
// );
// }
// })
// );
// }
// });
const buildSite = async () => {
await removeAsync(dir.path("app/srv/site"));
const onEndPlugin: Plugin = {
name: "on-end",
setup(build) {
build.onEnd(async (result) => {
console.log("Compressing deploy");
await removeAsync(dir.path("app/srv/site.zip"));
await $({ cwd: dir.path("app/srv") })`zip -r site.zip site`;
process.exit(0);
});
},
};
console.log("Building deploy");
const ctx = await context({
bundle: true,
absWorkingDir: dir.path(""),
entryPoints: [dir.path("app/web/src/render/site/site.tsx")],
outdir: dir.path("app/srv/site"),
splitting: true,
format: "esm",
jsx: "transform",
minify: true,
sourcemap: true,
logLevel: "error",
plugins: [onEndPlugin],
define: {
"process.env.NODE_ENV": `"production"`,
},
});
await ctx.rebuild();
await writeAsync(
dir.path("app/srv/site/index.html"),
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<link rel="stylesheet" href="https://prasi.app/index.css">
</head>
<body class="flex-col flex-1 w-full min-h-screen flex opacity-0">
<div id="root"></div>
<script src="/site.js" type="module"></script>
</body>
</html>`
);
};
await buildSite();

View File

@ -6,7 +6,7 @@
"@swc/core": "^1.3.91",
"@types/mime": "^3.0.2",
"@types/unzipper": "^0.10.7",
"brotli-wasm": "^2.0.1",
"esbuild": "^0.19.5",
"execa": "^8.0.1",
"fs-jetpack": "^5.1.0",
"lmdb": "^2.8.5",

View File

@ -11,8 +11,7 @@ export const cache = {
string,
{
type: string;
content: ReadableStream<Uint8Array>;
br?: ReadableStream<Uint8Array>;
content: ArrayBuffer;
}
>,
};
@ -30,6 +29,7 @@ export const createServer = async () => {
port: g.port,
websocket: {
maxPayloadLength: 9999999,
closeOnBackpressureLimit: true,
close(ws, code, reason) {
const pathname = ws.data.url.pathname;
if (wsHandler[pathname]) {
@ -99,7 +99,7 @@ export const createServer = async () => {
if (!cache.static[url.pathname]) {
cache.static[url.pathname] = {
type: lookup(url.pathname) || "text/plain",
content: file.stream(),
content: await file.arrayBuffer(),
};
}
const found = cache.static[url.pathname];
@ -115,6 +115,7 @@ export const createServer = async () => {
return new Response(Bun.file(dir.path(`${webPath}/index.html`)) as any);
} catch (e) {
g.log.error(e);
return new Response("Loading...");
}
},

View File

@ -19,21 +19,31 @@ export const ${name} = {
await Bun.write(dir.path(`app/srv/exports.ts`), out.join(`\n`));
const targetFile = dir.path("app/srv/exports.d.ts");
const tsc = spawn(
[
dir.path("node_modules/.bin/tsc"),
dir.path("app/srv/exports.ts"),
"--declaration",
"--emitDeclarationOnly",
"--outFile",
targetFile,
],
{
cwd: dir.path(`node_modules/.bin`),
}
);
await tsc.exited;
const args = [
dir.path("node_modules/.bin/tsc"),
dir.path("app/srv/exports.ts"),
"--declaration",
"--emitDeclarationOnly",
"--outFile",
targetFile,
];
if (g.mode === "dev") {
const tsc = spawn(
[
dir.path("node_modules/.bin/tsc"),
dir.path("app/srv/exports.ts"),
"--declaration",
"--emitDeclarationOnly",
"--outFile",
targetFile,
],
{
cwd: dir.path(`node_modules/.bin`),
}
);
await tsc.exited;
}
let res = await readAsync(targetFile);
if (res) {

View File

@ -1,13 +1,8 @@
import { spawn } from "bun";
import { dirAsync, inspectTreeAsync, writeAsync } from "fs-jetpack";
import { InspectTreeResult } from "fs-jetpack/types";
import { cache } from "../server/create";
import { dirAsync } from "fs-jetpack";
import { dir } from "./dir";
import { g } from "./global";
import { lookup } from "mime-types";
import brotliPromise from "brotli-wasm";
const brotli = await brotliPromise;
const decoder = new TextDecoder();
export const parcelBuild = async () => {