fix
This commit is contained in:
parent
b58490700b
commit
de88c0adcf
|
|
@ -0,0 +1,44 @@
|
||||||
|
declare module "exports" {
|
||||||
|
export const _web: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
path: string;
|
||||||
|
args: string[];
|
||||||
|
handler: Promise<any>;
|
||||||
|
};
|
||||||
|
export const _upload: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
path: string;
|
||||||
|
args: string[];
|
||||||
|
handler: Promise<any>;
|
||||||
|
};
|
||||||
|
export const _prasi: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
path: string;
|
||||||
|
args: any[];
|
||||||
|
handler: Promise<any>;
|
||||||
|
};
|
||||||
|
export const _file: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
path: string;
|
||||||
|
args: any[];
|
||||||
|
handler: Promise<any>;
|
||||||
|
};
|
||||||
|
export const _api_frm: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
path: string;
|
||||||
|
args: any[];
|
||||||
|
handler: Promise<any>;
|
||||||
|
};
|
||||||
|
export const _dbs: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
path: string;
|
||||||
|
args: string[];
|
||||||
|
handler: Promise<any>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"@swc/wasm-web": "1.3.94-nightly-20231014.1",
|
"@swc/wasm-web": "1.3.94-nightly-20231014.1",
|
||||||
"algoliasearch": "^4.20.0",
|
"algoliasearch": "^4.20.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
"dbgen": "workspace:*",
|
||||||
"downshift": "^8.2.2",
|
"downshift": "^8.2.2",
|
||||||
"esbuild-wasm": "^0.19.4",
|
"esbuild-wasm": "^0.19.4",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
|
|
@ -40,6 +41,7 @@
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.0.3",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"quill-delta": "^5.1.0",
|
"quill-delta": "^5.1.0",
|
||||||
|
"radix3": "^1.1.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
|
|
@ -52,11 +54,10 @@
|
||||||
"tinycolor2": "^1.6.0",
|
"tinycolor2": "^1.6.0",
|
||||||
"ua-parser-js": "^1.0.36",
|
"ua-parser-js": "^1.0.36",
|
||||||
"uuid": "9.0.1",
|
"uuid": "9.0.1",
|
||||||
|
"web-utils": "workspace:*",
|
||||||
"y-pojo": "^0.0.8",
|
"y-pojo": "^0.0.8",
|
||||||
"yjs": "^13.6.8",
|
"yjs": "^13.6.8",
|
||||||
"yjs-types": "^0.0.1",
|
"yjs-types": "^0.0.1"
|
||||||
"web-utils": "workspace:*",
|
|
||||||
"dbgen": "workspace:*"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash.concat": "^4.5.7",
|
"@types/lodash.concat": "^4.5.7",
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
import { page } from "web-utils";
|
import { page } from "web-utils";
|
||||||
|
|
||||||
export default page({
|
export default page({
|
||||||
url: "*",
|
url: "**",
|
||||||
component: ({}) => {
|
component: ({}) => {
|
||||||
navigate("/login");
|
useEffect(() => {
|
||||||
|
navigate("/login");
|
||||||
|
}, []);
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export default page({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Live
|
<Live
|
||||||
|
mode={"dev"}
|
||||||
domain={params.domain}
|
domain={params.domain}
|
||||||
pathname={`/${params._ === "_" ? "" : params._}`}
|
pathname={`/${params._ === "_" ? "" : params._}`}
|
||||||
loader={defaultLoader}
|
loader={defaultLoader}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
export const all = {
|
||||||
|
url: "**",
|
||||||
|
page: () => import("./page/all"),
|
||||||
|
};
|
||||||
|
export const login = {
|
||||||
|
url: "/login",
|
||||||
|
page: () => import("./page/auth/login"),
|
||||||
|
};
|
||||||
|
|
@ -1,25 +1,45 @@
|
||||||
import { FC } from "react";
|
import { createRouter } from "radix3";
|
||||||
|
import { FC, Suspense, lazy } from "react";
|
||||||
import { useState } from "react";
|
import { GlobalContext, useLocal } from "web-utils";
|
||||||
import { GlobalContext } from "web-utils";
|
import { Loading } from "../utils/ui/loading";
|
||||||
|
|
||||||
const w = window as unknown as {
|
|
||||||
prasiContext: any;
|
|
||||||
rootRender: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
w.prasiContext = {
|
|
||||||
global: {},
|
|
||||||
render() {},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Root: FC<{}> = ({}) => {
|
export const Root: FC<{}> = ({}) => {
|
||||||
const [_, render] = useState({});
|
const local = useLocal(
|
||||||
w.prasiContext.render = () => {
|
{
|
||||||
render({});
|
router: createRouter<any>({ strictTrailingSlash: true }),
|
||||||
};
|
Page: null as any,
|
||||||
w.rootRender = w.prasiContext.render;
|
},
|
||||||
|
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 }>;
|
const Provider = GlobalContext.Provider as FC<{ value: any; children: any }>;
|
||||||
return <Provider value={w.prasiContext}>Hello mantapun alamuko</Provider>;
|
|
||||||
|
const found = local.router.lookup(location.pathname);
|
||||||
|
if (found) {
|
||||||
|
local.Page = found;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!local.Page) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Provider value={prasiContext}>
|
||||||
|
<Suspense>
|
||||||
|
<local.Page />
|
||||||
|
</Suspense>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./index.css";
|
import { defineReact, defineWindow } from "web-utils";
|
||||||
import { Root } from "./base/root";
|
import { Root } from "./base/root";
|
||||||
|
import "./index.css";
|
||||||
|
import { createAPI, createDB, reloadDBAPI } from "./utils/script/init-api";
|
||||||
|
|
||||||
const registerServiceWorker = async () => {
|
const registerServiceWorker = async () => {
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
|
|
@ -21,6 +23,18 @@ const registerServiceWorker = async () => {
|
||||||
registerServiceWorker();
|
registerServiceWorker();
|
||||||
|
|
||||||
const el = document.getElementById("root");
|
const el = document.getElementById("root");
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
createRoot(el).render(<Root />);
|
(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(<Root />);
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { createStore, get, set } from "idb-keyval";
|
import { createStore, get, set } from "idb-keyval";
|
||||||
import trim from "lodash.trim";
|
import trim from "lodash.trim";
|
||||||
import { apiClient, dbClient } from "web-utils";
|
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 {
|
export const w = window as unknown as {
|
||||||
prasiApi: Record<string, any>;
|
prasiApi: Record<string, any>;
|
||||||
apiHeaders: any;
|
apiHeaders: any;
|
||||||
|
|
@ -16,6 +16,10 @@ export const createAPI = (url: string) => {
|
||||||
w.apiClient = apiClient;
|
w.apiClient = apiClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!w.prasiApi) {
|
||||||
|
w.prasiApi = {};
|
||||||
|
}
|
||||||
|
|
||||||
return w.apiClient(w.prasiApi[url]?.apiEntry, url);
|
return w.apiClient(w.prasiApi[url]?.apiEntry, url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"module": "src/index.ts",
|
"module": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"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",
|
"clean": "rm -rf app/static && rm -rf app/web/.parcel-cache",
|
||||||
"prod": "bun run --silent ./pkgs/core/index.ts",
|
"prod": "bun run --silent ./pkgs/core/index.ts",
|
||||||
"pull": "cd app/db && bun prisma db pull && bun prisma generate",
|
"pull": "cd app/db && bun prisma db pull && bun prisma generate",
|
||||||
|
|
|
||||||
|
|
@ -48,5 +48,5 @@ export const scanApi = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
await scan(dir(`app/srv/api`));
|
await scan(dir(`app/srv/api`));
|
||||||
await scan(dir(`pkgs/api`));
|
await scan(dir(`pkgs/core/api`));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,25 +13,18 @@ export const createServer = async () => {
|
||||||
async fetch(req) {
|
async fetch(req) {
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
|
|
||||||
if (req.method === "GET") {
|
const api = await serveAPI(url, req);
|
||||||
try {
|
if (api) {
|
||||||
const file = Bun.file(dir(`app/static${url.pathname}`));
|
return api;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(`404 Not Found`, {
|
try {
|
||||||
status: 404,
|
const file = Bun.file(dir(`app/static${url.pathname}`));
|
||||||
statusText: "Not Found",
|
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);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
"main": "src/export.ts",
|
"main": "src/export.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@paralleldrive/cuid2": "2.2.0",
|
"@paralleldrive/cuid2": "2.2.0",
|
||||||
|
"@types/hash-sum": "^1.0.0",
|
||||||
"goober": "^2.1.13",
|
"goober": "^2.1.13",
|
||||||
|
"hash-sum": "^2.0.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { fetchSendApi } from "./client-frame";
|
||||||
|
|
||||||
|
export const apiClient = (
|
||||||
|
api: Record<string, { url: string; args: any[] }>,
|
||||||
|
apiUrl: string
|
||||||
|
) => {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get: (_, actionName: string) => {
|
||||||
|
const createFn = (actionName: string) => {
|
||||||
|
return function (this: { apiUrl: string } | undefined, ...rest: any) {
|
||||||
|
return new Promise<any>(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);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -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<string, { timestamp: number; result: any }> =
|
||||||
|
{};
|
||||||
|
|
||||||
|
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<ReturnType<typeof createFrameCors>>;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
@ -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<void>((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<string, any>;
|
||||||
|
|
||||||
|
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<ArrayBuffer | undefined>((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<ReturnType<typeof createFrameCors>>;
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
@ -6,6 +6,11 @@ export const defineWindow = async (awaitServerUrl = true) => {
|
||||||
|
|
||||||
if (awaitServerUrl) await waitUntil(() => w.__SRV_URL__);
|
if (awaitServerUrl) await waitUntil(() => w.__SRV_URL__);
|
||||||
|
|
||||||
|
w.prasiContext = {
|
||||||
|
global: {},
|
||||||
|
render() {},
|
||||||
|
};
|
||||||
|
|
||||||
const location = window["location"];
|
const location = window["location"];
|
||||||
|
|
||||||
const host =
|
const host =
|
||||||
|
|
@ -70,11 +75,10 @@ export const defineWindow = async (awaitServerUrl = true) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
history.pushState({}, "", _href);
|
history.pushState({}, "", _href);
|
||||||
if (w.rootRes) w.rootRes.pathname = href;
|
|
||||||
w.pathname = href;
|
w.pathname = href;
|
||||||
|
|
||||||
if (w.rootRender) {
|
if (w.prasiContext && w.prasiContext.render) {
|
||||||
w.rootRender();
|
w.prasiContext.render();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,7 @@ export * from "./page";
|
||||||
export * from "./global";
|
export * from "./global";
|
||||||
export * from "./define-react";
|
export * from "./define-react";
|
||||||
export * from "./define-window";
|
export * from "./define-window";
|
||||||
|
export * from './client-api';
|
||||||
|
export * from './client-frame';
|
||||||
|
export * from './client-db';
|
||||||
export const React = _React;
|
export const React = _React;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
|
import goober from "goober";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
const navigate: (path: string) => void;
|
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 {};
|
export {};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
|
||||||
export const useLocal = <T extends object>(
|
export const useLocal = <T extends object>(
|
||||||
data: T,
|
data: T,
|
||||||
effect?: (arg: {
|
effect?: (arg: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue