From de88c0adcf975702fefe4683d1a7e9a76193155d Mon Sep 17 00:00:00 2001 From: Rizky Date: Sat, 14 Oct 2023 13:40:33 +0700 Subject: [PATCH] fix --- app/srv/exports.d.ts | 44 ++++++ app/srv/exports.ts | 42 ++++++ app/web/package.json | 7 +- app/web/src/base/page/all.tsx | 7 +- app/web/src/base/page/live.tsx | 1 + app/web/src/base/pages.ts | 8 ++ app/web/src/base/root.tsx | 60 +++++--- app/web/src/index.tsx | 18 ++- app/web/src/utils/script/init-api.ts | 6 +- bun.lockb | Bin 274175 -> 274917 bytes package.json | 2 +- pkgs/core/server/api-scan.ts | 2 +- pkgs/core/server/create.ts | 27 ++-- pkgs/web-utils/package.json | 2 + pkgs/web-utils/src/client-api.ts | 78 ++++++++++ pkgs/web-utils/src/client-db.ts | 131 +++++++++++++++++ pkgs/web-utils/src/client-frame.ts | 208 +++++++++++++++++++++++++++ pkgs/web-utils/src/define-window.ts | 10 +- pkgs/web-utils/src/export.ts | 3 + pkgs/web-utils/src/global.ts | 8 ++ pkgs/web-utils/src/use-local.ts | 1 - 21 files changed, 614 insertions(+), 51 deletions(-) create mode 100644 pkgs/web-utils/src/client-api.ts create mode 100644 pkgs/web-utils/src/client-db.ts create mode 100644 pkgs/web-utils/src/client-frame.ts diff --git a/app/srv/exports.d.ts b/app/srv/exports.d.ts index e69de29b..2ebf905c 100644 --- a/app/srv/exports.d.ts +++ b/app/srv/exports.d.ts @@ -0,0 +1,44 @@ +declare module "exports" { + export const _web: { + name: string; + url: string; + path: string; + args: string[]; + handler: Promise; + }; + export const _upload: { + name: string; + url: string; + path: string; + args: string[]; + handler: Promise; + }; + export const _prasi: { + name: string; + url: string; + path: string; + args: any[]; + handler: Promise; + }; + export const _file: { + name: string; + url: string; + path: string; + args: any[]; + handler: Promise; + }; + export const _api_frm: { + name: string; + url: string; + path: string; + args: any[]; + handler: Promise; + }; + export const _dbs: { + name: string; + url: string; + path: string; + args: string[]; + handler: Promise; + }; +} diff --git a/app/srv/exports.ts b/app/srv/exports.ts index e69de29b..899dd2c6 100644 --- a/app/srv/exports.ts +++ b/app/srv/exports.ts @@ -0,0 +1,42 @@ +export const _web = { + name: "_web", + url: "/_web/:id/**", + path: "app/srv/api/_web.ts", + args: ["id","_"], + handler: import("./api/_web") +} +export const _upload = { + name: "_upload", + url: "/_upload", + path: "app/srv/api/_upload.ts", + args: ["body"], + handler: import("./api/_upload") +} +export const _prasi = { + name: "_prasi", + url: "/_prasi/**", + path: "app/srv/api/_prasi.ts", + args: [], + handler: import("./api/_prasi") +} +export const _file = { + name: "_file", + url: "/_file/**", + path: "app/srv/api/_file.ts", + args: [], + handler: import("./api/_file") +} +export const _api_frm = { + name: "_api_frm", + url: "/_api_frm", + path: "app/srv/api/_api_frm.ts", + args: [], + handler: import("./api/_api_frm") +} +export const _dbs = { + name: "_dbs", + url: "/_dbs/:dbName/:action", + path: "app/srv/api/_dbs.ts", + args: ["dbName","action"], + handler: import("./api/_dbs") +} \ No newline at end of file diff --git a/app/web/package.json b/app/web/package.json index a788c239..71a1c3cc 100644 --- a/app/web/package.json +++ b/app/web/package.json @@ -15,6 +15,7 @@ "@swc/wasm-web": "1.3.94-nightly-20231014.1", "algoliasearch": "^4.20.0", "date-fns": "^2.30.0", + "dbgen": "workspace:*", "downshift": "^8.2.2", "esbuild-wasm": "^0.19.4", "idb-keyval": "^6.2.1", @@ -40,6 +41,7 @@ "prettier": "3.0.3", "prop-types": "^15.8.1", "quill-delta": "^5.1.0", + "radix3": "^1.1.0", "react": "18.2.0", "react-colorful": "^5.6.1", "react-dnd": "^16.0.1", @@ -52,11 +54,10 @@ "tinycolor2": "^1.6.0", "ua-parser-js": "^1.0.36", "uuid": "9.0.1", + "web-utils": "workspace:*", "y-pojo": "^0.0.8", "yjs": "^13.6.8", - "yjs-types": "^0.0.1", - "web-utils": "workspace:*", - "dbgen": "workspace:*" + "yjs-types": "^0.0.1" }, "devDependencies": { "@types/lodash.concat": "^4.5.7", diff --git a/app/web/src/base/page/all.tsx b/app/web/src/base/page/all.tsx index 4655d4f3..d25b2346 100644 --- a/app/web/src/base/page/all.tsx +++ b/app/web/src/base/page/all.tsx @@ -1,9 +1,12 @@ +import { useEffect } from "react"; import { page } from "web-utils"; export default page({ - url: "*", + url: "**", component: ({}) => { - navigate("/login"); + useEffect(() => { + navigate("/login"); + }, []); return
Loading...
; }, }); diff --git a/app/web/src/base/page/live.tsx b/app/web/src/base/page/live.tsx index f98d47d9..2ffe6213 100644 --- a/app/web/src/base/page/live.tsx +++ b/app/web/src/base/page/live.tsx @@ -13,6 +13,7 @@ export default page({ return ( import("./page/all"), +}; +export const login = { + url: "/login", + page: () => import("./page/auth/login"), +}; diff --git a/app/web/src/base/root.tsx b/app/web/src/base/root.tsx index 8aa6671d..afbac143 100644 --- a/app/web/src/base/root.tsx +++ b/app/web/src/base/root.tsx @@ -1,25 +1,45 @@ -import { FC } from "react"; - -import { useState } from "react"; -import { GlobalContext } from "web-utils"; - -const w = window as unknown as { - prasiContext: any; - rootRender: any; -}; - -w.prasiContext = { - global: {}, - render() {}, -}; +import { createRouter } from "radix3"; +import { FC, Suspense, lazy } from "react"; +import { GlobalContext, useLocal } from "web-utils"; +import { Loading } from "../utils/ui/loading"; export const Root: FC<{}> = ({}) => { - const [_, render] = useState({}); - w.prasiContext.render = () => { - render({}); - }; - w.rootRender = w.prasiContext.render; + const local = useLocal( + { + router: createRouter({ 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 () => { + return { default: (await v.page()).default.component as any }; + }) + ); + } + local.render(); + } + ); + prasiContext.render = local.render; const Provider = GlobalContext.Provider as FC<{ value: any; children: any }>; - return Hello mantapun alamuko; + + const found = local.router.lookup(location.pathname); + if (found) { + local.Page = found; + } + + if (!local.Page) { + return ; + } + + return ( + + + + + + ); }; diff --git a/app/web/src/index.tsx b/app/web/src/index.tsx index 5561ed89..d06e95fc 100644 --- a/app/web/src/index.tsx +++ b/app/web/src/index.tsx @@ -1,6 +1,8 @@ import { createRoot } from "react-dom/client"; -import "./index.css"; +import { defineReact, defineWindow } from "web-utils"; import { Root } from "./base/root"; +import "./index.css"; +import { createAPI, createDB, reloadDBAPI } from "./utils/script/init-api"; const registerServiceWorker = async () => { if ("serviceWorker" in navigator) { @@ -21,6 +23,18 @@ const registerServiceWorker = async () => { registerServiceWorker(); const el = document.getElementById("root"); + if (el) { - createRoot(el).render(); + (async () => { + defineReact(); + await defineWindow(false); + const w = window as any; + const base = `${location.protocol}//${location.host}`; + + await reloadDBAPI(base); + w.api = createAPI(base); + w.db = createDB(base); + + createRoot(el).render(); + })(); } diff --git a/app/web/src/utils/script/init-api.ts b/app/web/src/utils/script/init-api.ts index c5ef4abe..20647000 100644 --- a/app/web/src/utils/script/init-api.ts +++ b/app/web/src/utils/script/init-api.ts @@ -1,7 +1,7 @@ import { createStore, get, set } from "idb-keyval"; import trim from "lodash.trim"; import { apiClient, dbClient } from "web-utils"; -import { createFrameCors } from "web-utils/src/web/iframe-cors"; +import { createFrameCors } from "web-utils"; export const w = window as unknown as { prasiApi: Record; apiHeaders: any; @@ -16,6 +16,10 @@ export const createAPI = (url: string) => { w.apiClient = apiClient; } + if (!w.prasiApi) { + w.prasiApi = {}; + } + return w.apiClient(w.prasiApi[url]?.apiEntry, url); }; diff --git a/bun.lockb b/bun.lockb index 4fa6d14f01dd806818c3e7ea7787e389199bd934..3669b7c80b44c75a58ab9f04b3bc9a7ebb85850c 100755 GIT binary patch delta 55709 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 p74tab%vFQAsur0ir*c<4s3;yUj%0D_iL`PmXOkIZqP1N2zW_vV)mQ)k diff --git a/package.json b/package.json index faa9281c..5b5260f6 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "module": "src/index.ts", "type": "module", "scripts": { - "dev": "bun run --silent --watch ./pkgs/core/index.ts dev", + "dev": "bun clean && bun run --silent --watch ./pkgs/core/index.ts dev", "clean": "rm -rf app/static && rm -rf app/web/.parcel-cache", "prod": "bun run --silent ./pkgs/core/index.ts", "pull": "cd app/db && bun prisma db pull && bun prisma generate", diff --git a/pkgs/core/server/api-scan.ts b/pkgs/core/server/api-scan.ts index 5ef93e1b..74772ad5 100644 --- a/pkgs/core/server/api-scan.ts +++ b/pkgs/core/server/api-scan.ts @@ -48,5 +48,5 @@ export const scanApi = async () => { } }; await scan(dir(`app/srv/api`)); - await scan(dir(`pkgs/api`)); + await scan(dir(`pkgs/core/api`)); }; diff --git a/pkgs/core/server/create.ts b/pkgs/core/server/create.ts index c0fd2b03..4eb35904 100644 --- a/pkgs/core/server/create.ts +++ b/pkgs/core/server/create.ts @@ -13,25 +13,18 @@ export const createServer = async () => { async fetch(req) { const url = new URL(req.url); - if (req.method === "GET") { - try { - const file = Bun.file(dir(`app/static${url.pathname}`)); - if (file.type !== "application/octet-stream") { - return new Response(file as any); - } - } catch (e) {} - return new Response(Bun.file(dir(`app/static/index.html`)) as any); - } else { - const api = await serveAPI(url, req); - if (api) { - return api; - } + const api = await serveAPI(url, req); + if (api) { + return api; } - return new Response(`404 Not Found`, { - status: 404, - statusText: "Not Found", - }); + try { + const file = Bun.file(dir(`app/static${url.pathname}`)); + if (file.type !== "application/octet-stream") { + return new Response(file as any); + } + } catch (e) {} + return new Response(Bun.file(dir(`app/static/index.html`)) as any); }, }); diff --git a/pkgs/web-utils/package.json b/pkgs/web-utils/package.json index d960a4ce..dca1b78d 100644 --- a/pkgs/web-utils/package.json +++ b/pkgs/web-utils/package.json @@ -3,7 +3,9 @@ "main": "src/export.ts", "dependencies": { "@paralleldrive/cuid2": "2.2.0", + "@types/hash-sum": "^1.0.0", "goober": "^2.1.13", + "hash-sum": "^2.0.0", "react": "18.2.0", "react-dom": "18.2.0" }, diff --git a/pkgs/web-utils/src/client-api.ts b/pkgs/web-utils/src/client-api.ts new file mode 100644 index 00000000..b3c211aa --- /dev/null +++ b/pkgs/web-utils/src/client-api.ts @@ -0,0 +1,78 @@ +import { fetchSendApi } from "./client-frame"; + +export const apiClient = ( + api: Record, + apiUrl: string +) => { + return new Proxy( + {}, + { + get: (_, actionName: string) => { + const createFn = (actionName: string) => { + return function (this: { apiUrl: string } | undefined, ...rest: any) { + return new Promise(async (resolve, reject) => { + try { + let _apiURL = apiUrl; + if (typeof this?.apiUrl === "string") { + _apiURL = this.apiUrl; + } + + if (!api || !api[actionName]) { + resolve(null); + console.error( + `API ${actionName.toString()} not found, existing API: ${Object.keys( + api + )}` + ); + return; + } + + let actionUrl = api[actionName].url; + const actionParams = api[actionName].args; + if (actionUrl && actionParams) { + if (rest.length > 0 && actionParams.length > 0) { + for (const [idx, p] of Object.entries(rest)) { + const paramName = actionParams[parseInt(idx)]; + if (actionParams && actionParams.includes(paramName)) { + if ( + !!p && + typeof p !== "string" && + typeof p !== "number" + ) { + continue; + } + } + actionUrl = actionUrl.replace(`:${paramName}?`, p + ""); + actionUrl = actionUrl.replace(`:${paramName}`, p + ""); + } + } + + const url = `${_apiURL}${actionUrl}`; + + const result = await fetchSendApi(url, rest); + resolve(result); + } else { + console.error(`API Not Found: ${actionName.toString()}`); + } + } catch (e) { + reject(e); + } + }); + }; + }; + if (actionName === "then") { + return new Proxy( + {}, + { + get: (_, actionName: string) => { + return createFn(actionName); + }, + } + ); + } + + return createFn(actionName); + }, + } + ); +}; diff --git a/pkgs/web-utils/src/client-db.ts b/pkgs/web-utils/src/client-db.ts new file mode 100644 index 00000000..7be56acb --- /dev/null +++ b/pkgs/web-utils/src/client-db.ts @@ -0,0 +1,131 @@ +import { waitUntil } from "web-utils"; +import { createFrameCors } from "./client-frame"; +import hash_sum from "hash-sum"; + +export const dbClient = (name: string, dburl?: string) => { + return new Proxy( + {}, + { + get(_, table: string) { + if (table === "_tables") { + return () => { + return fetchSendDb( + name, + { + name, + action: "definition", + table: "*", + }, + dburl + ); + }; + } + + if (table === "_definition") { + return (table: string) => { + return fetchSendDb( + name, + { + name, + action: "definition", + table, + }, + dburl + ); + }; + } + + if (table.startsWith("$")) { + return (...params: any[]) => { + return fetchSendDb( + name, + { + name, + action: "query", + table, + params, + }, + dburl + ); + }; + } + + return new Proxy( + {}, + { + get(_, action: string) { + return (...params: any[]) => { + if (table === "query") { + table = action; + action = "query"; + } + return fetchSendDb( + name, + { + name, + action, + table, + params, + }, + dburl + ); + }; + }, + } + ); + }, + } + ); +}; + +const cachedQueryResult: Record = + {}; + +export const fetchSendDb = async ( + name: string, + params: any, + dburl?: string +) => { + const w = typeof window === "object" ? window : (globalThis as any); + let url = `/_dbs/${name}`; + let frm: Awaited>; + + if (params.table) { + url += `/${params.table}`; + } + + const _base = dburl || w.serverurl; + + if (!w.frmapi) { + w.frmapi = {}; + } + + if (!w.frmapi[_base]) { + w.frmapi[_base] = await createFrameCors(_base); + } + + frm = w.frmapi[_base]; + + if (!frm) { + await waitUntil(() => { + frm = w.frmapi[_base]; + return frm; + }); + } + + const hsum = hash_sum(params); + const cached = cachedQueryResult[hsum]; + + if (!cached || (cached && Date.now() - cached.timestamp > 1000)) { + cachedQueryResult[hsum] = { + timestamp: Date.now(), + result: null, + }; + + const result = await frm.send(url, params, w.apiHeaders); + cachedQueryResult[hsum].result = result; + return result; + } + + return cached.result; +}; diff --git a/pkgs/web-utils/src/client-frame.ts b/pkgs/web-utils/src/client-frame.ts new file mode 100644 index 00000000..32f6f70f --- /dev/null +++ b/pkgs/web-utils/src/client-frame.ts @@ -0,0 +1,208 @@ +import { waitUntil } from "web-utils"; +import { createId } from "@paralleldrive/cuid2"; +const cuid = createId; + +(BigInt.prototype as any).toJSON = function (): string { + return `BigInt::` + this.toString(); +}; + +export const createFrameCors = async (url: string, win?: any) => { + let w = window; + if (!!win) { + w = win; + } + const document = w.document; + + const id = `__` + url.replace(/\W/g, ""); + + if (typeof document !== "undefined" && !document.querySelector(`#${id}`)) { + const iframe = document.createElement("iframe"); + iframe.style.display = "none"; + iframe.id = id; + + const _url = new URL(url); + _url.pathname = "/_api_frm"; + iframe.src = _url.toString(); + + await new Promise((resolve, reject) => { + iframe.onload = () => { + if (!iframe.contentDocument) { + setTimeout(() => { + if (!iframe.contentDocument) { + reject( + `Cannot load iframe ${_url.toString()}. content document not found.` + ); + } + }, 100); + } + }; + + const onInit = (e: any) => { + if (e.data === "initialized") { + iframe.setAttribute("loaded", "y"); + w.removeEventListener("message", onInit); + resolve(); + } + }; + w.addEventListener("message", onInit); + + document.body.appendChild(iframe); + }); + } + + const wm = {} as Record; + + const sendRaw = async ( + input: RequestInfo | URL, + init?: RequestInit | undefined + ) => { + if (w.document && w.document.querySelector) { + const iframe = w.document.querySelector(`#${id}`) as HTMLIFrameElement; + + if ( + !iframe || + !iframe.contentWindow || + (iframe && iframe.getAttribute("loaded") !== "y") + ) { + await waitUntil( + () => + iframe && + iframe.contentWindow && + iframe.getAttribute("loaded") === "y" + ); + } + + return await new Promise((resolve, reject) => { + if (iframe && iframe.contentWindow) { + const id = cuid(); + wm[id] = (e: any) => { + if (id === e.data.id) { + w.removeEventListener("message", wm[id]); + delete wm[id]; + if (e.data.error) { + let err = e.data.error; + if (typeof err === "string") { + reject( + err.replace( + /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, + "" + ) + ); + } + } else { + resolve(e.data.result); + } + } + }; + w.addEventListener("message", wm[id]); + + let _input = input; + if (typeof input === "string") { + if (!input.startsWith("http")) { + _input = `${url}${input}`; + } + } + iframe.contentWindow.postMessage({ input: _input, init, id }, "*"); + } + }); + } + }; + + return { + sendRaw, + async send(input: string | RequestInfo | URL, data?: any, _headers?: any) { + const uri = input.toString(); + const headers = { ..._headers }; + + let body = data; + let isFile = false; + + const formatSingle = async (data: any) => { + if (!(data instanceof w.FormData || data instanceof w.File)) { + headers["content-type"] = "application/json"; + } else { + if (data instanceof w.File) { + isFile = true; + let ab = await new Promise((resolve) => { + const reader = new FileReader(); + reader.addEventListener("load", (e) => { + resolve(e.target?.result as ArrayBuffer); + }); + reader.readAsArrayBuffer(data); + }); + if (ab) { + data = new File([ab], data.name); + } + } + } + + return data; + }; + + if (Array.isArray(data)) { + body = await Promise.all(data.map((e) => formatSingle(e))); + } else { + body = await formatSingle(data); + } + if (!isFile) { + body = JSON.stringify(body); + } + + return await sendRaw( + `${url.endsWith("/") ? url : `${url}/`}${ + uri.startsWith("/") ? uri.substring(1) : uri + }`, + data + ? { + method: "post", + headers, + body, + } + : {} + ); + }, + }; +}; + +export const fetchSendApi = async ( + _url: string, + params: any, + parentWindow?: any +) => { + let w: any = typeof window === "object" ? window : globalThis; + + const win = parentWindow || w; + let url = _url; + let frm: Awaited>; + if (!win.frmapi) { + win.frmapi = {}; + + win.frmapi[w.serverurl] = await createFrameCors(w.serverurl, win); + } + + frm = win.frmapi[w.serverurl]; + + if (url.startsWith("http")) { + const purl = new URL(url); + if (!win.frmapi[purl.host]) { + win.frmapi[purl.host] = await createFrameCors( + `${purl.protocol}//${purl.host}` + ); + } + + frm = win.frmapi[purl.host]; + url = url.substring(`${purl.protocol}//${purl.host}`.length); + } + if (!win.apiHeaders) { + win.apiHeaders = {}; + } + + if (!frm) { + await waitUntil(() => { + frm = win.frmapi[w.serverurl]; + return frm; + }); + } + + return await frm.send(url, params, win.apiHeaders); +}; diff --git a/pkgs/web-utils/src/define-window.ts b/pkgs/web-utils/src/define-window.ts index 0fb4e654..bc7aa88f 100644 --- a/pkgs/web-utils/src/define-window.ts +++ b/pkgs/web-utils/src/define-window.ts @@ -6,6 +6,11 @@ export const defineWindow = async (awaitServerUrl = true) => { if (awaitServerUrl) await waitUntil(() => w.__SRV_URL__); + w.prasiContext = { + global: {}, + render() {}, + }; + const location = window["location"]; const host = @@ -70,11 +75,10 @@ export const defineWindow = async (awaitServerUrl = true) => { } history.pushState({}, "", _href); - if (w.rootRes) w.rootRes.pathname = href; w.pathname = href; - if (w.rootRender) { - w.rootRender(); + if (w.prasiContext && w.prasiContext.render) { + w.prasiContext.render(); } }; diff --git a/pkgs/web-utils/src/export.ts b/pkgs/web-utils/src/export.ts index 6525a0f1..f77c7d8b 100644 --- a/pkgs/web-utils/src/export.ts +++ b/pkgs/web-utils/src/export.ts @@ -7,4 +7,7 @@ export * from "./page"; export * from "./global"; export * from "./define-react"; export * from "./define-window"; +export * from './client-api'; +export * from './client-frame'; +export * from './client-db'; export const React = _React; diff --git a/pkgs/web-utils/src/global.ts b/pkgs/web-utils/src/global.ts index 9797c034..e642be28 100644 --- a/pkgs/web-utils/src/global.ts +++ b/pkgs/web-utils/src/global.ts @@ -1,4 +1,12 @@ +import goober from "goober"; + 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 prasiContext: any; } export {}; diff --git a/pkgs/web-utils/src/use-local.ts b/pkgs/web-utils/src/use-local.ts index 7442859c..55988f88 100644 --- a/pkgs/web-utils/src/use-local.ts +++ b/pkgs/web-utils/src/use-local.ts @@ -1,6 +1,5 @@ import { useEffect, useRef, useState } from "react"; - export const useLocal = ( data: T, effect?: (arg: {