This commit is contained in:
rizky 2024-08-21 07:58:53 -07:00
parent 13d68d0a3e
commit 5de493a07f
4 changed files with 134 additions and 22 deletions

View File

@ -23,6 +23,7 @@
"@types/react": "^18.2.65",
"bun-types": "^1.1.24",
"@types/react-dom": "^18.3.0",
"rou3": "^0.5.1",
"@types/uuid": "^9.0.8",
"@wojtekmaj/react-qr-svg": "^1.0.0",
"any-date-parser": "^1.5.4",

View File

@ -1,3 +1,6 @@
import { _post } from "lib/utils/post";
import { addRoute, createRouter, findRoute } from "rou3";
export type ServerArg = {
req: Request;
handle: (req: Request) => Promise<Response>;
@ -7,7 +10,85 @@ export type ServerArg = {
pathname: string;
};
};
export const newRoute = (arg: {
url: string;
handler: (arg: ServerArg) => Promise<Response | void> | Response | void;
}) => {};
type RouteFn = (...arg: any[]) => Promise<any>;
type SingleRoute = [string, () => Promise<{ default: RouteFn }>];
type SingleRouteWithOption = [
string,
() => Promise<{ default: RouteFn }>,
RouteOption
];
type RouteOption = {
request_as?: "json" | "raw";
response_as?: "json" | "raw";
};
export const newRouter = <
T extends Record<string, SingleRoute | SingleRouteWithOption>
>(
arg: T
) => {
return arg;
};
export const serverRouting = <T extends ReturnType<typeof newRouter>>(
router: T
) => {
return new Proxy(
{},
{
get(target, api_name, receiver) {
return (...args: any[]) => {
const [url, _, opt] = router[api_name as any];
if (opt && opt.response_as)
return _post(url, args, { response_as: opt.response_as });
return _post(url, args);
};
},
}
) as {
[K in keyof T]: Awaited<ReturnType<T[K][1]>>["default"];
};
};
export const useServerRoutes = async <T extends ReturnType<typeof newRouter>>(
router: T
) => {
const rou = createRouter<{
handler: { default: RouteFn };
opt?: RouteOption;
}>();
for (const item of Object.values(router)) {
try {
addRoute(rou, undefined, item[0], {
handler: await (item as any)[1](),
opt: item[2],
});
} catch (e) {}
}
return {
async handle(arg: ServerArg) {
const { url, req } = arg;
const found = findRoute(rou, undefined, url.pathname);
if (found) {
const route = found.data;
let result = null;
if (!route.opt || route.opt?.request_as === "raw") {
result = await route.handler.default();
} else {
const params = await req.json();
result = await route.handler.default(...params);
}
if (result) return result;
else return new Response(JSON.stringify(result));
}
return await arg.handle(arg.req);
},
};
};

View File

@ -1,6 +1,6 @@
/// <reference types="bun-types" />
import { ServerArg } from "./server-route";
import { ServerArg, useServerRoutes } from "./server-route";
type ServerSession = {
handle: (arg: ServerArg) => Promise<Response>;
@ -8,9 +8,7 @@ type ServerSession = {
export const sessionServer = <T>(arg: {
encrypt?: boolean;
router?: (
arg: ServerArg & { session: {} }
) => Response | (() => Promise<Response | void>) | void;
router?: ReturnType<typeof useServerRoutes>;
on: {
login: (arg: {
mode: "user-pass";
@ -19,23 +17,31 @@ export const sessionServer = <T>(arg: {
}) => Promise<false | T>;
};
}): ServerSession => {
const internal = {
has_router: false,
router: null as null | Awaited<ReturnType<typeof useServerRoutes>>,
};
if (typeof arg.router === "object" && arg.router instanceof Promise) {
internal.has_router = true;
arg.router.then((e) => {
internal.router = e;
});
}
const s: ServerSession = {
async handle(server_arg) {
const { req, handle, mode, url } = server_arg;
if (typeof arg.router === "function") {
let result = arg.router({
...server_arg,
session: {},
});
if (result && typeof result === "function") {
result = await result();
}
if (result instanceof Response) {
const { req, handle } = server_arg;
if (internal.has_router && internal.router) {
const result = await internal.router.handle(server_arg);
if (typeof result === "object" && result instanceof Response) {
return result;
}
return new Response(JSON.stringify(result));
}
return await handle(req);
return handle(req);
},
};

View File

@ -1,7 +1,9 @@
import { baseurl } from "./baseurl";
export const _post = async (
path: string,
data: any,
arg?: { mode: "auto" | "always-prod" }
opt?: { server_target?: "auto" | "always-prod"; response_as?: "json" | "raw" }
) => {
const final_path = path.startsWith("/") ? path : `/${path}`;
@ -11,7 +13,7 @@ export const _post = async (
location.hostname === "prasi.avolut.com" ||
location.host === "localhost:4550"
) {
if (arg?.mode === "always-prod") {
if (opt?.server_target === "always-prod") {
const newurl = new URL(location.href);
newurl.pathname = `/_proxy/${_url}`;
_url = newurl.toString();
@ -22,5 +24,27 @@ export const _post = async (
method: "POST",
body: JSON.stringify(data),
});
return await res.json();
let text = await res.text();
if (!opt || (opt && opt.response_as === "json")) {
try {
return JSON.parse(text);
} catch (e) {
console.error(`\
🚧 Server Error: ${path}
`);
console.error(
`%c⬆ DATA SENT: `,
"color:green",
`\n` + JSON.stringify(data, null, 2)
);
console.error(
`%c⬇ DATA RECEIVED: `,
`color:red`,
`\n` + JSON.stringify(text, null, 2)
);
console.error(`Failed to parse received data as JSON!`);
}
} else {
return text;
}
};