wip checkpoint

This commit is contained in:
Rizky 2023-12-17 08:45:34 +07:00
parent 3dc13caab8
commit 21fa871b92
29 changed files with 200 additions and 537 deletions

View File

@ -0,0 +1,62 @@
import { w } from "../../../utils/types/general";
import { fetchViaProxy } from "../proxy";
export const loadApiProxyDef = async (url: string, with_types: boolean) => {
const raw = await fetchViaProxy(urlPath(url, "/_prasi/_"));
let ver = "";
if (raw && (raw as any).prasi) {
ver = (raw as any).prasi;
}
const base = baseUrl(url);
if (ver === "v2") {
await new Promise<void>((done) => {
const d = document;
const script = d.createElement("script");
script.onload = async () => {
done();
};
if (with_types) {
script.src = `${base}/_prasi/load.js?url=${url}&dev=1`;
} else {
script.src = `${base}/_prasi/load.js?url=${url}`;
}
d.body.appendChild(script);
});
} else {
const apiEntry = await fetch(base + "/_prasi/api-entry");
w.prasiApi[url] = {
apiEntry: (await apiEntry.json()).srv,
};
if (with_types) {
const apiTypes = await fetch(base + "/_prasi/api-types");
w.prasiApi[url].apiTypes = await apiTypes.text();
w.prasiApi[url].prismaTypes = {
"prisma.d.ts": await loadText(`${base}/_prasi/prisma/index.d.ts`),
"runtime/index.d.ts": await loadText(
`${base}/_prasi/prisma/runtime/index.d.ts`
),
"runtime/library.d.ts": await loadText(
`${base}/_prasi/prisma/runtime/library.d.ts`
),
};
}
}
};
const baseUrl = (url: string) => {
const base = new URL(url);
return `${base.protocol}//${base.host}`;
};
const urlPath = (url: string, pathname: string) => {
const base = new URL(url);
base.pathname = pathname;
return base.toString();
};
const loadText = async (url: string, v2?: boolean) => {
const res = await fetch(url);
return await res.text();
};

View File

