rasengan 1.0.0-beta.1

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.
Files changed (118) hide show
  1. package/LICENSE +21 -0
  2. package/lib/cli/dirname.d.ts +2 -0
  3. package/lib/cli/dirname.js +6 -0
  4. package/lib/cli/dirname.js.map +1 -0
  5. package/lib/cli/index.d.ts +2 -0
  6. package/lib/cli/index.js +101 -0
  7. package/lib/cli/index.js.map +1 -0
  8. package/lib/config/index.d.ts +39 -0
  9. package/lib/config/index.js +57 -0
  10. package/lib/config/index.js.map +1 -0
  11. package/lib/config/type.d.ts +68 -0
  12. package/lib/config/type.js +2 -0
  13. package/lib/config/type.js.map +1 -0
  14. package/lib/core/components/index.d.ts +26 -0
  15. package/lib/core/components/index.js +72 -0
  16. package/lib/core/components/index.js.map +1 -0
  17. package/lib/core/index.d.ts +2 -0
  18. package/lib/core/index.js +2 -0
  19. package/lib/core/index.js.map +1 -0
  20. package/lib/core/interfaces.d.ts +76 -0
  21. package/lib/core/interfaces.js +91 -0
  22. package/lib/core/interfaces.js.map +1 -0
  23. package/lib/core/types.d.ts +45 -0
  24. package/lib/core/types.js +2 -0
  25. package/lib/core/types.js.map +1 -0
  26. package/lib/decorators/index.d.ts +2 -0
  27. package/lib/decorators/index.js +3 -0
  28. package/lib/decorators/index.js.map +1 -0
  29. package/lib/decorators/route.d.ts +7 -0
  30. package/lib/decorators/route.js +25 -0
  31. package/lib/decorators/route.js.map +1 -0
  32. package/lib/decorators/router.d.ts +7 -0
  33. package/lib/decorators/router.js +24 -0
  34. package/lib/decorators/router.js.map +1 -0
  35. package/lib/decorators/types.d.ts +47 -0
  36. package/lib/decorators/types.js +2 -0
  37. package/lib/decorators/types.js.map +1 -0
  38. package/lib/entries/entry-client.d.ts +1 -0
  39. package/lib/entries/entry-client.js +15 -0
  40. package/lib/entries/entry-client.js.map +1 -0
  41. package/lib/entries/entry-server.d.ts +6 -0
  42. package/lib/entries/entry-server.js +20 -0
  43. package/lib/entries/entry-server.js.map +1 -0
  44. package/lib/hooks/index.d.ts +0 -0
  45. package/lib/hooks/index.js +1 -0
  46. package/lib/hooks/index.js.map +1 -0
  47. package/lib/index.d.ts +6 -0
  48. package/lib/index.js +10 -0
  49. package/lib/index.js.map +1 -0
  50. package/lib/routing/components/index.d.ts +32 -0
  51. package/lib/routing/components/index.js +69 -0
  52. package/lib/routing/components/index.js.map +1 -0
  53. package/lib/routing/index.d.ts +3 -0
  54. package/lib/routing/index.js +4 -0
  55. package/lib/routing/index.js.map +1 -0
  56. package/lib/routing/interfaces.d.ts +67 -0
  57. package/lib/routing/interfaces.js +88 -0
  58. package/lib/routing/interfaces.js.map +1 -0
  59. package/lib/routing/types.d.ts +4 -0
  60. package/lib/routing/types.js +2 -0
  61. package/lib/routing/types.js.map +1 -0
  62. package/lib/routing/utils/index.d.ts +40 -0
  63. package/lib/routing/utils/index.js +256 -0
  64. package/lib/routing/utils/index.js.map +1 -0
  65. package/lib/server/functions/vercel/api/index.d.ts +2 -0
  66. package/lib/server/functions/vercel/api/index.js +91 -0
  67. package/lib/server/functions/vercel/api/index.js.map +1 -0
  68. package/lib/server/functions/vercel/vercel.json +12 -0
  69. package/lib/server/utils/createFetchRequest.d.ts +5 -0
  70. package/lib/server/utils/createFetchRequest.js +34 -0
  71. package/lib/server/utils/createFetchRequest.js.map +1 -0
  72. package/lib/server/utils/getIp.d.ts +1 -0
  73. package/lib/server/utils/getIp.js +30 -0
  74. package/lib/server/utils/getIp.js.map +1 -0
  75. package/lib/server/utils/handleError.d.ts +2 -0
  76. package/lib/server/utils/handleError.js +28 -0
  77. package/lib/server/utils/handleError.js.map +1 -0
  78. package/lib/server/utils/index.d.ts +5 -0
  79. package/lib/server/utils/index.js +8 -0
  80. package/lib/server/utils/index.js.map +1 -0
  81. package/lib/server/utils/log.d.ts +6 -0
  82. package/lib/server/utils/log.js +69 -0
  83. package/lib/server/utils/log.js.map +1 -0
  84. package/package.json +75 -0
  85. package/server.js +229 -0
  86. package/src/cli/dirname.ts +7 -0
  87. package/src/cli/index.ts +134 -0
  88. package/src/config/index.ts +67 -0
  89. package/src/config/type.ts +76 -0
  90. package/src/core/components/index.tsx +111 -0
  91. package/src/core/index.ts +14 -0
  92. package/src/core/interfaces.tsx +129 -0
  93. package/src/core/types.ts +43 -0
  94. package/src/decorators/index.ts +2 -0
  95. package/src/decorators/route.ts +32 -0
  96. package/src/decorators/router.ts +30 -0
  97. package/src/decorators/types.ts +54 -0
  98. package/src/entries/entry-client.tsx +33 -0
  99. package/src/entries/entry-server.tsx +50 -0
  100. package/src/hooks/index.ts +0 -0
  101. package/src/index.ts +11 -0
  102. package/src/routing/components/index.tsx +125 -0
  103. package/src/routing/index.ts +23 -0
  104. package/src/routing/interfaces.ts +105 -0
  105. package/src/routing/types.ts +3 -0
  106. package/src/routing/utils/index.tsx +342 -0
  107. package/src/server/functions/vercel/api/index.ts +122 -0
  108. package/src/server/functions/vercel/vercel.json +12 -0
  109. package/src/server/utils/createFetchRequest.ts +40 -0
  110. package/src/server/utils/getIp.ts +37 -0
  111. package/src/server/utils/handleError.ts +36 -0
  112. package/src/server/utils/index.ts +15 -0
  113. package/src/server/utils/log.ts +115 -0
  114. package/src/vite-env.d.ts +1 -0
  115. package/tsconfig.json +30 -0
  116. package/tsconfig.lib.json +41 -0
  117. package/tsconfig.node.json +11 -0
  118. package/vite.config.ts +45 -0
