@ramesesinc/loader 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # rameses-lib
2
+
3
+ A lightweight, dynamic loader library for Next.js projects.
4
+ This library helps you **dynamically load pages, templates, and menus** based on tenant/module configurations.
5
+
6
+ ---
7
+
8
+ ## 📦 Installation
9
+
10
+ Install from npm:
11
+
12
+ ```bash
13
+ npm install rameses-lib
14
+ # or
15
+ yarn add rameses-lib
16
+ ```
@@ -0,0 +1,4 @@
1
+ export { ComponentLoaders, initComponentLoaders, loadComponent } from "./loaders/ComponentLoader";
2
+ export { loadMenu } from "./loaders/MenuLoader";
3
+ export { initTemplateLoaders, loadPage, TemplateLoaders } from "./loaders/PageLoader";
4
+ export { addRoutes } from "./utils/config";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // src/index.ts
2
+ export { initComponentLoaders, loadComponent } from "./loaders/ComponentLoader";
3
+ export { loadMenu } from "./loaders/MenuLoader";
4
+ export { initTemplateLoaders, loadPage } from "./loaders/PageLoader";
5
+ export { addRoutes } from "./utils/config";
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ interface ComponentConfig {
3
+ component?: string;
4
+ attr?: Record<string, any>;
5
+ _id?: string;
6
+ title?: string;
7
+ debug?: boolean;
8
+ }
9
+ interface LoadComponentOptions {
10
+ tenant?: string;
11
+ module?: string;
12
+ component: string;
13
+ target?: string;
14
+ params?: Record<string, any>;
15
+ collections?: string;
16
+ apiBase?: string;
17
+ }
18
+ export type ComponentLoaders = Record<string, (name: string) => React.ComponentType<any> | null>;
19
+ export declare const initComponentLoaders: (loaders: ComponentLoaders) => void;
20
+ export declare const loadComponent: ({ module, component, target, params, collections, apiBase, }: LoadComponentOptions) => Promise<React.ReactElement>;
21
+ export type { ComponentConfig, LoadComponentOptions };
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createAPI } from "../utils/createApi";
3
+ import { resolveTenantModule } from "../utils/resolveTenantModule";
4
+ let globalComponentLoaders = {};
5
+ export const initComponentLoaders = (loaders) => {
6
+ globalComponentLoaders = loaders;
7
+ };
8
+ export const loadComponent = async ({ module, component, target, params = {}, collections, apiBase = "/api/localapi", }) => {
9
+ try {
10
+ let { tenant: tenantID, module: moduleID } = params !== null && params !== void 0 ? params : {};
11
+ if (!tenantID && !moduleID) {
12
+ const resolved = resolveTenantModule();
13
+ tenantID = resolved.tenant;
14
+ moduleID = resolved.module;
15
+ }
16
+ if (!tenantID || !moduleID) {
17
+ throw new Error("Both tenant and module are required from props");
18
+ }
19
+ let config = {};
20
+ const req = {};
21
+ // If component name is provided, try to load its configuration
22
+ if (component) {
23
+ const collection = collections || "components";
24
+ req.path = `/mgmt/${tenantID}/${moduleID}/${collection}/${component}`;
25
+ req.type = "GET";
26
+ req.tenant = tenantID;
27
+ req.module = moduleID;
28
+ req.contextPath = process.env.NEXT_PUBLIC_APP_CONTEXT_PATH;
29
+ req.filePath = `mgmt/${collection}/${component}.json`;
30
+ try {
31
+ const api = createAPI();
32
+ const result = await api.post(`${apiBase}/invoke`, req);
33
+ const data = result.data;
34
+ if (data === null || data === void 0 ? void 0 : data.message) {
35
+ console.log("Data from LoadComponent", { data });
36
+ }
37
+ config = data;
38
+ }
39
+ catch (err) {
40
+ console.error("Error loading component config:", err);
41
+ // Continue with default config if loading fails
42
+ }
43
+ }
44
+ else {
45
+ throw new Error("Component name is required");
46
+ }
47
+ const componentName = config.component || component;
48
+ if (!componentName) {
49
+ throw new Error("No component specified in the configuration.");
50
+ }
51
+ const [namespace, componentKey] = componentName.includes(":") ? componentName.split(":") : ["default", componentName];
52
+ const normalizedNamespace = namespace.replace("@", "");
53
+ const importer = globalComponentLoaders[normalizedNamespace];
54
+ if (!importer) {
55
+ throw new Error(`Namespace '${namespace}' not registered in component loaders.`);
56
+ }
57
+ const Component = importer(componentKey);
58
+ if (!Component) {
59
+ throw new Error(`Component '${componentKey}' not found in namespace '${namespace}'.`);
60
+ }
61
+ return _jsx(Component, { attr: config.attr, id: config._id, title: config.title, params: params, target: target, debug: config.debug });
62
+ }
63
+ catch (error) {
64
+ console.error("Component loading error:", error);
65
+ return (_jsx("div", { className: "p-4 bg-yellow-100 border border-yellow-400 rounded-lg", children: _jsxs("p", { className: "text-yellow-800 font-medium", children: ["Component Error: ", error.message] }) }));
66
+ }
67
+ };
@@ -0,0 +1,3 @@
1
+ export declare const loadMenu: ({ menuid }: {
2
+ menuid: string;
3
+ }) => Promise<any>;
@@ -0,0 +1,28 @@
1
+ import { createAPI } from "../utils/createApi";
2
+ import { resolveTenantModule } from "../utils/resolveTenantModule";
3
+ export const loadMenu = ({ menuid }) => {
4
+ const resolved = resolveTenantModule();
5
+ const tenant = resolved.tenant || process.env.NEXT_PUBLIC_TENANT_NAME;
6
+ const module = process.env.NEXT_PUBLIC_MODULE_NAME || resolved.module;
7
+ const req = {};
8
+ const fetchData = async () => {
9
+ req.path = `/mgmt/${tenant}/${module}/menus/${menuid}`;
10
+ req.type = "GET";
11
+ req.tenant = tenant;
12
+ req.module = module;
13
+ req.contextPath = process.env.NEXT_PUBLIC_APP_CONTEXT_PATH;
14
+ if (menuid !== "list") {
15
+ req.filePath = `mgmt/menus/${menuid}.json`;
16
+ }
17
+ try {
18
+ const api = createAPI();
19
+ const result = await api.post("/api/localapi/invoke", req);
20
+ return result.data;
21
+ }
22
+ catch (err) {
23
+ console.error(err);
24
+ return { items: [] };
25
+ }
26
+ };
27
+ return fetchData();
28
+ };
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ interface LoadOptions {
3
+ tenant?: string;
4
+ module?: string;
5
+ page?: string;
6
+ component?: string;
7
+ params?: Record<string, any>;
8
+ target: string;
9
+ collections?: string;
10
+ apiBase?: string;
11
+ }
12
+ export type TemplateLoaders = Record<string, (name: string) => React.ComponentType<any> | null>;
13
+ export declare const initTemplateLoaders: (loaders: TemplateLoaders) => void;
14
+ export declare const loadPage: ({ module, page, component, params, target, collections, apiBase }: LoadOptions) => Promise<import("react/jsx-runtime").JSX.Element>;
15
+ export {};
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createAPI } from "../utils/createApi";
3
+ import { resolveTenantModule } from "../utils/resolveTenantModule";
4
+ let globalTemplateLoaders = {};
5
+ export const initTemplateLoaders = (loaders) => {
6
+ globalTemplateLoaders = loaders;
7
+ };
8
+ export const loadPage = async ({ module, page, component, params = {}, target, collections, apiBase = "/api/localapi" }) => {
9
+ var _a;
10
+ try {
11
+ let { tenant: tenantID, module: moduleID } = params !== null && params !== void 0 ? params : {};
12
+ if (!tenantID && !moduleID) {
13
+ const resolved = resolveTenantModule();
14
+ const tenantID = resolved.tenant;
15
+ const moduleID = resolved.module;
16
+ }
17
+ if (!tenantID || !moduleID) {
18
+ throw new Error("Both tenant and module are required from props");
19
+ }
20
+ let conf = {};
21
+ const req = {};
22
+ if (page) {
23
+ const collection = !collections ? "pages" : collections;
24
+ req.path = `/mgmt/${tenantID}/${moduleID}/${collection}/${page}`;
25
+ req.type = "GET";
26
+ req.tenant = tenantID;
27
+ req.module = moduleID;
28
+ req.contextPath = process.env.NEXT_PUBLIC_APP_CONTEXT_PATH;
29
+ if (page !== "list") {
30
+ req.filePath = `mgmt/${collection}/${page}.json`;
31
+ }
32
+ try {
33
+ const api = createAPI();
34
+ // console.log({ path: `${apiBase}/invoke`, req });
35
+ const result = await api.post(`${apiBase}/invoke`, req);
36
+ // console.log("Result", result);
37
+ const data = result.data;
38
+ if (data === null || data === void 0 ? void 0 : data.message) {
39
+ console.log("Data from LoadPage", { data });
40
+ }
41
+ conf = data;
42
+ }
43
+ catch (err) {
44
+ console.error(err);
45
+ }
46
+ }
47
+ else {
48
+ conf.template = component;
49
+ conf.attr = {};
50
+ }
51
+ if (!conf.template) {
52
+ throw new Error("No template found in the configuration.");
53
+ }
54
+ const [namespace, xpage] = conf.template.includes(":") ? conf.template.split(":") : ["default", conf.template];
55
+ const normalizedNamespace = namespace.replace("@", "");
56
+ const importer = globalTemplateLoaders[normalizedNamespace];
57
+ if (!importer)
58
+ throw new Error(`Namespace '${namespace}' not registered.`);
59
+ const Template = importer(xpage);
60
+ if (!Template)
61
+ throw new Error(`Template '${xpage}' not found.`);
62
+ // return <Template attr={conf.attr} id={conf._id} title={conf.title} params={params} target={target} debug={conf.debug} />;
63
+ return (_jsx(Template, Object.assign({}, conf.attr, { attr: conf.attr, data: (_a = conf.data) !== null && _a !== void 0 ? _a : {}, id: conf._id, title: conf.title, params: params, target: target, debug: conf.debug })));
64
+ }
65
+ catch (error) {
66
+ return (_jsx("div", { className: "p-4 bg-red-100 border border-red-400 rounded-lg", children: _jsxs("p", { className: "text-red-700 font-medium", children: ["Error: ", error.message] }) }));
67
+ }
68
+ };
File without changes
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ // import dynamic from "next/dynamic";
3
+ // export const templateLoaders: Record<string, (name: string) => React.ComponentType<any> | null> = {
4
+ // seti: (name) => dynamic(() => import(`@/seti/templates/${name}`)),
5
+ // agos: (name) => dynamic(() => import(`@/agos/templates/${name}`)),
6
+ // default: (name) => dynamic(() => import(`@/templates/${name}`)),
7
+ // };
@@ -0,0 +1 @@
1
+ {"root":["../src/index.ts","../src/loaders/componentloader.tsx","../src/loaders/menuloader.ts","../src/loaders/pageloader.tsx","../src/loaders/templateloader.ts","../src/utils/config.ts","../src/utils/createapi.ts","../src/utils/resolvetenantmodule.ts"],"version":"5.9.3"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Add route prefixes
3
+ */
4
+ export declare const addRoutes: (routes: string[]) => void;
5
+ /**
6
+ * Get route prefixes
7
+ */
8
+ export declare const getRoutePrefixes: () => string[];
@@ -0,0 +1,11 @@
1
+ let routePrefixes = [];
2
+ /**
3
+ * Add route prefixes
4
+ */
5
+ export const addRoutes = (routes) => {
6
+ routePrefixes = [...routePrefixes, ...routes];
7
+ };
8
+ /**
9
+ * Get route prefixes
10
+ */
11
+ export const getRoutePrefixes = () => routePrefixes;
@@ -0,0 +1 @@
1
+ export declare function createAPI(): import("axios").AxiosInstance;
@@ -0,0 +1,12 @@
1
+ import axios from "axios";
2
+ const __LOCAL_API_KEY__ = "4e3b5a2c-9c74-4e10-9c76-3a3deec6d3c2";
3
+ export function createAPI() {
4
+ const api = axios.create();
5
+ api.interceptors.request.use((config) => {
6
+ if (config.headers) {
7
+ config.headers["X-LOCAL_API_KEY"] = __LOCAL_API_KEY__;
8
+ }
9
+ return config;
10
+ });
11
+ return api;
12
+ }
@@ -0,0 +1,4 @@
1
+ export declare const resolveTenantModule: () => {
2
+ tenant?: string;
3
+ module?: string;
4
+ };
@@ -0,0 +1,12 @@
1
+ import { getRoutePrefixes } from "./config";
2
+ export const resolveTenantModule = () => {
3
+ if (typeof window === "undefined")
4
+ return {};
5
+ const routePrefixes = getRoutePrefixes();
6
+ const pathname = window.location.pathname;
7
+ const [, seg1, seg2, seg3] = pathname.split("/");
8
+ if (seg1 === 'modules' || seg1 === 'sysmgmt') {
9
+ return { tenant: seg2, module: seg3 };
10
+ }
11
+ return {};
12
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@ramesesinc/loader",
3
+ "version": "1.0.10",
4
+ "description": "Reusable loader utilities",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./utils": {
15
+ "import": "./dist/utils/index.js",
16
+ "require": "./dist/utils/index.js",
17
+ "types": "./dist/utils/index.d.ts"
18
+ },
19
+ "./loaders": {
20
+ "import": "./dist/loaders/index.js",
21
+ "require": "./dist/loaders/index.js",
22
+ "types": "./dist/loaders/index.d.ts"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc --build",
30
+ "clean": "rm -rf dist",
31
+ "dev": "tsc --watch",
32
+ "prepublishOnly": "npm run build"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "peerDependencies": {
38
+ "axios": ">=1.0.0",
39
+ "next": ">=13.5.0 <15.0.0",
40
+ "react": ">=18.0.0",
41
+ "react-dom": ">=18.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^20",
45
+ "@types/react": "^18",
46
+ "@types/react-dom": "^18",
47
+ "typescript": "^5.9.2"
48
+ }
49
+ }