frontend-hamroun 1.2.74 → 1.2.77
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/dist/Counter.d.ts +0 -0
- package/dist/batch/package.json +16 -0
- package/dist/client-router/package.json +16 -0
- package/dist/component/package.json +16 -0
- package/dist/context/package.json +16 -0
- package/dist/event-bus/package.json +16 -0
- package/dist/forms/package.json +16 -0
- package/dist/hooks/package.json +16 -0
- package/dist/hooks-0728361a.cjs +1 -0
- package/dist/hooks-b58f947c.js +133 -0
- package/dist/hooks.js +1 -0
- package/dist/hooks.mjs +13 -0
- package/dist/index.js +1 -384
- package/dist/index.mjs +130 -374
- package/dist/jsx-runtime/package.json +16 -0
- package/dist/jsx-runtime.js +1 -0
- package/dist/jsx-runtime.mjs +64 -0
- package/dist/lifecycle-events/package.json +16 -0
- package/dist/package.json +71 -0
- package/dist/render-component/package.json +16 -0
- package/dist/renderer/package.json +16 -0
- package/dist/renderer.js +1 -0
- package/dist/renderer.mjs +27 -0
- package/dist/router/package.json +16 -0
- package/dist/server/package.json +17 -0
- package/dist/server/src/batch.d.ts +3 -0
- package/dist/server/src/batch.js +23 -0
- package/dist/server/src/batch.js.map +1 -0
- package/dist/server/src/client-router.d.ts +60 -0
- package/dist/server/src/client-router.js +210 -0
- package/dist/server/src/client-router.js.map +1 -0
- package/dist/server/src/component.d.ts +14 -0
- package/dist/server/src/component.js +106 -0
- package/dist/server/src/component.js.map +1 -0
- package/dist/server/src/context.d.ts +13 -0
- package/dist/server/src/context.js +21 -0
- package/dist/server/src/context.js.map +1 -0
- package/dist/server/src/event-bus.d.ts +23 -0
- package/dist/server/src/event-bus.js +75 -0
- package/dist/server/src/event-bus.js.map +1 -0
- package/dist/server/src/forms.d.ts +40 -0
- package/dist/server/src/forms.js +148 -0
- package/dist/server/src/forms.js.map +1 -0
- package/dist/server/src/hooks.d.ts +12 -0
- package/dist/server/src/hooks.js +170 -0
- package/dist/server/src/hooks.js.map +1 -0
- package/dist/server/src/index.client.d.ts +12 -0
- package/dist/server/src/index.client.js +14 -0
- package/dist/server/src/index.client.js.map +1 -0
- package/dist/server/src/index.d.ts +88 -0
- package/dist/server/src/index.js +78 -0
- package/dist/server/src/index.js.map +1 -0
- package/dist/server/src/jsx-runtime/jsx-dev-runtime.d.ts +1 -0
- package/dist/server/src/jsx-runtime/jsx-dev-runtime.js +2 -0
- package/dist/server/src/jsx-runtime/jsx-dev-runtime.js.map +1 -0
- package/dist/server/src/jsx-runtime/jsx-runtime.d.ts +4 -0
- package/dist/server/src/jsx-runtime/jsx-runtime.js +41 -0
- package/dist/server/src/jsx-runtime/jsx-runtime.js.map +1 -0
- package/dist/server/src/jsx-runtime.d.ts +20 -0
- package/dist/server/src/jsx-runtime.js +105 -0
- package/dist/server/src/jsx-runtime.js.map +1 -0
- package/dist/server/src/lifecycle-events.d.ts +108 -0
- package/dist/server/src/lifecycle-events.js +177 -0
- package/dist/server/src/lifecycle-events.js.map +1 -0
- package/dist/server/src/renderComponent.d.ts +14 -0
- package/dist/server/src/renderComponent.js +25 -0
- package/dist/server/src/renderComponent.js.map +1 -0
- package/dist/server/src/renderer.d.ts +2 -0
- package/dist/server/src/renderer.js +31 -0
- package/dist/server/src/renderer.js.map +1 -0
- package/dist/server/src/router.d.ts +55 -0
- package/dist/server/src/router.js +166 -0
- package/dist/server/src/router.js.map +1 -0
- package/dist/server/src/server/api-router.d.ts +15 -0
- package/dist/server/src/server/api-router.js +111 -0
- package/dist/server/src/server/api-router.js.map +1 -0
- package/dist/server/src/server/auth.d.ts +32 -0
- package/dist/server/src/server/auth.js +80 -0
- package/dist/server/src/server/auth.js.map +1 -0
- package/dist/server/src/server/database.d.ts +24 -0
- package/dist/server/src/server/database.js +135 -0
- package/dist/server/src/server/database.js.map +1 -0
- package/dist/server/src/server/index.d.ts +127 -0
- package/dist/server/src/server/index.js +388 -0
- package/dist/server/src/server/index.js.map +1 -0
- package/dist/server/src/server/middleware.d.ts +11 -0
- package/dist/server/src/server/middleware.js +46 -0
- package/dist/server/src/server/middleware.js.map +1 -0
- package/dist/server/src/server/server.d.ts +9 -0
- package/dist/server/src/server/server.js +87 -0
- package/dist/server/src/server/server.js.map +1 -0
- package/dist/server/src/server/templates.d.ts +28 -0
- package/dist/server/src/server/templates.js +204 -0
- package/dist/server/src/server/templates.js.map +1 -0
- package/dist/server/src/server/types.d.ts +38 -0
- package/dist/server/src/server/types.js +4 -0
- package/dist/server/src/server/types.js.map +1 -0
- package/dist/server/src/server/utils.d.ts +70 -0
- package/dist/server/src/server/utils.js +156 -0
- package/dist/server/src/server/utils.js.map +1 -0
- package/dist/server/src/server/wasm.d.ts +9 -0
- package/dist/server/src/server/wasm.js +117 -0
- package/dist/server/src/server/wasm.js.map +1 -0
- package/dist/server/src/server-renderer.d.ts +5 -0
- package/dist/server/src/server-renderer.js +106 -0
- package/dist/server/src/server-renderer.js.map +1 -0
- package/dist/server/src/server-types.d.ts +42 -0
- package/dist/server/src/server-types.js +6 -0
- package/dist/server/src/server-types.js.map +1 -0
- package/dist/server/src/store.d.ts +41 -0
- package/dist/server/src/store.js +99 -0
- package/dist/server/src/store.js.map +1 -0
- package/dist/server/src/types.d.ts +19 -0
- package/dist/server/src/types.js +2 -0
- package/dist/server/src/types.js.map +1 -0
- package/dist/server/src/utils.d.ts +46 -0
- package/dist/server/src/utils.js +144 -0
- package/dist/server/src/utils.js.map +1 -0
- package/dist/server/src/vdom.d.ts +8 -0
- package/dist/server/src/vdom.js +22 -0
- package/dist/server/src/vdom.js.map +1 -0
- package/dist/server/src/wasm.d.ts +36 -0
- package/dist/server/src/wasm.js +159 -0
- package/dist/server/src/wasm.js.map +1 -0
- package/dist/server/tsconfig.server.tsbuildinfo +1 -0
- package/dist/server-renderer/package.json +16 -0
- package/dist/server-renderer.js +1 -0
- package/dist/server-renderer.mjs +64 -0
- package/dist/store/package.json +16 -0
- package/dist/types/package.json +16 -0
- package/dist/utils/package.json +16 -0
- package/dist/vdom/package.json +16 -0
- package/dist/wasm/package.json +16 -0
- package/dist/wasm.js +1 -0
- package/dist/wasm.mjs +103 -0
- package/package.json +14 -13
- package/templates/complete-app/build.js +284 -0
- package/templates/complete-app/package.json +40 -0
- package/templates/complete-app/public/styles.css +345 -0
- package/templates/complete-app/src/api/index.js +31 -0
- package/templates/complete-app/src/client.js +93 -0
- package/templates/complete-app/src/components/App.js +66 -0
- package/templates/complete-app/src/components/Footer.js +19 -0
- package/templates/complete-app/src/components/Header.js +38 -0
- package/templates/complete-app/src/pages/About.js +59 -0
- package/templates/complete-app/src/pages/Home.js +54 -0
- package/templates/complete-app/src/pages/WasmDemo.js +136 -0
- package/templates/complete-app/src/server.js +186 -0
- package/templates/complete-app/src/wasm/build.bat +16 -0
- package/templates/complete-app/src/wasm/build.sh +16 -0
- package/templates/complete-app/src/wasm/example.go +101 -0
- package/templates/fullstack-app/build/main.css +225 -15
- package/templates/fullstack-app/build/main.css.map +2 -2
- package/templates/fullstack-app/build/main.js +657 -372
- package/templates/fullstack-app/build/main.js.map +4 -4
- package/templates/fullstack-app/build.ts +3 -4
- package/templates/fullstack-app/public/styles.css +222 -15
- package/templates/fullstack-app/server.ts +46 -12
- package/templates/fullstack-app/src/components/ClientHome.tsx +0 -0
- package/templates/fullstack-app/src/components/ErrorBoundary.tsx +36 -0
- package/templates/fullstack-app/src/components/Layout.tsx +23 -26
- package/templates/fullstack-app/src/components/StateDemo.tsx +207 -0
- package/templates/fullstack-app/src/components/UserList.tsx +30 -13
- package/templates/fullstack-app/src/data/api.ts +173 -38
- package/templates/fullstack-app/src/main.tsx +88 -154
- package/templates/fullstack-app/src/middleware.ts +28 -0
- package/templates/fullstack-app/src/pages/404.tsx +28 -0
- package/templates/fullstack-app/src/pages/[id].tsx +0 -0
- package/templates/fullstack-app/src/pages/_app.tsx +11 -0
- package/templates/fullstack-app/src/pages/_document.tsx +25 -0
- package/templates/fullstack-app/src/pages/_error.tsx +45 -0
- package/templates/fullstack-app/src/pages/about.tsx +71 -0
- package/templates/fullstack-app/src/pages/api/users/[id].ts +73 -0
- package/templates/fullstack-app/src/pages/api/users/index.ts +43 -0
- package/templates/fullstack-app/src/pages/index.tsx +97 -20
- package/templates/fullstack-app/src/pages/users/[id].tsx +153 -0
- package/templates/fullstack-app/src/pages/wasm-demo.tsx +1 -0
- package/templates/go/build.sh +43 -43
- package/templates/go/example.go +99 -86
- package/templates/go-wasm-app/babel.config.js +8 -2
- package/templates/go-wasm-app/build-wasm.js +84 -84
- package/templates/go-wasm-app/build.config.js +62 -0
- package/templates/go-wasm-app/build.js +218 -0
- package/templates/go-wasm-app/package.json +21 -11
- package/templates/go-wasm-app/public/index.html +49 -53
- package/templates/go-wasm-app/server.js +56 -695
- package/templates/go-wasm-app/src/app.js +173 -0
- package/templates/go-wasm-app/vite.config.js +16 -5
- package/templates/ssr-template/client.js +54 -26
- package/templates/ssr-template/server.js +5 -28
- package/templates/ssr-template/vite.config.js +21 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAY,EAAE,SAAsB;IAChE,WAAW,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;YAAS,CAAC;QACT,WAAW,GAAG,KAAK,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAY,EAAE,SAAsB;IAC/D,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IAE3C,YAAY,CAAC,KAAK,IAAI,EAAE;QACtB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;YAC9C,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;YAE7C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;YAC3B,CAAC;YACD,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAEjC,CAAC;gBAAS,CAAC;YACT,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
export interface Route {
|
2
|
+
path: string;
|
3
|
+
component: any;
|
4
|
+
exact?: boolean;
|
5
|
+
children?: Route[];
|
6
|
+
}
|
7
|
+
export interface RouterContextValue {
|
8
|
+
currentPath: string;
|
9
|
+
navigate: (path: string) => void;
|
10
|
+
params: Record<string, string>;
|
11
|
+
query: Record<string, string>;
|
12
|
+
}
|
13
|
+
export interface RouteParams {
|
14
|
+
[key: string]: string;
|
15
|
+
}
|
16
|
+
export declare const RouterContext: import("./context.js").Context<RouterContextValue>;
|
17
|
+
export declare function useRouter(): RouterContextValue;
|
18
|
+
export declare function useLocation(): {
|
19
|
+
pathname: string;
|
20
|
+
search: string;
|
21
|
+
hash: string;
|
22
|
+
state: {};
|
23
|
+
};
|
24
|
+
export declare function useParams<T extends RouteParams = RouteParams>(): T;
|
25
|
+
export declare function useNavigate(): (path: string) => void;
|
26
|
+
export declare function RouterProvider({ children }: {
|
27
|
+
children: any;
|
28
|
+
}): any;
|
29
|
+
export declare function Router({ routes }: {
|
30
|
+
routes: Route[];
|
31
|
+
}): any;
|
32
|
+
export declare function Link({ to, children, ...rest }: {
|
33
|
+
to: string;
|
34
|
+
children: any;
|
35
|
+
[key: string]: any;
|
36
|
+
}): any;
|
37
|
+
export declare function Route({ path, component }: {
|
38
|
+
path: string;
|
39
|
+
component: any;
|
40
|
+
}): null;
|
41
|
+
export declare function Switch({ children }: {
|
42
|
+
children: any;
|
43
|
+
}): any;
|
44
|
+
declare const _default: {
|
45
|
+
RouterProvider: typeof RouterProvider;
|
46
|
+
Router: typeof Router;
|
47
|
+
Link: typeof Link;
|
48
|
+
Route: typeof Route;
|
49
|
+
Switch: typeof Switch;
|
50
|
+
useRouter: typeof useRouter;
|
51
|
+
useParams: typeof useParams;
|
52
|
+
useNavigate: typeof useNavigate;
|
53
|
+
useLocation: typeof useLocation;
|
54
|
+
};
|
55
|
+
export default _default;
|
@@ -0,0 +1,166 @@
|
|
1
|
+
/**
|
2
|
+
* Router implementation for client and server navigation
|
3
|
+
*/
|
4
|
+
import { useState, useEffect } from './hooks';
|
5
|
+
import { createContext, useContext } from './context';
|
6
|
+
import { jsx } from './jsx-runtime';
|
7
|
+
export const RouterContext = createContext({
|
8
|
+
currentPath: '/',
|
9
|
+
navigate: () => { },
|
10
|
+
params: {},
|
11
|
+
query: {}
|
12
|
+
});
|
13
|
+
export function useRouter() {
|
14
|
+
return useContext(RouterContext);
|
15
|
+
}
|
16
|
+
export function useLocation() {
|
17
|
+
const router = useContext(RouterContext);
|
18
|
+
return {
|
19
|
+
pathname: router.currentPath,
|
20
|
+
search: '', // TODO: Implement search parsing
|
21
|
+
hash: '', // TODO: Implement hash parsing
|
22
|
+
state: {} // TODO: Implement history state
|
23
|
+
};
|
24
|
+
}
|
25
|
+
export function useParams() {
|
26
|
+
const router = useContext(RouterContext);
|
27
|
+
return router.params;
|
28
|
+
}
|
29
|
+
export function useNavigate() {
|
30
|
+
const router = useContext(RouterContext);
|
31
|
+
return router.navigate;
|
32
|
+
}
|
33
|
+
export function RouterProvider({ children }) {
|
34
|
+
// Initial path should be window.location.pathname on client, or passed from server context
|
35
|
+
const [currentPath, setCurrentPath] = useState(typeof window !== 'undefined' ? window.location.pathname : '/');
|
36
|
+
const [params, setParams] = useState({});
|
37
|
+
const [query, setQuery] = useState({});
|
38
|
+
// Update path when URL changes
|
39
|
+
useEffect(() => {
|
40
|
+
if (typeof window === 'undefined')
|
41
|
+
return;
|
42
|
+
const handlePopState = () => {
|
43
|
+
setCurrentPath(window.location.pathname);
|
44
|
+
parseQuery(window.location.search);
|
45
|
+
};
|
46
|
+
window.addEventListener('popstate', handlePopState);
|
47
|
+
// Parse initial query
|
48
|
+
parseQuery(window.location.search);
|
49
|
+
return () => {
|
50
|
+
window.removeEventListener('popstate', handlePopState);
|
51
|
+
};
|
52
|
+
}, []);
|
53
|
+
// Parse query string into object
|
54
|
+
const parseQuery = (queryString) => {
|
55
|
+
const queryObj = {};
|
56
|
+
if (queryString.startsWith('?')) {
|
57
|
+
queryString = queryString.substring(1);
|
58
|
+
}
|
59
|
+
queryString.split('&').forEach(pair => {
|
60
|
+
if (!pair)
|
61
|
+
return;
|
62
|
+
const [key, value] = pair.split('=');
|
63
|
+
queryObj[decodeURIComponent(key)] = decodeURIComponent(value || '');
|
64
|
+
});
|
65
|
+
setQuery(queryObj);
|
66
|
+
};
|
67
|
+
// Navigate programmatically
|
68
|
+
const navigate = (path) => {
|
69
|
+
if (typeof window === 'undefined')
|
70
|
+
return;
|
71
|
+
window.history.pushState(null, '', path);
|
72
|
+
setCurrentPath(path);
|
73
|
+
parseQuery(window.location.search);
|
74
|
+
};
|
75
|
+
return jsx(RouterContext.Provider, {
|
76
|
+
value: { currentPath, navigate, params, query },
|
77
|
+
children
|
78
|
+
});
|
79
|
+
}
|
80
|
+
export function Router({ routes }) {
|
81
|
+
const router = useRouter();
|
82
|
+
const currentPath = router.currentPath;
|
83
|
+
// Find matching route
|
84
|
+
const matchedRoute = findMatchingRoute(routes, currentPath);
|
85
|
+
if (!matchedRoute) {
|
86
|
+
return jsx('div', { children: '404 - Page Not Found' });
|
87
|
+
}
|
88
|
+
return matchedRoute.component({ children: matchedRoute.children });
|
89
|
+
}
|
90
|
+
function findMatchingRoute(routes, path) {
|
91
|
+
for (const route of routes) {
|
92
|
+
const match = matchPath(path, route);
|
93
|
+
if (match) {
|
94
|
+
return {
|
95
|
+
...route,
|
96
|
+
params: match.params
|
97
|
+
};
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return null;
|
101
|
+
}
|
102
|
+
function matchPath(pathname, route) {
|
103
|
+
const { path, exact = true } = route;
|
104
|
+
// Convert route pattern to regex
|
105
|
+
const pattern = path.replace(/:[a-zA-Z0-9_]+/g, '([^/]+)');
|
106
|
+
const regex = new RegExp(`^${pattern}${exact ? '$' : ''}`);
|
107
|
+
const match = pathname.match(regex);
|
108
|
+
if (!match) {
|
109
|
+
return null;
|
110
|
+
}
|
111
|
+
// Extract params
|
112
|
+
const params = {};
|
113
|
+
const paramNames = path.match(/:[a-zA-Z0-9_]+/g) || [];
|
114
|
+
paramNames.forEach((paramName, index) => {
|
115
|
+
params[paramName.substring(1)] = match[index + 1];
|
116
|
+
});
|
117
|
+
return { params };
|
118
|
+
}
|
119
|
+
export function Link({ to, children, ...rest }) {
|
120
|
+
const router = useRouter();
|
121
|
+
const navigate = router.navigate;
|
122
|
+
const handleClick = (e) => {
|
123
|
+
e.preventDefault();
|
124
|
+
navigate(to);
|
125
|
+
};
|
126
|
+
return jsx('a', {
|
127
|
+
href: to,
|
128
|
+
onClick: handleClick,
|
129
|
+
...rest,
|
130
|
+
children
|
131
|
+
});
|
132
|
+
}
|
133
|
+
export function Route({ path, component }) {
|
134
|
+
// This is a configuration component, not actually rendered
|
135
|
+
return null;
|
136
|
+
}
|
137
|
+
export function Switch({ children }) {
|
138
|
+
const router = useRouter();
|
139
|
+
const currentPath = router.currentPath;
|
140
|
+
// Find the first matching route
|
141
|
+
const child = Array.isArray(children)
|
142
|
+
? children.find(child => {
|
143
|
+
if (!child || !child.props)
|
144
|
+
return false;
|
145
|
+
const routeObj = {
|
146
|
+
path: child.props.path,
|
147
|
+
component: child.props.component,
|
148
|
+
exact: child.props.exact
|
149
|
+
};
|
150
|
+
return matchPath(currentPath, routeObj);
|
151
|
+
})
|
152
|
+
: children;
|
153
|
+
return child || null;
|
154
|
+
}
|
155
|
+
export default {
|
156
|
+
RouterProvider,
|
157
|
+
Router,
|
158
|
+
Link,
|
159
|
+
Route,
|
160
|
+
Switch,
|
161
|
+
useRouter,
|
162
|
+
useParams,
|
163
|
+
useNavigate,
|
164
|
+
useLocation
|
165
|
+
};
|
166
|
+
//# sourceMappingURL=router.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/router.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Router } from 'express';
|
2
|
+
import { AuthService } from './auth.js';
|
3
|
+
export declare class ApiRouter {
|
4
|
+
router: Router;
|
5
|
+
private apiDir;
|
6
|
+
private auth;
|
7
|
+
constructor(apiDir: string, auth?: AuthService | null);
|
8
|
+
private setupRoutes;
|
9
|
+
private scanDirectory;
|
10
|
+
private isRouteFile;
|
11
|
+
private getRoutePath;
|
12
|
+
private registerRoute;
|
13
|
+
private isValidRouteModule;
|
14
|
+
private wrapHandler;
|
15
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import express from 'express';
|
2
|
+
import path from 'path';
|
3
|
+
import fs from 'fs';
|
4
|
+
export class ApiRouter {
|
5
|
+
constructor(apiDir, auth = null) {
|
6
|
+
Object.defineProperty(this, "router", {
|
7
|
+
enumerable: true,
|
8
|
+
configurable: true,
|
9
|
+
writable: true,
|
10
|
+
value: void 0
|
11
|
+
});
|
12
|
+
Object.defineProperty(this, "apiDir", {
|
13
|
+
enumerable: true,
|
14
|
+
configurable: true,
|
15
|
+
writable: true,
|
16
|
+
value: void 0
|
17
|
+
});
|
18
|
+
Object.defineProperty(this, "auth", {
|
19
|
+
enumerable: true,
|
20
|
+
configurable: true,
|
21
|
+
writable: true,
|
22
|
+
value: void 0
|
23
|
+
});
|
24
|
+
this.router = express.Router();
|
25
|
+
this.apiDir = path.resolve(process.cwd(), apiDir);
|
26
|
+
this.auth = auth;
|
27
|
+
this.setupRoutes();
|
28
|
+
}
|
29
|
+
setupRoutes() {
|
30
|
+
if (!fs.existsSync(this.apiDir)) {
|
31
|
+
console.log(`API directory not found: ${this.apiDir}`);
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
this.scanDirectory(this.apiDir, '');
|
35
|
+
}
|
36
|
+
scanDirectory(dirPath, routePrefix) {
|
37
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
38
|
+
for (const entry of entries) {
|
39
|
+
const fullPath = path.join(dirPath, entry.name);
|
40
|
+
if (entry.isDirectory()) {
|
41
|
+
// Recursively scan subdirectories
|
42
|
+
this.scanDirectory(fullPath, `${routePrefix}/${entry.name}`);
|
43
|
+
}
|
44
|
+
else if (this.isRouteFile(entry.name)) {
|
45
|
+
// Process route file
|
46
|
+
const routePath = this.getRoutePath(entry.name, routePrefix);
|
47
|
+
this.registerRoute(fullPath, routePath);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
isRouteFile(filename) {
|
52
|
+
return filename.endsWith('.js') ||
|
53
|
+
filename.endsWith('.ts') ||
|
54
|
+
filename.endsWith('.mjs');
|
55
|
+
}
|
56
|
+
getRoutePath(filename, routePrefix) {
|
57
|
+
// Remove extension and handle special names
|
58
|
+
const baseName = path.basename(filename, path.extname(filename));
|
59
|
+
if (baseName === 'index') {
|
60
|
+
return routePrefix || '/';
|
61
|
+
}
|
62
|
+
// Handle dynamic routes [param]
|
63
|
+
const paramMatch = baseName.match(/^\[(.+)\]$/);
|
64
|
+
if (paramMatch) {
|
65
|
+
return `${routePrefix}/:${paramMatch[1]}`;
|
66
|
+
}
|
67
|
+
return `${routePrefix}/${baseName}`;
|
68
|
+
}
|
69
|
+
async registerRoute(filePath, routePath) {
|
70
|
+
try {
|
71
|
+
// Dynamic import the route file
|
72
|
+
const routeModule = await import(filePath);
|
73
|
+
if (!this.isValidRouteModule(routeModule)) {
|
74
|
+
console.warn(`Invalid route module: ${filePath}`);
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
console.log(`Registering API route: ${routePath}`);
|
78
|
+
// Register middleware if any
|
79
|
+
const middleware = routeModule.middleware || [];
|
80
|
+
// Register HTTP methods
|
81
|
+
for (const method of ['get', 'post', 'put', 'delete', 'patch', 'options']) {
|
82
|
+
const handler = routeModule[method];
|
83
|
+
if (typeof handler === 'function') {
|
84
|
+
const routerMethod = this.router[method];
|
85
|
+
routerMethod(routePath, ...middleware, this.wrapHandler(handler));
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
catch (error) {
|
90
|
+
console.error(`Error registering route (${filePath}):`, error);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
isValidRouteModule(module) {
|
94
|
+
if (!module)
|
95
|
+
return false;
|
96
|
+
// Check if at least one HTTP method handler is defined
|
97
|
+
return ['get', 'post', 'put', 'delete', 'patch', 'options']
|
98
|
+
.some(method => typeof module[method] === 'function');
|
99
|
+
}
|
100
|
+
wrapHandler(handler) {
|
101
|
+
return async (req, res, next) => {
|
102
|
+
try {
|
103
|
+
await handler(req, res, next);
|
104
|
+
}
|
105
|
+
catch (error) {
|
106
|
+
next(error);
|
107
|
+
}
|
108
|
+
};
|
109
|
+
}
|
110
|
+
}
|
111
|
+
//# sourceMappingURL=api-router.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"api-router.js","sourceRoot":"","sources":["../../../../src/server/api-router.ts"],"names":[],"mappings":"AAAA,OAAO,OAAoD,MAAM,SAAS,CAAC;AAC3E,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAmBpB,MAAM,OAAO,SAAS;IAKpB,YAAY,MAAc,EAAE,OAA2B,IAAI;QAJpD;;;;;WAAe;QACd;;;;;WAAe;QACf;;;;;WAAyB;QAG/B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACvD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtC,CAAC;IAEO,aAAa,CAAC,OAAe,EAAE,WAAmB;QACxD,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAEhD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,kCAAkC;gBAClC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,WAAW,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC/D,CAAC;iBAAM,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxC,qBAAqB;gBACrB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;gBAC7D,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,QAAgB;QAClC,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxB,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAEO,YAAY,CAAC,QAAgB,EAAE,WAAmB;QACxD,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEjE,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,OAAO,WAAW,IAAI,GAAG,CAAC;QAC5B,CAAC;QAED,gCAAgC;QAChC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAChD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,GAAG,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,CAAC;QAED,OAAO,GAAG,WAAW,IAAI,QAAQ,EAAE,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,SAAiB;QAC7D,IAAI,CAAC;YACH,gCAAgC;YAChC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YAE3C,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAC;YAEnD,6BAA6B;YAC7B,MAAM,UAAU,GAAG,WAAW,CAAC,UAAU,IAAI,EAAE,CAAC;YAEhD,wBAAwB;YACxB,KAAK,MAAM,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;gBAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;gBACpC,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;oBAClC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,MAAsB,CAAQ,CAAC;oBAChE,YAAY,CACV,SAAS,EACT,GAAG,UAAU,EACb,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAC1B,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,QAAQ,IAAI,EAAE,KAAK,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAEO,kBAAkB,CAAC,MAAW;QACpC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAE1B,uDAAuD;QACvD,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC;aACxD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,CAAC;IAC1D,CAAC;IAEO,WAAW,CAAC,OAAqB;QACvC,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;YAC/D,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;CACF"}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { SignOptions } from 'jsonwebtoken';
|
2
|
+
import { Request, Response, NextFunction } from 'express';
|
3
|
+
export interface AuthConfig {
|
4
|
+
secret: string;
|
5
|
+
expiresIn?: SignOptions['expiresIn'];
|
6
|
+
}
|
7
|
+
export interface User {
|
8
|
+
id: string | number;
|
9
|
+
username: string;
|
10
|
+
password?: string;
|
11
|
+
email?: string;
|
12
|
+
roles?: string[];
|
13
|
+
[key: string]: any;
|
14
|
+
}
|
15
|
+
export declare class AuthService {
|
16
|
+
private config;
|
17
|
+
constructor(config: AuthConfig);
|
18
|
+
hashPassword(password: string): Promise<string>;
|
19
|
+
comparePasswords(password: string, hashedPassword: string): Promise<boolean>;
|
20
|
+
generateToken(user: Omit<User, 'password'>): string;
|
21
|
+
verifyToken(token: string): any;
|
22
|
+
initialize(): (req: Request & {
|
23
|
+
user?: any;
|
24
|
+
}, res: Response, next: NextFunction) => void;
|
25
|
+
requireAuth(): (req: Request & {
|
26
|
+
user?: any;
|
27
|
+
}, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
28
|
+
requireRoles(roles: string[]): (req: Request & {
|
29
|
+
user?: any;
|
30
|
+
}, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
31
|
+
private extractToken;
|
32
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
2
|
+
import bcrypt from 'bcryptjs';
|
3
|
+
export class AuthService {
|
4
|
+
constructor(config) {
|
5
|
+
Object.defineProperty(this, "config", {
|
6
|
+
enumerable: true,
|
7
|
+
configurable: true,
|
8
|
+
writable: true,
|
9
|
+
value: void 0
|
10
|
+
});
|
11
|
+
this.config = {
|
12
|
+
expiresIn: '24h',
|
13
|
+
...config
|
14
|
+
};
|
15
|
+
}
|
16
|
+
async hashPassword(password) {
|
17
|
+
return bcrypt.hash(password, 10);
|
18
|
+
}
|
19
|
+
async comparePasswords(password, hashedPassword) {
|
20
|
+
return bcrypt.compare(password, hashedPassword);
|
21
|
+
}
|
22
|
+
generateToken(user) {
|
23
|
+
const options = {};
|
24
|
+
if (this.config.expiresIn) {
|
25
|
+
options.expiresIn = this.config.expiresIn;
|
26
|
+
}
|
27
|
+
return jwt.sign({ id: user.id, username: user.username, roles: user.roles || [] }, this.config.secret, options);
|
28
|
+
}
|
29
|
+
verifyToken(token) {
|
30
|
+
try {
|
31
|
+
return jwt.verify(token, this.config.secret);
|
32
|
+
}
|
33
|
+
catch (error) {
|
34
|
+
return null;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
// Express middleware for authentication
|
38
|
+
initialize() {
|
39
|
+
return (req, res, next) => {
|
40
|
+
const token = this.extractToken(req);
|
41
|
+
if (token) {
|
42
|
+
const decoded = this.verifyToken(token);
|
43
|
+
if (decoded) {
|
44
|
+
req.user = decoded;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
next();
|
48
|
+
};
|
49
|
+
}
|
50
|
+
// Express middleware for requiring authentication
|
51
|
+
requireAuth() {
|
52
|
+
return (req, res, next) => {
|
53
|
+
if (!req.user) {
|
54
|
+
return res.status(401).json({ message: 'Unauthorized' });
|
55
|
+
}
|
56
|
+
return next();
|
57
|
+
};
|
58
|
+
}
|
59
|
+
// Express middleware for requiring specific roles
|
60
|
+
requireRoles(roles) {
|
61
|
+
return (req, res, next) => {
|
62
|
+
if (!req.user) {
|
63
|
+
return res.status(401).json({ message: 'Unauthorized' });
|
64
|
+
}
|
65
|
+
const userRoles = req.user.roles || [];
|
66
|
+
const hasRequiredRole = roles.some(role => userRoles.includes(role));
|
67
|
+
if (!hasRequiredRole) {
|
68
|
+
return res.status(403).json({ message: 'Forbidden' });
|
69
|
+
}
|
70
|
+
return next();
|
71
|
+
};
|
72
|
+
}
|
73
|
+
extractToken(req) {
|
74
|
+
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
|
75
|
+
return req.headers.authorization.substring(7);
|
76
|
+
}
|
77
|
+
return null;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
//# sourceMappingURL=auth.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/server/auth.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Db } from 'mongodb';
|
2
|
+
import mysql from 'mysql2/promise';
|
3
|
+
import pg from 'pg';
|
4
|
+
export interface DbConfig {
|
5
|
+
url: string;
|
6
|
+
type: 'mongodb' | 'mysql' | 'postgres';
|
7
|
+
}
|
8
|
+
export declare class Database {
|
9
|
+
private config;
|
10
|
+
private mongoClient;
|
11
|
+
private mongoDb;
|
12
|
+
private mysqlPool;
|
13
|
+
private pgPool;
|
14
|
+
constructor(config: DbConfig);
|
15
|
+
connect(): Promise<void>;
|
16
|
+
private connectMongo;
|
17
|
+
private connectMysql;
|
18
|
+
private connectPostgres;
|
19
|
+
disconnect(): Promise<void>;
|
20
|
+
getMongoDb(): Db | null;
|
21
|
+
getMysqlPool(): mysql.Pool | null;
|
22
|
+
getPgPool(): pg.Pool | null;
|
23
|
+
query(sql: string, values?: any[]): Promise<any>;
|
24
|
+
}
|
@@ -0,0 +1,135 @@
|
|
1
|
+
import { MongoClient } from 'mongodb';
|
2
|
+
import mysql from 'mysql2/promise';
|
3
|
+
import pg from 'pg';
|
4
|
+
export class Database {
|
5
|
+
constructor(config) {
|
6
|
+
Object.defineProperty(this, "config", {
|
7
|
+
enumerable: true,
|
8
|
+
configurable: true,
|
9
|
+
writable: true,
|
10
|
+
value: void 0
|
11
|
+
});
|
12
|
+
Object.defineProperty(this, "mongoClient", {
|
13
|
+
enumerable: true,
|
14
|
+
configurable: true,
|
15
|
+
writable: true,
|
16
|
+
value: null
|
17
|
+
});
|
18
|
+
Object.defineProperty(this, "mongoDb", {
|
19
|
+
enumerable: true,
|
20
|
+
configurable: true,
|
21
|
+
writable: true,
|
22
|
+
value: null
|
23
|
+
});
|
24
|
+
Object.defineProperty(this, "mysqlPool", {
|
25
|
+
enumerable: true,
|
26
|
+
configurable: true,
|
27
|
+
writable: true,
|
28
|
+
value: null
|
29
|
+
});
|
30
|
+
Object.defineProperty(this, "pgPool", {
|
31
|
+
enumerable: true,
|
32
|
+
configurable: true,
|
33
|
+
writable: true,
|
34
|
+
value: null
|
35
|
+
});
|
36
|
+
this.config = config;
|
37
|
+
}
|
38
|
+
async connect() {
|
39
|
+
switch (this.config.type) {
|
40
|
+
case 'mongodb':
|
41
|
+
await this.connectMongo();
|
42
|
+
break;
|
43
|
+
case 'mysql':
|
44
|
+
await this.connectMysql();
|
45
|
+
break;
|
46
|
+
case 'postgres':
|
47
|
+
await this.connectPostgres();
|
48
|
+
break;
|
49
|
+
default:
|
50
|
+
throw new Error(`Unsupported database type: ${this.config.type}`);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
async connectMongo() {
|
54
|
+
try {
|
55
|
+
this.mongoClient = new MongoClient(this.config.url);
|
56
|
+
await this.mongoClient.connect();
|
57
|
+
this.mongoDb = this.mongoClient.db();
|
58
|
+
console.log('Connected to MongoDB');
|
59
|
+
}
|
60
|
+
catch (error) {
|
61
|
+
console.error('MongoDB connection error:', error);
|
62
|
+
throw error;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
async connectMysql() {
|
66
|
+
try {
|
67
|
+
this.mysqlPool = mysql.createPool(this.config.url);
|
68
|
+
// Test connection
|
69
|
+
await this.mysqlPool.getConnection();
|
70
|
+
console.log('Connected to MySQL');
|
71
|
+
}
|
72
|
+
catch (error) {
|
73
|
+
console.error('MySQL connection error:', error);
|
74
|
+
throw error;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
async connectPostgres() {
|
78
|
+
try {
|
79
|
+
this.pgPool = new pg.Pool({ connectionString: this.config.url });
|
80
|
+
// Test connection
|
81
|
+
const client = await this.pgPool.connect();
|
82
|
+
client.release();
|
83
|
+
console.log('Connected to PostgreSQL');
|
84
|
+
}
|
85
|
+
catch (error) {
|
86
|
+
console.error('PostgreSQL connection error:', error);
|
87
|
+
throw error;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
async disconnect() {
|
91
|
+
if (this.mongoClient) {
|
92
|
+
await this.mongoClient.close();
|
93
|
+
this.mongoClient = null;
|
94
|
+
this.mongoDb = null;
|
95
|
+
}
|
96
|
+
if (this.mysqlPool) {
|
97
|
+
await this.mysqlPool.end();
|
98
|
+
this.mysqlPool = null;
|
99
|
+
}
|
100
|
+
if (this.pgPool) {
|
101
|
+
await this.pgPool.end();
|
102
|
+
this.pgPool = null;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
// Database-specific methods
|
106
|
+
getMongoDb() {
|
107
|
+
return this.mongoDb;
|
108
|
+
}
|
109
|
+
getMysqlPool() {
|
110
|
+
return this.mysqlPool;
|
111
|
+
}
|
112
|
+
getPgPool() {
|
113
|
+
return this.pgPool;
|
114
|
+
}
|
115
|
+
// Generic query method
|
116
|
+
async query(sql, values) {
|
117
|
+
switch (this.config.type) {
|
118
|
+
case 'mongodb':
|
119
|
+
throw new Error('For MongoDB, use getMongoDb() instead of query()');
|
120
|
+
case 'mysql':
|
121
|
+
if (!this.mysqlPool)
|
122
|
+
throw new Error('MySQL not connected');
|
123
|
+
const [rows] = await this.mysqlPool.execute(sql, values || []);
|
124
|
+
return rows;
|
125
|
+
case 'postgres':
|
126
|
+
if (!this.pgPool)
|
127
|
+
throw new Error('PostgreSQL not connected');
|
128
|
+
const result = await this.pgPool.query(sql, values || []);
|
129
|
+
return result.rows;
|
130
|
+
default:
|
131
|
+
throw new Error(`Unsupported database type: ${this.config.type}`);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
//# sourceMappingURL=database.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../../../src/server/database.ts"],"names":[],"mappings":"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"}
|