@@ -0,0 +1,342 @@
1
+ import { RouterComponent } from "../interfaces.js";
2
+ import { RouterProvider, createBrowserRouter } from "react-router-dom";
3
+ import {
4
+ RouteDecoratorProps,
5
+ RouteLayoutDecoratorProps,
6
+ RouterDecoratorProps,
7
+ } from "../../decorators/types.js";
8
+ import { DefaultLayout, LayoutComponent, PageComponent } from "../../index.js";
9
+ import {
10
+ ClientComponent,
11
+ NotFoundComponentContainer,
12
+ NotFoundPageComponent,
13
+ ServerComponent,
14
+ } from "../components/index.js";
15
+ import { RouteErrorBoundary as ErrorBoundary } from "../../core/components/index.js";
16
+
17
+ /**
18
+ * This function receives a router component and get a formated router first
19
+ * and then return a router.
20
+ */
21
+ export const getRouter = (router: RouterComponent) => {
22
+ const routes = generateBrowserRoutes(router);
23
+
24
+ let Router = createBrowserRouter(routes);
25
+
26
+ return () => (
27
+ <RouterProvider fallbackElement={<>Not Found</>} router={Router} />
28
+ );
29
+ };
30
+
31
+ /**
32
+ * This function receives a router component and return a formated router.
33
+ */
34
+ const generateBrowserRoutes = (router: RouterComponent, isRoot = true) => {
35
+ // Initialization of the list of routes
36
+ const routes = [] as any;
37
+
38
+ // Get information about the layout and the path
39
+ const layout = router.layout;
40
+ const LayoutToRender = layout.render;
41
+
42
+ const route = {
43
+ path: layout.path,
44
+ elementError: <ErrorBoundary />,
45
+ element: <LayoutToRender />,
46
+ children: [] as unknown as any,
47
+ };
48
+
49
+ // Defining the page not found route
50
+ if (isRoot) {
51
+ routes.push({
52
+ path: "*",
53
+ element: (
54
+ <NotFoundComponentContainer content={router.notFoundComponent} />
55
+ ),
56
+ });
57
+ }
58
+
59
+ // Get informations about pages
60
+ const pages = router.pages.map((page) => {
61
+ // Get the path of the page
62
+ const path = page.path === "/" ? layout.path : page.path;
63
+
64
+ return {
65
+ path,
66
+ loader: async ({ params, request }: any) => {
67
+ // Get the response from the loader
68
+ const response = await page.loader({ params, request });
69
+
70
+ // Handle redirection
71
+ if (response.redirect) {
72
+ const formData = new FormData();
73
+
74
+ formData.append("redirect", response.redirect);
75
+
76
+ return new Response(formData, {
77
+ status: 302,
78
+ headers: {
79
+ Location: response.redirect,
80
+ },
81
+ });
82
+ }
83
+
84
+ return response;
85
+ },
86
+ element: (
87
+ <ClientComponent page={page} loader={router.loaderComponent({})} />
88
+ ),
89
+ elementError: <ErrorBoundary />,
90
+ };
91
+ });
92
+
93
+ // Add pages into children of the current route
94
+ pages.forEach((page) => {
95
+ route.children.push(page);
96
+ });
97
+
98
+ // Loop throug sub routers in order to apply the same thing.
99
+ // for (const SubRouter of router.routers) {
100
+ // const subRouter = new SubRouter();
101
+
102
+ // const subRoutes = generateBrowserRoutes(subRouter);
103
+
104
+ // // Add sub routes into the lists of route
105
+ // route.children.push(subRoutes);
106
+ // }
107
+
108
+ routes.push(route);
109
+
110
+ // Loop throug besides routers in order to apply the same thing.
111
+ for (const besideRouter of router.routers) {
112
+ const besidesRoutes = generateBrowserRoutes(besideRouter, false);
113
+
114
+ // Add besides routes into the lists of route
115
+ routes.push(...besidesRoutes);
116
+ }
117
+
118
+ // Return the formated router
119
+ return routes;
120
+ };
121
+
122
+ /**
123
+ * This function receives a router component and return a formated router for static routing
124
+ * @param router Represents the router component
125
+ * @returns
126
+ */
127
+ export const generateStaticRoutes = (
128
+ router: RouterComponent,
129
+ isRoot = true
130
+ ) => {
131
+ // Initialization of the list of routes
132
+ const routes = [] as any;
133
+
134
+ // Get information about the layout and the path
135
+ const layout = router.layout;
136
+ const LayoutToRender = layout.render;
137
+
138
+ const route = {
139
+ path: layout.path,
140
+ elementError: <ErrorBoundary />,
141
+ element: <LayoutToRender />,
142
+ children: [] as unknown as any,
143
+ };
144
+
145
+ // Defining the page not found route
146
+ if (isRoot) {
147
+ routes.push({
148
+ path: "*",
149
+ element: (
150
+ <NotFoundComponentContainer content={router.notFoundComponent} />
151
+ ),
152
+ });
153
+ }
154
+
155
+ // Get informations about pages
156
+ const pages = router.pages.map((page) => {
157
+ // Get the path of the page
158
+ const path = page.path === "/" ? layout.path : page.path;
159
+
160
+ return {
161
+ path,
162
+ async loader({ params, request }: any) {
163
+ // Get the response from the loader
164
+ const response = await page.loader({ params, request });
165
+
166
+ // Handle redirection
167
+ if (response.redirect) {
168
+ const formData = new FormData();
169
+
170
+ formData.append("redirect", response.redirect);
171
+
172
+ return new Response(formData, {
173
+ status: 302,
174
+ headers: {
175
+ Location: response.redirect,
176
+ },
177
+ });
178
+ }
179
+
180
+ return response;
181
+ },
182
+ Component() {
183
+ return (
184
+ <ServerComponent page={page} loader={router.loaderComponent({})} />
185
+ );
186
+ },
187
+ elementError: <ErrorBoundary />,
188
+ };
189
+ });
190
+
191
+ // Add pages into children of the current route
192
+ pages.forEach((page) => {
193
+ route.children.push(page);
194
+ });
195
+
196
+ // Loop throug sub routers in order to apply the same thing.
197
+ // for (const SubRouter of router.routers) {
198
+ // const subRouter = new SubRouter();
199
+ // const subRoutes = generateStaticRoutes(subRouter);
200
+
201
+ // // Add sub routes into the lists of route
202
+ // route.children.push(subRoutes);
203
+ // }
204
+
205
+ routes.push(route);
206
+
207
+ // Loop throug besides routers in order to apply the same thing.
208
+ for (const besideRouter of router.routers) {
209
+ const besidesRoutes = generateStaticRoutes(besideRouter, false);
210
+
211
+ // Add besides routes into the lists of route
212
+ routes.push(...besidesRoutes);
213
+ }
214
+
215
+ // Return the formated router
216
+ return routes;
217
+ };
218
+
219
+ /**
220
+ * This function receives a router component and extract all metadatas of all pages
221
+ * and put all of them inside a map function in order to be used to enhance ssr
222
+ */
223
+ export const extractPageMetadata = (router: RouterComponent) => {
224
+ // Initialisation of the Map of metadata
225
+ const metadatas = new Map<string, { title: string; description: string }>();
226
+
227
+ // Get base url
228
+ const baseURL = router.layout.path;
229
+
230
+ // Get informations about pages of the main router
231
+ router.pages.forEach((page) => {
232
+ // Add the first slash if not exists from the page path
233
+ const pagePath = page.path[0] === "/" ? page.path : "/" + page.path;
234
+
235
+ // Remove the last slash if exists from the base url
236
+ const finalBaseURL =
237
+ baseURL === "/"
238
+ ? baseURL
239
+ : baseURL[baseURL.length - 1] === "/"
240
+ ? baseURL.slice(0, -1)
241
+ : baseURL;
242
+
243
+ // Get the path of the page
244
+ const path =
245
+ pagePath === "/"
246
+ ? finalBaseURL
247
+ : finalBaseURL === "/"
248
+ ? pagePath
249
+ : finalBaseURL + "/" + pagePath;
250
+
251
+ // Add metadata
252
+ metadatas.set(path, {
253
+ title: page.title,
254
+ description: page.description,
255
+ });
256
+ });
257
+
258
+ // Loop through the others routers recursively
259
+ for (let besidesRouter of router.routers) {
260
+ const data = extractPageMetadata(besidesRouter);
261
+
262
+ // Copy metadata from data to metadatas map
263
+ data.forEach((value, key) => {
264
+ metadatas.set(key, value);
265
+ });
266
+ }
267
+
268
+ return metadatas;
269
+ };
270
+
271
+ /**
272
+ * This function adds metadata to a page or a layout
273
+ * @param option
274
+ * @returns
275
+ */
276
+ export const defineRoutePage = (option: RouteDecoratorProps) => {
277
+ const { path, title, description } = option;
278
+
279
+ return (Component: new () => PageComponent) => {
280
+ if (!path) throw new Error("You must provide a path to the page");
281
+
282
+ // Create a new instance of the component
283
+ const component = new Component();
284
+
285
+ // Set properties
286
+ component.path = path;
287
+ component.title = title || Component.name;
288
+ component.description = description || "";
289
+
290
+ return component;
291
+ };
292
+ };
293
+
294
+ /**
295
+ * This function adds metadata to a page or a layout
296
+ * @param option
297
+ * @returns
298
+ */
299
+ export const defineRouteLayout = (option: RouteLayoutDecoratorProps) => {
300
+ const { path } = option;
301
+
302
+ return (Component: new () => LayoutComponent) => {
303
+ if (!path) throw new Error("You must provide a path to the layout");
304
+
305
+ // Create a new instance of the component
306
+ const component = new Component();
307
+
308
+ // Set properties
309
+ component.path = path;
310
+
311
+ return component;
312
+ };
313
+ };
314
+
315
+ /**
316
+ * This function adds metadata to a router
317
+ * @param option
318
+ * @returns
319
+ */
320
+ export const defineRouter = (option: RouterDecoratorProps) => {
321
+ const { imports, layout, pages, loaderComponent, notFoundComponent } = option;
322
+
323
+ return (Component: new () => RouterComponent) => {
324
+ // Handle errors
325
+ if (!option.pages)
326
+ throw new Error(
327
+ "You must provide a list of pages in the router decorator"
328
+ );
329
+
330
+ // Create router
331
+ const router = new Component();
332
+
333
+ // Set properties
334
+ router.routers = imports || [];
335
+ router.layout = layout || new DefaultLayout();
336
+ router.pages = pages;
337
+ router.loaderComponent = loaderComponent || (() => null);
338
+ router.notFoundComponent = notFoundComponent || NotFoundPageComponent;
339
+
340
+ return router;
341
+ };
342
+ };
@@ -0,0 +1,122 @@
1
+ import fs from "node:fs/promises";
2
+ import path, { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ import type { VercelRequest, VercelResponse } from "@vercel/node";
5
+ import {
6
+ StaticHandlerContext,
7
+ createStaticHandler,
8
+ createStaticRouter,
9
+ } from "react-router-dom/server.js";
10
+ // @ts-ignore
11
+ import { createFetchRequest } from "rasengan";
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+
16
+ // Create server for production only
17
+ export default async function handler(req: VercelRequest, res: VercelResponse) {
18
+ try {
19
+ // Get URL
20
+ const url = req.url;
21
+ const host = req.headers.host;
22
+
23
+ // Get app path
24
+ const appPath = join(__dirname, "..");
25
+
26
+ // ! Favicon Fix
27
+ if (url === "/favicon.ico") {
28
+ return res.send(path.resolve(join(appPath, "dist/client/rasengan.png")));
29
+ }
30
+
31
+ // ! Robots Fix
32
+ if (url === "/robots.txt") {
33
+ return res.send(`
34
+ user-agent: *
35
+ disallow: /downloads/
36
+ disallow: /private/
37
+ allow: /
38
+
39
+ user-agent: magicsearchbot
40
+ disallow: /uploads/
41
+ `);
42
+ }
43
+
44
+ // ! Sitemap Fix
45
+ if (url === "/sitemap.xml") {
46
+ return res.send(path.resolve(join(appPath, "dist/client/sitemap.xml")));
47
+ }
48
+
49
+ // ! Manifest Fix
50
+ if (url === "/manifest.json") {
51
+ return res.send(path.resolve(join(appPath, "dist/client/manifest.json")));
52
+ }
53
+
54
+ let template;
55
+ let entry;
56
+ let manifest;
57
+
58
+ // Always read fresh template in development
59
+ const htmlFilePath = join(appPath, "dist/client/index.html");
60
+ const serverFilePath = join(appPath, "dist/server/entry-server.js");
61
+ const ssrManifestFilePath = join(
62
+ appPath,
63
+ "dist/client/.vite/ssr-manifest.json"
64
+ );
65
+
66
+ // Read template, server-renderer and manifest in production
67
+ template = await fs.readFile(htmlFilePath, "utf-8");
68
+ entry = await import(serverFilePath);
69
+ manifest = await fs.readFile(ssrManifestFilePath, "utf-8");
70
+
71
+ // Extract render and staticRoutes from entry
72
+ const { render, staticRoutes } = entry;
73
+
74
+ // Create static handler
75
+ let handler = createStaticHandler(staticRoutes);
76
+
77
+ // Create fetch request for static routing
78
+ let fetchRequest = createFetchRequest(req, host);
79
+ let context = await handler.query(fetchRequest);
80
+
81
+ // Handle redirects
82
+ const status = (context as Response).status;
83
+
84
+ if (status === 302) {
85
+ const redirect = (context as Response).headers.get("Location");
86
+
87
+ if (redirect) return res.redirect(redirect);
88
+ }
89
+
90
+ // Helmet context
91
+ const helmetContext = {} as { helmet: any };
92
+
93
+ // Create static router
94
+ let router = createStaticRouter(
95
+ handler.dataRoutes,
96
+ context as StaticHandlerContext
97
+ );
98
+
99
+ const rendered = await render(router, context, helmetContext);
100
+
101
+ // Get metadata
102
+ const helmet = helmetContext.helmet;
103
+
104
+ let head = `
105
+ ${helmet.title.toString()}
106
+ ${helmet.meta.toString()}
107
+ `;
108
+
109
+ let html = template
110
+ .replace(`<!--app-head-->`, head ?? "")
111
+ .replace(`<!--app-html-->`, rendered.html ?? "");
112
+
113
+ res
114
+ .status(200)
115
+ .setHeader("Content-Type", "text/html")
116
+ .setHeader("Cache-Control", "max-age=31536000")
117
+ .end(html);
118
+ } catch (e: any) {
119
+ console.log(e.stack);
120
+ res.status(500).end(e.stack);
121
+ }
122
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "routes": [
3
+ {
4
+ "src": "/assets/(.*)",
5
+ "dest": "client/assets/$1"
6
+ },
7
+ {
8
+ "src": "/(.*)",
9
+ "dest": "api/index.js"
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,40 @@
1
+ import { Request } from "express";
2
+
3
+ /**
4
+ * This function is used to create a fetch request from an express request.
5
+ */
6
+ export default function createFetchRequest(req: Request, host: string) {
7
+ let origin = `${req.protocol}://${host}`;
8
+ // Note: This had to take originalUrl into account for presumably vite's proxying
9
+ let url = new URL(req.originalUrl || req.url, origin);
10
+
11
+ let controller = new AbortController();
12
+ req.on("close", () => controller.abort());
13
+
14
+ let headers = new Headers();
15
+
16
+ for (let [key, values] of Object.entries(req.headers)) {
17
+ if (values) {
18
+ if (Array.isArray(values)) {
19
+ for (let value of values) {
20
+ headers.append(key, value);
21
+ }
22
+ } else {
23
+ headers.set(key, values);
24
+ }
25
+ }
26
+ }
27
+
28
+ let init = {
29
+ method: req.method,
30
+ headers,
31
+ signal: controller.signal,
32
+ body: null,
33
+ };
34
+
35
+ if (req.method !== "GET" && req.method !== "HEAD") {
36
+ init.body = req.body;
37
+ }
38
+
39
+ return new Request(url.href, init);
40
+ }
@@ -0,0 +1,37 @@
1
+ import os from "node:os";
2
+
3
+ // Get local IP
4
+ export default function getIP() {
5
+ // Get network interfaces
6
+ const networkInterfaces = os.networkInterfaces();
7
+
8
+ // Find the IPv4 address for the default network interface
9
+ let ipAddress = "";
10
+
11
+ // Loop through the network interfaces
12
+ for (const interfaceName in networkInterfaces) {
13
+ // Get the network interface
14
+ const iface = networkInterfaces[interfaceName];
15
+
16
+ // Skip when there is no network interface
17
+ if (!iface) {
18
+ continue;
19
+ }
20
+
21
+ // Loop through the interface addresses
22
+ for (let i = 0; i < iface.length; i++) {
23
+ const alias = iface[i];
24
+
25
+ if (alias.family === "IPv4" && !alias.internal) {
26
+ ipAddress = alias.address;
27
+ break;
28
+ }
29
+ }
30
+
31
+ if (ipAddress) {
32
+ break;
33
+ }
34
+ }
35
+
36
+ return ipAddress;
37
+ }
@@ -0,0 +1,36 @@
1
+ import path, { join } from "node:path";
2
+ import { Response } from "express";
3
+
4
+ export function fix404(url: string, res: Response, appPath: string) {
5
+ // ! Favicon Fix
6
+ if (url === "/favicon.ico") {
7
+ return res.sendFile(
8
+ path.resolve(join(appPath, "dist/client/rasengan.png"))
9
+ );
10
+ }
11
+
12
+ // ! Robots Fix
13
+ if (url === "/robots.txt") {
14
+ return res.send(`
15
+ user-agent: *
16
+ disallow: /downloads/
17
+ disallow: /private/
18
+ allow: /
19
+
20
+ user-agent: magicsearchbot
21
+ disallow: /uploads/
22
+ `);
23
+ }
24
+
25
+ // ! Sitemap Fix
26
+ if (url === "/sitemap.xml") {
27
+ return res.sendFile(path.resolve(join(appPath, "dist/client/sitemap.xml")));
28
+ }
29
+
30
+ // ! Manifest Fix
31
+ if (url === "/manifest.json") {
32
+ return res.sendFile(
33
+ path.resolve(join(appPath, "dist/client/manifest.json"))
34
+ );
35
+ }
36
+ }
@@ -0,0 +1,15 @@
1
+ // Import section
2
+
3
+ import createFetchRequest from "./createFetchRequest.js";
4
+ import getIP from "./getIp.js";
5
+ import { logServerInfo } from "./log.js";
6
+ import { fix404 } from "./handleError.js";
7
+
8
+ // Export section
9
+
10
+ export {
11
+ createFetchRequest,
12
+ getIP,
13
+ logServerInfo,
14
+ fix404,
15
+ }