@ -1,40 +1,49 @@
import { fetchSendApi } from "./client-frame"; import { w } from "../../../utils/types/general";
import { fetchViaProxy } from "../proxy";
import { loadApiProxyDef } from "./api-proxy-def";
export const apiClient = ( export type ApiProxy<T extends Record<string, any> = {}> = any;
api: Record<string, { url: string; args: any[] }>,
apiUrl: string export const apiProxy = (api_url: string) => {
) => {
return new Proxy( return new Proxy(
{}, {},
{ {
get: (_, actionName: string) => { get: (_, actionName: string) => {
const createFn = (actionName: string) => { const createFn = (actionName: string) => {
return function (this: { apiUrl: string } | undefined, ...rest: any) { return function (
this: { api_url: string } | undefined,
...rest: any
) {
return new Promise<any>(async (resolve, reject) => { return new Promise<any>(async (resolve, reject) => {
try { try {
let _apiURL = apiUrl; let base_url = api_url;
if (typeof this?.apiUrl === "string") { if (typeof this?.api_url === "string") {
_apiURL = this.apiUrl; base_url = this.api_url;
} }
if (!api) { if (!w.prasiApi) {
reject( w.prasiApi = {};
new Error(`API Definition for ${_apiURL} is not loaded.`)
);
return;
} }
if (api && !api[actionName]) { if (!w.prasiApi[base_url]) {
await loadApiProxyDef(base_url, false);
}
const api_def = w.prasiApi[base_url];
if (api_def) {
if (!api_def.apiEntry) api_def.apiEntry = {};
if (api_def.apiEntry && !api_def.apiEntry[actionName]) {
reject( reject(
`API ${actionName.toString()} not found, existing API: \n - ${Object.keys( `API ${actionName.toString()} not found, existing API: \n - ${Object.keys(
api || {} api_def || {}
).join("\n - ")}` ).join("\n - ")}`
); );
return; return;
} }
}
let actionUrl = api[actionName].url; let actionUrl = api_def.apiEntry[actionName].url;
const actionParams = api[actionName].args; const actionParams = api_def.apiEntry[actionName].args;
if (actionUrl && actionParams) { if (actionUrl && actionParams) {
if (rest.length > 0 && actionParams.length > 0) { if (rest.length > 0 && actionParams.length > 0) {
for (const [idx, p] of Object.entries(rest)) { for (const [idx, p] of Object.entries(rest)) {
@ -53,7 +62,7 @@ export const apiClient = (
} }
} }
const url = `${_apiURL}${actionUrl}`; const url = `${base_url}${actionUrl}`;
const result = await fetchSendApi(url, rest); const result = await fetchSendApi(url, rest);
resolve(result); resolve(result);
@ -82,3 +91,9 @@ export const apiClient = (
} }
); );
}; };
const fetchSendApi = async (url: string, params: any) => {
return await fetchViaProxy(url, params, {
"content-type": "application/json",
});
};

View File

@ -1,8 +1,7 @@
import { waitUntil } from "web-utils";
import { createFrameCors } from "./client-frame";
import hash_sum from "hash-sum"; import hash_sum from "hash-sum";
import { fetchViaProxy } from "../proxy";
export const dbClient = (name: string, dburl?: string) => { export const dbProxy = (dburl: string) => {
return new Proxy( return new Proxy(
{}, {},
{ {
@ -10,7 +9,6 @@ export const dbClient = (name: string, dburl?: string) => {
if (table === "_tables") { if (table === "_tables") {
return () => { return () => {
return fetchSendDb( return fetchSendDb(
name,
{ {
name, name,
action: "definition", action: "definition",
@ -24,7 +22,6 @@ export const dbClient = (name: string, dburl?: string) => {
if (table === "_definition") { if (table === "_definition") {
return (table: string) => { return (table: string) => {
return fetchSendDb( return fetchSendDb(
name,
{ {
name, name,
action: "definition", action: "definition",
@ -38,7 +35,6 @@ export const dbClient = (name: string, dburl?: string) => {
if (table.startsWith("$")) { if (table.startsWith("$")) {
return (...params: any[]) => { return (...params: any[]) => {
return fetchSendDb( return fetchSendDb(
name,
{ {
name, name,
action: "query", action: "query",
@ -60,7 +56,6 @@ export const dbClient = (name: string, dburl?: string) => {
action = "query"; action = "query";
} }
return fetchSendDb( return fetchSendDb(
name,
{ {
name, name,
action, action,
@ -83,37 +78,13 @@ const cachedQueryResult: Record<
{ timestamp: number; result: any; promise: Promise<any> } { timestamp: number; result: any; promise: Promise<any> }
> = {}; > = {};
export const fetchSendDb = async ( export const fetchSendDb = async (params: any, dburl: string) => {
name: string, const base = new URL(dburl);
params: any, base.pathname = `/_dbs/`;
dburl?: string
) => {
const w = typeof window === "object" ? window : (globalThis as any);
let url = `/_dbs/${name}`;
let frm: Awaited<ReturnType<typeof createFrameCors>>;
if (params.table) { if (params.table) {
url += `/${params.table}`; base.pathname += `/${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 url = base.toString();
const hsum = hash_sum(params); const hsum = hash_sum(params);
const cached = cachedQueryResult[hsum]; const cached = cachedQueryResult[hsum];
@ -121,7 +92,9 @@ export const fetchSendDb = async (
if (!cached || (cached && Date.now() - cached.timestamp > 1000)) { if (!cached || (cached && Date.now() - cached.timestamp > 1000)) {
cachedQueryResult[hsum] = { cachedQueryResult[hsum] = {
timestamp: Date.now(), timestamp: Date.now(),
promise: frm.send(url, params, w.apiHeaders), promise: fetchViaProxy(url, params, {
"content-type": "application/json",
}),
result: null, result: null,
}; };

View File

@ -47,11 +47,16 @@ export const fetchViaProxy = async (
const cur = new URL(location.href); const cur = new URL(location.href);
const base = new URL(url); const base = new URL(url);
if (cur.host === base.host) { if (cur.host === base.host) {
const res = await fetch(base.pathname, { const res = await fetch(
base.pathname,
data
? {
method: "POST", method: "POST",
body, body,
headers, headers,
}); }
: undefined
);
const raw = await res.text(); const raw = await res.text();
try { try {
return JSON.parse(raw); return JSON.parse(raw);
@ -59,17 +64,15 @@ export const fetchViaProxy = async (
return raw; return raw;
} }
} else { } else {
console.log(url); const res = await fetch(`/_proxy`, {
return null; method: "POST",
// const res = await fetch(`/_proxy`, { body: JSON.stringify({
// method: "POST", url,
// body: JSON.stringify({ body,
// url, headers,
// body, }),
// headers, headers: { "content-type": "application/json" },
// }), });
// headers: { "content-type": "application/json" }, return res.json();
// });
// return res.json();
} }
}; };

View File

@ -1,12 +1,12 @@
import { Root as ReactRoot, createRoot } from "react-dom/client"; import { Root as ReactRoot, createRoot } from "react-dom/client";
import { defineReact, defineWindow } from "web-utils"; import { defineReact, defineWindow } from "web-utils";
import { apiProxy } from "./base/load/api/api-proxy";
import { dbProxy } from "./base/load/db/db-proxy";
import { Root } from "./base/root"; import { Root } from "./base/root";
import "./index.css"; import "./index.css";
import { registerMobile } from "./render/live/logic/mobile"; import { registerMobile } from "./render/live/logic/mobile";
import { reloadDBAPI } from "./utils/script/init-api";
import { w } from "./utils/types/general";
import { sworkerAddCache, sworkerRegister } from "./sworker-boot"; import { sworkerAddCache, sworkerRegister } from "./sworker-boot";
import { dbClient } from "./base/load/db/client-db"; import { w } from "./utils/types/general";
const start = async () => { const start = async () => {
const base = `${location.protocol}//${location.host}`; const base = `${location.protocol}//${location.host}`;
@ -14,7 +14,12 @@ const start = async () => {
root: null as null | ReactRoot, root: null as null | ReactRoot,
}; };
w.mobile = registerMobile(); w.mobile = registerMobile();
w.db = dbClient("prasi", location.origin);
const cur = new URL(location.href);
const base_url = `${cur.protocol}//${cur.host}`;
w.db = dbProxy(base_url);
w.api = apiProxy(base_url);
w.serverurl = base; w.serverurl = base;
sworkerRegister(react); sworkerRegister(react);

View File

@ -1,17 +1,18 @@
import init from "wasm-gzip"; import init from "wasm-gzip";
import { jscript } from "../../../utils/script/jscript"; import { jscript } from "../../../utils/script/jscript";
import { dbClient } from "../../../base/load/db/client-db"; import { dbProxy } from "../../../base/load/db/db-proxy";
import { PG } from "./ed-global"; import { PG } from "./ed-global";
import { fetchViaProxy } from "../../vi/load/proxy"; import { fetchViaProxy } from "../../../base/load/proxy";
import { ApiProxy, apiProxy } from "../../../base/load/api/api-proxy";
let w = window as unknown as { db: ReturnType<typeof dbClient> }; let w = window as unknown as {
db: ReturnType<typeof dbProxy>;
api: ApiProxy;
};
export const edInit = async (p: PG) => { export const edInit = async (p: PG) => {
p.status = "ready"; p.status = "ready";
const cur = new URL(location.href);
w.db = dbClient("prasi", `${cur.protocol}//${cur.host}`);
await init(); await init();
jscript.init(p.render, { esbuild: false }); jscript.init(p.render, { esbuild: false });

View File

@ -1,6 +1,7 @@
import { IContent } from "../../../../utils/types/general"; import { IContent } from "../../../../utils/types/general";
import { VG } from "../../../vi/render/global"; import { VG } from "../../../vi/render/global";
import { IMeta, PG, active } from "../../logic/ed-global"; import { IMeta, PG, active } from "../../logic/ed-global";
import { treeRebuild } from "../../logic/tree/build";
type MPIVParam = Parameters<Exclude<VG["visit"], undefined>>; type MPIVParam = Parameters<Exclude<VG["visit"], undefined>>;
export const mainPerItemVisit = ( export const mainPerItemVisit = (
@ -59,6 +60,12 @@ export const mainPerItemVisit = (
parts.props.onPointerDown = (e) => { parts.props.onPointerDown = (e) => {
e.stopPropagation(); e.stopPropagation();
if (active.comp_id && !p.comp.list[active.comp_id]) {
active.comp_id = "";
treeRebuild(p);
return;
}
const item = getOuterItem( const item = getOuterItem(
{ {
meta: active.comp_id ? p.comp.list[active.comp_id].meta : p.page.meta, meta: active.comp_id ? p.comp.list[active.comp_id].meta : p.page.meta,

View File

@ -119,7 +119,7 @@ export const EdPopUser = ({
</div> </div>
))} ))}
</div> </div>
{user.all.length > 0 && onAdd && ( {Array.isArray(user.all) && user.all.length > 0 && onAdd && (
<Select <Select
options={user.all options={user.all
.filter((e) => { .filter((e) => {

View File

@ -1,7 +1,8 @@
import Downshift from "downshift"; import Downshift from "downshift";
import { FC, useEffect } from "react"; import { FC, useEffect } from "react";
import { useGlobal, useLocal } from "web-utils"; import { useGlobal, useLocal } from "web-utils";
import { createAPI, createDB } from "../../../../../utils/script/init-api"; import { apiProxy } from "../../../../../base/load/api/api-proxy";
import { dbProxy } from "../../../../../base/load/db/db-proxy";
import { FMCompDef, FNCompDef } from "../../../../../utils/types/meta-fn"; import { FMCompDef, FNCompDef } from "../../../../../utils/types/meta-fn";
import { EDGlobal } from "../../../logic/ed-global"; import { EDGlobal } from "../../../logic/ed-global";
import { EdPropLabel } from "./prop-label"; import { EdPropLabel } from "./prop-label";
@ -27,8 +28,8 @@ export const EdPropInstanceOptions: FC<{
if (!local.loaded) { if (!local.loaded) {
try { try {
if (p.site.config.api_url) { if (p.site.config.api_url) {
if (!p.script.db) p.script.db = createDB(p.site.config.api_url); if (!p.script.db) p.script.db = dbProxy(p.site.config.api_url);
if (!p.script.api) p.script.api = createAPI(p.site.config.api_url); if (!p.script.api) p.script.api = apiProxy(p.site.config.api_url);
} }
const args = { const args = {

View File

@ -1,17 +1,12 @@
import get from "lodash.get"; import get from "lodash.get";
import { import { apiProxy } from "../../../base/load/api/api-proxy";
createAPI, import { dbProxy } from "../../../base/load/db/db-proxy";
createDB, import { jscript } from "../../../utils/script/jscript";
initApi, import { devLoader } from "../../live/dev-loader";
reloadDBAPI,
} from "../../../utils/script/init-api";
import { LSite } from "../../live/logic/global"; import { LSite } from "../../live/logic/global";
import { validateLayout } from "../../live/logic/layout"; import { validateLayout } from "../../live/logic/layout";
import importModule from "../tools/dynamic-import"; import importModule from "../tools/dynamic-import";
import { EditorGlobal, PG } from "./global"; import { EditorGlobal, PG } from "./global";
import { devLoader } from "../../live/dev-loader";
import { jscript } from "../../../utils/script/jscript";
import { deepClone } from "web-utils";
export const w = window as unknown as { export const w = window as unknown as {
basepath: string; basepath: string;
@ -121,7 +116,7 @@ export const initEditor = async (p: PG, site_id: string) => {
prodUrl: localStorage.getItem(`prasi-ext-prod-url-${p.site.id}`) || "", prodUrl: localStorage.getItem(`prasi-ext-prod-url-${p.site.id}`) || "",
}; };
p.site.api_url = await initApi(site.config); p.site.api_url = site.config.api_url;
if (w.externalAPI.prodUrl !== p.site.api_url) { if (w.externalAPI.prodUrl !== p.site.api_url) {
w.externalAPI.prodUrl = p.site.api_url; w.externalAPI.prodUrl = p.site.api_url;
@ -129,7 +124,6 @@ export const initEditor = async (p: PG, site_id: string) => {
} }
if (w.externalAPI.mode === "dev" && w.externalAPI.devUrl) { if (w.externalAPI.mode === "dev" && w.externalAPI.devUrl) {
p.site.api_url = w.externalAPI.devUrl; p.site.api_url = w.externalAPI.devUrl;
await reloadDBAPI(w.externalAPI.devUrl);
} }
w.apiurl = p.site.api_url; w.apiurl = p.site.api_url;
@ -173,8 +167,8 @@ export const execSiteJS = (p: PG) => {
}; };
const fn = p.site.js_compiled; const fn = p.site.js_compiled;
scope["api"] = createAPI(p.site.api_url); scope["api"] = apiProxy(p.site.api_url);
scope["db"] = createDB(p.site.api_url); scope["db"] = dbProxy(p.site.api_url);
const f = new Function(...Object.keys(scope), fn); const f = new Function(...Object.keys(scope), fn);
try { try {
const res = f(...Object.values(scope)); const res = f(...Object.values(scope));

View File

@ -1,5 +1,6 @@
import { FC } from "react"; import { FC } from "react";
import { createAPI, createDB } from "../../../utils/script/init-api"; import { apiProxy } from "../../../base/load/api/api-proxy";
import { dbProxy } from "../../../base/load/db/db-proxy";
import { FNCompDef } from "../../../utils/types/meta-fn"; import { FNCompDef } from "../../../utils/types/meta-fn";
import { EItem } from "../elements/e-item"; import { EItem } from "../elements/e-item";
import { ItemMeta, PG } from "./global"; import { ItemMeta, PG } from "./global";
@ -15,8 +16,8 @@ export const treePropEval = (
) => { ) => {
if (meta.item.type === "item" && meta.item.component) { if (meta.item.type === "item" && meta.item.component) {
if (p.site.api_url) { if (p.site.api_url) {
if (!p.script.db) p.script.db = createDB(p.site.api_url); if (!p.script.db) p.script.db = dbProxy(p.site.api_url);
if (!p.script.api) p.script.api = createAPI(p.site.api_url); if (!p.script.api) p.script.api = apiProxy(p.site.api_url);
} }
const props = meta.item.component.props; const props = meta.item.component.props;

View File

@ -1,6 +1,7 @@
import { FC, ReactNode, Suspense, useEffect } from "react"; import { FC, ReactNode, Suspense, useEffect } from "react";
import { deepClone } from "web-utils"; import { deepClone } from "web-utils";
import { createAPI, createDB } from "../../../utils/script/init-api"; import { apiProxy } from "../../../base/load/api/api-proxy";
import { dbProxy } from "../../../base/load/db/db-proxy";
import { ErrorBox } from "../elements/e-error"; import { ErrorBox } from "../elements/e-error";
import { ItemMeta, PG } from "./global"; import { ItemMeta, PG } from "./global";
@ -30,8 +31,8 @@ export const treeScopeEval = (
// prepare args // prepare args
if (p.site.api_url) { if (p.site.api_url) {
if (!p.script.db) p.script.db = createDB(p.site.api_url); if (!p.script.db) p.script.db = dbProxy(p.site.api_url);
if (!p.script.api) p.script.api = createAPI(p.site.api_url); if (!p.script.api) p.script.api = apiProxy(p.site.api_url);
} }
const w = window as any; const w = window as any;

View File

@ -2,7 +2,6 @@ import { useGlobal } from "web-utils";
import { EditorGlobal } from "../../../../logic/global"; import { EditorGlobal } from "../../../../logic/global";
import { ExternalDeploy } from "./ExternalDeploy"; import { ExternalDeploy } from "./ExternalDeploy";
import { w } from "../../../../logic/init"; import { w } from "../../../../logic/init";
import { reloadDBAPI } from "../../../../../../utils/script/init-api";
export const ExternalAPI = ({ export const ExternalAPI = ({
status, status,
@ -88,11 +87,9 @@ export const ExternalAPI = ({
if (w.externalAPI.mode === "dev") { if (w.externalAPI.mode === "dev") {
p.site.api_url = w.externalAPI.devUrl; p.site.api_url = w.externalAPI.devUrl;
checkApi(); checkApi();
await reloadDBAPI(w.externalAPI.devUrl, "dev");
} else { } else {
p.site.api_url = w.externalAPI.prodUrl; p.site.api_url = w.externalAPI.prodUrl;
checkApi(); checkApi();
await reloadDBAPI(w.externalAPI.prodUrl, "dev");
} }
}} }}
> >

View File

@ -3,9 +3,9 @@ import { formatDistance } from "date-fns/esm";
import trim from "lodash.trim"; import trim from "lodash.trim";
import { useEffect } from "react"; import { useEffect } from "react";
import { deepClone, useGlobal, useLocal } from "web-utils"; import { deepClone, useGlobal, useLocal } from "web-utils";
import { createAPI } from "../../../../../../utils/script/init-api";
import { AutoHeightTextarea } from "../../../../../../utils/ui/auto-textarea"; import { AutoHeightTextarea } from "../../../../../../utils/ui/auto-textarea";
import { EditorGlobal } from "../../../../logic/global"; import { EditorGlobal } from "../../../../logic/global";
import { apiProxy } from "../../../../../../base/load/api/api-proxy";
const server = { const server = {
status: "ready" as status: "ready" as
@ -40,7 +40,7 @@ export const ExternalDeploy = () => {
try { try {
const url = p.site.api_url; const url = p.site.api_url;
local.api = createAPI(url); local.api = apiProxy(url);
let res = await local.api._deploy({ let res = await local.api._deploy({
type: "check", type: "check",
id_site: p.site.id, id_site: p.site.id,

View File

@ -5,7 +5,6 @@ import trim from "lodash.trim";
import { EditorGlobal } from "../../../../logic/global"; import { EditorGlobal } from "../../../../logic/global";
import { Loading } from "../../../../../../utils/ui/loading"; import { Loading } from "../../../../../../utils/ui/loading";
import { w } from "../../../../../../utils/types/general"; import { w } from "../../../../../../utils/types/general";
import { reloadDBAPI } from "../../../../../../utils/script/init-api";
export const InternalAPI: FC<{ export const InternalAPI: FC<{
close: () => void; close: () => void;
@ -178,10 +177,6 @@ export const InternalAPI: FC<{
config.api_url = `https://${p.site.api_prasi.port}.prasi.world`; config.api_url = `https://${p.site.api_prasi.port}.prasi.world`;
const base = trim(config.api_url, "/"); const base = trim(config.api_url, "/");
try {
await reloadDBAPI(base);
} catch (e) {}
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
@ -198,16 +193,7 @@ export const InternalAPI: FC<{
<div <div
className={cx("cursor-pointer hover:underline")} className={cx("cursor-pointer hover:underline")}
onClick={async () => { onClick={async () => {}}
local.clearingCache = true;
local.render();
try {
await reloadDBAPI(p.site.api_url, "dev");
} catch (e) {}
local.clearingCache = false;
local.render();
alert("API Cache Cleared");
}}
> >
{local.clearingCache ? "Clearing Cache..." : "Clear API Cache"} {local.clearingCache ? "Clearing Cache..." : "Clear API Cache"}
</div> </div>

View File

@ -1,7 +1,7 @@
import { createRouter } from "radix3"; import { createRouter } from "radix3";
import { validate } from "uuid"; import { validate } from "uuid";
import { type apiClient } from "web-utils"; import { apiProxy } from "../../../base/load/api/api-proxy";
import { createAPI, createDB, initApi } from "../../../utils/script/init-api"; import { dbProxy } from "../../../base/load/db/db-proxy";
import importModule from "../../editor/tools/dynamic-import"; import importModule from "../../editor/tools/dynamic-import";
import { LSite, PG } from "./global"; import { LSite, PG } from "./global";
import { validateLayout } from "./layout"; import { validateLayout } from "./layout";
@ -17,7 +17,6 @@ export const w = window as unknown as {
isDesktop: boolean; isDesktop: boolean;
exports: any; exports: any;
params: any; params: any;
apiClient: typeof apiClient;
apiurl: string; apiurl: string;
preload: (path: string) => void; preload: (path: string) => void;
mobile?: ReturnType<typeof registerMobile>; mobile?: ReturnType<typeof registerMobile>;
@ -94,7 +93,7 @@ export const initLive = async (p: PG, domain_or_siteid: string) => {
await validateLayout(p); await validateLayout(p);
p.site.api_url = await initApi(site.config, "prod"); p.site.api_url = site.config.api_url || "";
w.apiurl = p.site.api_url; w.apiurl = p.site.api_url;
@ -104,8 +103,8 @@ export const initLive = async (p: PG, domain_or_siteid: string) => {
const exec = (fn: string, scopes: any) => { const exec = (fn: string, scopes: any) => {
if (p) { if (p) {
if (p.site.api_url) { if (p.site.api_url) {
scopes["api"] = createAPI(p.site.api_url); scopes["api"] = apiProxy(p.site.api_url);
scopes["db"] = createDB(p.site.api_url); scopes["db"] = dbProxy(p.site.api_url);
} }
if (!w.params) { if (!w.params) {
w.params = {}; w.params = {};

View File

@ -1,4 +1,4 @@
import { w } from "../../../utils/script/init-api"; import { w } from "../../../utils/types/general";
import { PG } from "./global"; import { PG } from "./global";
type NOTIF_ARG = { type NOTIF_ARG = {

View File

@ -1,5 +1,6 @@
import { FC } from "react"; import { FC } from "react";
import { createAPI, createDB } from "../../../utils/script/init-api"; import { apiProxy } from "../../../base/load/api/api-proxy";
import { dbProxy } from "../../../base/load/db/db-proxy";
import { FNCompDef } from "../../../utils/types/meta-fn"; import { FNCompDef } from "../../../utils/types/meta-fn";
import { LItem } from "../elements/l-item"; import { LItem } from "../elements/l-item";
import { PG } from "./global"; import { PG } from "./global";
@ -19,8 +20,8 @@ export const treePropEval = (
if (meta.item.type === "item" && meta.item.component) { if (meta.item.type === "item" && meta.item.component) {
if (p.site.api_url) { if (p.site.api_url) {
if (!p.script.db) p.script.db = createDB(p.site.api_url); if (!p.script.db) p.script.db = dbProxy(p.site.api_url);
if (!p.script.api) p.script.api = createAPI(p.site.api_url); if (!p.script.api) p.script.api = apiProxy(p.site.api_url);
} }
const props = meta.item.component.props; const props = meta.item.component.props;

View File

@ -1,10 +1,11 @@
import hash_sum from "hash-sum";
import { FC, ReactNode, Suspense, useEffect, useState } from "react"; import { FC, ReactNode, Suspense, useEffect, useState } from "react";
import { deepClone } from "web-utils"; import { deepClone } from "web-utils";
import { createAPI, createDB } from "../../../utils/script/init-api"; import { apiProxy } from "../../../base/load/api/api-proxy";
import { dbProxy } from "../../../base/load/db/db-proxy";
import { ErrorBox } from "../../editor/elements/e-error"; import { ErrorBox } from "../../editor/elements/e-error";
import { ItemMeta, PG } from "./global"; import { ItemMeta, PG } from "./global";
import { extractNavigate, preload } from "./route"; import { extractNavigate, preload } from "./route";
import hash_sum from "hash-sum";
export const JS_DEBUG = false; export const JS_DEBUG = false;
@ -43,8 +44,8 @@ export const treeScopeEval = (
// prepare args // prepare args
if (p.site.api_url) { if (p.site.api_url) {
if (!p.script.db) p.script.db = createDB(p.site.api_url); if (!p.script.db) p.script.db = dbProxy(p.site.api_url);
if (!p.script.api) p.script.api = createAPI(p.site.api_url); if (!p.script.api) p.script.api = apiProxy(p.site.api_url);
} }
const w = window as any; const w = window as any;

View File

@ -1,4 +1,4 @@
import { w } from "../../utils/script/init-api"; import { w } from "../../utils/types/general";
import { Loader } from "../live/logic/global"; import { Loader } from "../live/logic/global";
const cache = { const cache = {
@ -55,7 +55,7 @@ export const mobileLoader: Loader = {
}; };
const load = async (url: string) => { const load = async (url: string) => {
const res = await fetch(`${w.mobilepath}${url}`); const res = await fetch(`${(w as any).mobilepath}${url}`);
try { try {
const text = await res.text(); const text = await res.text();
const json = JSON.parse(text); const json = JSON.parse(text);

View File

@ -1,4 +1,4 @@
import { w } from "../../utils/script/init-api"; import { w } from "../../utils/types/general";
import { Loader } from "../live/logic/global"; import { Loader } from "../live/logic/global";
const base = `/_web/${(window as any).id_site}`; const base = `/_web/${(window as any).id_site}`;

View File

@ -1,154 +0,0 @@
import { createStore, get, set } from "idb-keyval";
import trim from "lodash.trim";
import { apiClient, dbClient, waitUntil } from "web-utils";
import { createFrameCors } from "web-utils";
export const w = window as unknown as {
prasiApi: Record<string, any>;
apiHeaders: any;
apiClient: typeof apiClient;
dbClient: typeof dbClient;
serverurl: string;
apiurl: string;
mobilepath: string;
};
export const createAPI = (url: string) => {
if (!w.apiClient) {
w.apiClient = apiClient;
}
if (!w.prasiApi) {
w.prasiApi = {};
}
if (!url) {
return null;
}
return w.apiClient(w.prasiApi[url]?.apiEntry, url);
};
export const createDB = (url: string) => {
if (!w.dbClient) {
w.dbClient = dbClient;
}
const dbc: typeof dbClient = w.dbClient;
return dbc("db", url);
};
export const initApi = async (config: any, mode: "dev" | "prod" = "dev") => {
let url = "";
if (config.prasi) {
if (
!(
location.hostname === "prasi.app" ||
location.hostname === "api.prasi.app"
) // android localhost
) {
if (
location.hostname === "localhost" ||
location.hostname === "127.0.0.1" ||
location.hostname === "10.0.2.2"
) {
url = `https://${config.prasi.port}.prasi.world`;
} else {
url = `https://${location.hostname}:${config.prasi.port}`;
}
} else {
url = `https://${config.prasi.port}.prasi.world`;
}
} else if (config.api_url) {
url = config.api_url;
}
if (!w.prasiApi) {
w.prasiApi = {};
}
if (url) {
if (!w.prasiApi[url]) {
try {
await reloadDBAPI(url, mode);
} catch (e) {}
}
}
return url;
};
const loadText = async (url: string, v2?: boolean) => {
const res = await fetch(url);
return await res.text();
};
export const reloadDBAPI = async (
url: string,
mode: "dev" | "prod" = "dev"
) => {
const base = trim(url, "/");
if (!w.prasiApi) {
w.prasiApi = {};
}
const cache = createStore(`prasi-api`, "config");
const forceReload = async () => {
if (!w.prasiApi[url]) {
w.prasiApi[url] = {};
}
const frm = await createFrameCors(base);
const raw = await frm.sendRaw(`/_prasi/_`);
let ver = "";
if (raw && (raw as any).prasi) {
ver = (raw as any).prasi;
}
if (ver === "v2") {
await new Promise<void>((done) => {
const d = document;
const script = d.createElement("script");
script.onload = async () => {
done();
};
script.src = `${base}/_prasi/load.js?url=${url}${
mode === "dev" ? "&dev=1" : ""
}`;
d.body.appendChild(script);
});
} else {
const apiTypes = await fetch(base + "/_prasi/api-types");
const apiEntry = await fetch(base + "/_prasi/api-entry");
w.prasiApi[url] = {
apiEntry: (await apiEntry.json()).srv,
prismaTypes: {
"prisma.d.ts": await loadText(`${base}/_prasi/prisma/index.d.ts`),
"runtime/index.d.ts": await loadText(
`${base}/_prasi/prisma/runtime/index.d.ts`
),
"runtime/library.d.ts": await loadText(
`${base}/_prasi/prisma/runtime/library.d.ts`
),
},
apiTypes: await apiTypes.text(),
};
}
await set(url, JSON.stringify(w.prasiApi[url]), cache);
};
const prasiBase = `${location.protocol}//${location.host}`;
try {
const found = await get(url, cache);
if (found) {
w.prasiApi[url] = JSON.parse(found);
await forceReload();
} else {
await forceReload();
}
} catch (e) {
console.warn("Failed to load API");
if (url === prasiBase) {
console.error("Failed to load prasi. Reloading...");
setTimeout(() => location.reload(), 3000);
}
}
};

View File

@ -12,12 +12,12 @@ export type PageProps = {
export type PrasiAPI = { export type PrasiAPI = {
apiEntry: any; apiEntry: any;
prismaTypes: { prismaTypes?: {
"prisma.d.ts": string; "prisma.d.ts": string;
"runtime/library.d.ts": string; "runtime/library.d.ts": string;
"runtime/index.d.ts": string; "runtime/index.d.ts": string;
}; };
apiTypes: string; apiTypes?: string;
}; };
export const w = window as unknown as { export const w = window as unknown as {
@ -32,6 +32,7 @@ export const w = window as unknown as {
editorGlbDefault: string; editorGlbDefault: string;
ts: number; ts: number;
serverurl: string; serverurl: string;
apiurl: string;
api: any; api: any;
db: any; db: any;
offline: boolean; offline: boolean;

View File

@ -1,21 +0,0 @@
import { apiContext } from "../server/api/api-ctx";
import { g } from "../utils/global";
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");
res.setHeader("Access-Control-Allow-Headers", "content-type");
res.setHeader("Access-Control-Allow-Credentials", "true");
if (allowUrl) {
res.setHeader("Access-Control-Allow-Origin", allowUrl);
}
res.setHeader("content-type", "text/html");
res.setHeader("etag", g.frm.etag);
res.send(`<script>${g.frm.js}</script>`);
},
};

View File

@ -2,8 +2,8 @@ import { apiContext } from "../server/api/api-ctx";
import { DBArg, execQuery } from "../utils/query"; import { DBArg, execQuery } from "../utils/query";
export const _ = { export const _ = {
url: "/_dbs/:dbName/:action", url: "/_dbs/:action",
async api(dbName: any, action?: string) { async api(action?: string) {
const { req, res } = apiContext(this); const { req, res } = apiContext(this);
try { try {

View File

@ -1,7 +1,6 @@
import { createRouter } from "radix3"; import { createRouter } from "radix3";
import { g } from "utils/global"; import { g } from "utils/global";
import { createResponse } from "./api/api-ctx"; import { createResponse } from "./api/api-ctx";
import { prepareApiRoutes } from "./api/api-scan";
export const serveAPI = { export const serveAPI = {
init: async () => { init: async () => {

View File

@ -43,7 +43,6 @@ export const serveStatic = {
if (filename) { if (filename) {
const path = join("static", filename); const path = join("static", filename);
const file = Bun.file(dir.path(`app/${path}`)); const file = Bun.file(dir.path(`app/${path}`));
console.log(_, filename);
if (await file.exists()) { if (await file.exists()) {
cache.static[`/${filename}`] = { cache.static[`/${filename}`] = {
type: mime.getType(path) || "application/octet-stream", type: mime.getType(path) || "application/octet-stream",

View File

@ -1,205 +0,0 @@
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 (
rawUrl: string,
params: any,
parentWindow?: any
) => {
let w: any = typeof window === "object" ? window : globalThis;
const win = parentWindow || w;
const url = new URL(rawUrl);
let frm: Awaited<ReturnType<typeof createFrameCors>>;
const base = `${url.protocol}//${url.host}`;
if (!win.frmapi) {
win.frmapi = {};
}
if (!win.frmapi[base]) {
win.frmapi[base] = await createFrameCors(base, win);
}
frm = win.frmapi[base];
if (!win.apiHeaders) {
win.apiHeaders = {};
}
if (!frm) {
await waitUntil(() => {
frm = win.frmapi[base];
return frm;
});
}
if (url.pathname.startsWith("//")) {
url.pathname = url.pathname.substring(1);
}
return await frm.send(url.pathname, params, win.apiHeaders);
};

View File

@ -7,7 +7,4 @@ 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;