xpine 0.0.29 → 0.0.31
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/index.js +282 -263
- package/dist/src/context.d.ts +1 -1
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/express.d.ts +1 -0
- package/dist/src/express.d.ts.map +1 -1
- package/dist/src/scripts/build.d.ts.map +1 -1
- package/dist/src/scripts/xpine-build.js +78 -39
- package/dist/src/scripts/xpine-dev.js +83 -44
- package/dist/src/util/regex.d.ts +2 -0
- package/dist/src/util/regex.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/test-results/.last-run.json +4 -0
- package/types.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// src/runDevServer.ts
|
|
2
2
|
import expressWs from "express-ws";
|
|
3
3
|
import http from "http";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import express2 from "express";
|
|
5
|
+
import EventEmitter2 from "events";
|
|
6
6
|
import chokidar from "chokidar";
|
|
7
7
|
|
|
8
8
|
// src/scripts/build.ts
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import path6 from "path";
|
|
10
|
+
import fs6 from "fs-extra";
|
|
11
11
|
import { build } from "esbuild";
|
|
12
12
|
|
|
13
13
|
// src/build/typescript-builder.ts
|
|
@@ -121,10 +121,12 @@ function createContext(value) {
|
|
|
121
121
|
},
|
|
122
122
|
runArrayQueue() {
|
|
123
123
|
Object.keys(arrayQueue).forEach((key) => {
|
|
124
|
-
arrayQueue[key].
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
const dates = arrayQueue[key].filter((item) => item?.position instanceof Date);
|
|
125
|
+
const numbers = arrayQueue[key].filter((item) => typeof item?.position === "number" || !item?.position);
|
|
126
|
+
const sortedDates = dates.toSorted((a, b) => b?.position.getTime() - a?.position.getTime());
|
|
127
|
+
const sortedNumbers = numbers.toSorted((a, b) => (a?.position ?? Infinity) - (b.position ?? Infinity));
|
|
128
|
+
const output = sortedNumbers.concat(sortedDates);
|
|
129
|
+
for (const item of output) {
|
|
128
130
|
this.set(key, item.value, []);
|
|
129
131
|
}
|
|
130
132
|
});
|
|
@@ -283,7 +285,7 @@ async function triggerXPineOnLoad(noCache = false) {
|
|
|
283
285
|
}
|
|
284
286
|
|
|
285
287
|
// src/scripts/build.ts
|
|
286
|
-
import { globSync } from "glob";
|
|
288
|
+
import { globSync as globSync2 } from "glob";
|
|
287
289
|
import postcss from "postcss";
|
|
288
290
|
import tailwindPostcss from "@tailwindcss/postcss";
|
|
289
291
|
|
|
@@ -324,7 +326,9 @@ var regex_default = {
|
|
|
324
326
|
dynamicRoutes: /(\[)(.*?)(\])/g,
|
|
325
327
|
isDynamicRoute: /\[(.*)\]/g,
|
|
326
328
|
endsWithTSX: /\.tsx$/,
|
|
327
|
-
endsWithJSX: /\.jsx
|
|
329
|
+
endsWithJSX: /\.jsx$/,
|
|
330
|
+
endsWithFileName: /\.(html|tsx|jsx|js|ts)$/,
|
|
331
|
+
indexFile: /index\.(html|tsx|jsx|js|ts)$/g
|
|
328
332
|
};
|
|
329
333
|
|
|
330
334
|
// src/util/config-file.ts
|
|
@@ -447,8 +451,227 @@ var staticComment = "<!-- static -->";
|
|
|
447
451
|
|
|
448
452
|
// src/scripts/build.ts
|
|
449
453
|
import ts3 from "typescript";
|
|
454
|
+
|
|
455
|
+
// src/express.ts
|
|
456
|
+
import express from "express";
|
|
457
|
+
import { globSync } from "glob";
|
|
458
|
+
|
|
459
|
+
// src/auth.ts
|
|
460
|
+
import jsonwebtoken from "jsonwebtoken";
|
|
461
|
+
var { verify, sign } = jsonwebtoken;
|
|
462
|
+
async function signUser(email, username) {
|
|
463
|
+
return new Promise((resolve, reject) => {
|
|
464
|
+
sign(
|
|
465
|
+
{
|
|
466
|
+
user: {
|
|
467
|
+
email,
|
|
468
|
+
username
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
// @ts-ignore
|
|
472
|
+
process.env.JWT_PRIVATE_KEY,
|
|
473
|
+
{ expiresIn: "30d" },
|
|
474
|
+
(err, token) => {
|
|
475
|
+
if (err) reject(err);
|
|
476
|
+
resolve(token);
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
async function verifyUser(token) {
|
|
482
|
+
return new Promise((resolve, reject) => {
|
|
483
|
+
verify(token, process.env.JWT_PRIVATE_KEY, (err, authorizedData) => {
|
|
484
|
+
if (err) reject(err);
|
|
485
|
+
resolve(authorizedData);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
function getTokenFromRequest(req) {
|
|
490
|
+
const { authorization } = req.headers;
|
|
491
|
+
if (!authorization) return null;
|
|
492
|
+
const token = authorization.split(" ").pop() || "";
|
|
493
|
+
return token || null;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/express.ts
|
|
497
|
+
import requestIP from "request-ip";
|
|
498
|
+
import fs5 from "fs-extra";
|
|
499
|
+
import path5 from "path";
|
|
500
|
+
import EventEmitter from "events";
|
|
501
|
+
var OnInitEmitter = class extends EventEmitter {
|
|
502
|
+
};
|
|
503
|
+
var onInitEmitter = new OnInitEmitter();
|
|
504
|
+
onInitEmitter.on("triggerOnInit", async (paths) => {
|
|
505
|
+
for (const routePath of paths) {
|
|
506
|
+
const pathImport = await import(routePath.path + `?cache=${Date.now()}`);
|
|
507
|
+
if (pathImport?.config?.onInit) await pathImport.config.onInit();
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
function getAllBuiltRoutes() {
|
|
511
|
+
const routes = globSync(config.pagesDir + "/**/*.{tsx,ts}");
|
|
512
|
+
return routes.map((route) => {
|
|
513
|
+
const routeFormatted = route.split(config.pagesDir).pop().replace(".tsx", "").replace(".js", "").replace(".ts", "");
|
|
514
|
+
if (routeFormatted.endsWith("+config")) return;
|
|
515
|
+
const routeFormattedWithIndex = routeFormatted.replace(/\/index$/g, "");
|
|
516
|
+
return {
|
|
517
|
+
route: routeFormattedWithIndex,
|
|
518
|
+
path: route.replace(config.srcDir, config.distDir).replace(".tsx", ".js").replace(".ts", ".js"),
|
|
519
|
+
originalRoute: route
|
|
520
|
+
};
|
|
521
|
+
}).filter(Boolean);
|
|
522
|
+
}
|
|
523
|
+
async function createRouter() {
|
|
524
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
525
|
+
const methods = ["get", "post", "put", "patch", "delete"];
|
|
526
|
+
const router = express.Router();
|
|
527
|
+
const routeMap = getAllBuiltRoutes();
|
|
528
|
+
const routeResults = [];
|
|
529
|
+
const configFiles = globSync(config.pagesDir + "/**/+config.{tsx,ts}");
|
|
530
|
+
await triggerXPineOnLoad();
|
|
531
|
+
for (const route of routeMap) {
|
|
532
|
+
const isJSX = route.originalRoute.endsWith(".tsx") || route.originalRoute.endsWith(".jsx");
|
|
533
|
+
const slugRoute = route.route.replace(/[ ]/g, "");
|
|
534
|
+
const foundMethod = methods.find((method) => slugRoute.endsWith(`.${method}`));
|
|
535
|
+
const isDynamicRoute = slugRoute.match(regex_default.isDynamicRoute);
|
|
536
|
+
let formattedRouteItem = slugRoute;
|
|
537
|
+
if (foundMethod) formattedRouteItem = formattedRouteItem.split(".").shift();
|
|
538
|
+
if (isDynamicRoute) {
|
|
539
|
+
const result = [...formattedRouteItem.matchAll(regex_default.dynamicRoutes)];
|
|
540
|
+
for (const match of result) {
|
|
541
|
+
formattedRouteItem = formattedRouteItem.replace(match[0], ":" + match[2]);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
const componentImport = await import(route.path);
|
|
545
|
+
const componentFn = isDev ? null : componentImport?.default;
|
|
546
|
+
if (componentImport?.config?.onInit) {
|
|
547
|
+
await componentImport.config?.onInit();
|
|
548
|
+
}
|
|
549
|
+
let config2 = {};
|
|
550
|
+
const configFilePaths = getConfigFiles(route.originalRoute, configFiles);
|
|
551
|
+
if (!isDev) {
|
|
552
|
+
config2 = configFilePaths && await getCompleteConfig(configFilePaths, Date.now());
|
|
553
|
+
if (componentImport?.config) {
|
|
554
|
+
config2 = {
|
|
555
|
+
...config2,
|
|
556
|
+
...componentImport.config
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
routeResults.push({
|
|
561
|
+
formattedRouteItem,
|
|
562
|
+
foundMethod,
|
|
563
|
+
route
|
|
564
|
+
});
|
|
565
|
+
router[foundMethod || "get"](formattedRouteItem, async (req, res) => {
|
|
566
|
+
const urlPath = req?.route?.path || "/";
|
|
567
|
+
try {
|
|
568
|
+
const staticPath = routeHasStaticPath(formattedRouteItem, req.params);
|
|
569
|
+
if (staticPath && !isDev) {
|
|
570
|
+
res.sendFile(staticPath);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (componentFn && !isDev) {
|
|
574
|
+
if (isJSX) {
|
|
575
|
+
const data = config2?.data ? await config2.data(req) : null;
|
|
576
|
+
const originalResult = await componentFn({ req, res, data, path: urlPath });
|
|
577
|
+
const output = config2?.wrapper ? await config2.wrapper({ req, children: originalResult, config: config2, data, path: urlPath }) : originalResult;
|
|
578
|
+
res.send(doctypeHTML + output);
|
|
579
|
+
} else {
|
|
580
|
+
await componentFn(req, res);
|
|
581
|
+
}
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
await triggerXPineOnLoad(true);
|
|
585
|
+
const componentImportDev = await import(route.path + `?cache=${Date.now()}`);
|
|
586
|
+
const componentFnDev = componentImportDev.default;
|
|
587
|
+
onInitEmitter.emit("triggerOnInit", getAllBuiltRoutes());
|
|
588
|
+
if (isJSX) {
|
|
589
|
+
let config3 = configFilePaths && await getCompleteConfig(configFilePaths, Date.now());
|
|
590
|
+
if (componentImportDev?.config) {
|
|
591
|
+
config3 = {
|
|
592
|
+
...config3,
|
|
593
|
+
...componentImportDev.config
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
const data = config3?.data ? await config3.data(req) : null;
|
|
597
|
+
const originalResult = await componentFnDev({ req, res, data, config: config3, path: urlPath });
|
|
598
|
+
const output = config3?.wrapper ? await config3.wrapper({ req, children: originalResult, config: config3, data, path: urlPath }) : originalResult;
|
|
599
|
+
context.clear();
|
|
600
|
+
res.send(doctypeHTML + output);
|
|
601
|
+
} else {
|
|
602
|
+
await componentFnDev(req, res);
|
|
603
|
+
}
|
|
604
|
+
} catch (err) {
|
|
605
|
+
console.error(err);
|
|
606
|
+
res.status(err?.status || 500).send(err?.message || "Error");
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
router,
|
|
612
|
+
routeResults
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
async function verifyUserMiddleware(req, _res, next) {
|
|
616
|
+
const { usertoken } = req.cookies;
|
|
617
|
+
if (!usertoken) {
|
|
618
|
+
req.user = null;
|
|
619
|
+
}
|
|
620
|
+
try {
|
|
621
|
+
const { user } = await verifyUser(usertoken);
|
|
622
|
+
req.user = user;
|
|
623
|
+
} catch (err) {
|
|
624
|
+
req.user = null;
|
|
625
|
+
}
|
|
626
|
+
next();
|
|
627
|
+
}
|
|
628
|
+
async function createXPineRouter(app, beforeErrorRoute) {
|
|
629
|
+
app.use(express.static(config.distPublicDir));
|
|
630
|
+
app.use(verifyUserMiddleware);
|
|
631
|
+
app.use(requestIP.mw());
|
|
632
|
+
const { router, routeResults } = await createRouter();
|
|
633
|
+
app.use(function replaceableRouter(req, res, next) {
|
|
634
|
+
router(req, res, next);
|
|
635
|
+
});
|
|
636
|
+
const found404 = routeResults?.find((item) => item?.formattedRouteItem === "/404");
|
|
637
|
+
const import404 = process.env.NODE_ENV === "development" || !found404 ? null : (await import(found404.route.path)).default;
|
|
638
|
+
if (beforeErrorRoute) beforeErrorRoute(app);
|
|
639
|
+
app.use(async function(req, res) {
|
|
640
|
+
res.status(404);
|
|
641
|
+
if (import404) {
|
|
642
|
+
res.send(doctypeHTML + await import404(req, res));
|
|
643
|
+
} else if (found404 && process.env.NODE_ENV === "development") {
|
|
644
|
+
const import404Item = (await import(found404.route.path + `?cache=${Date.now()}`)).default;
|
|
645
|
+
res.send(doctypeHTML + await import404Item(req, res));
|
|
646
|
+
} else {
|
|
647
|
+
res.send("Error");
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
function routeHasStaticPath(route, params) {
|
|
652
|
+
const paramEntries = Object.entries(params);
|
|
653
|
+
let routeToStaticPath = route;
|
|
654
|
+
for (const [key, value] of paramEntries) {
|
|
655
|
+
routeToStaticPath = routeToStaticPath.replace(`:${key}`, value);
|
|
656
|
+
}
|
|
657
|
+
routeToStaticPath += "/index.html";
|
|
658
|
+
const outputPath = path5.join(config.distPagesDir, routeToStaticPath);
|
|
659
|
+
if (fs5.existsSync(outputPath)) return outputPath;
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
function filePathToURLPath(pathName, isDist = true) {
|
|
663
|
+
const result = pathName.split(isDist ? config.distPagesDir : config.pagesDir).pop().replace(regex_default.indexFile, "").replace(regex_default.endsWithFileName, "");
|
|
664
|
+
if (result.endsWith("/")) {
|
|
665
|
+
const cleanedResult = result.slice(0, -1);
|
|
666
|
+
if (!cleanedResult) return "/";
|
|
667
|
+
return cleanedResult;
|
|
668
|
+
}
|
|
669
|
+
return result;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/scripts/build.ts
|
|
450
673
|
var extensions = [".ts", ".tsx"];
|
|
451
|
-
var packageJson = JSON.parse(
|
|
674
|
+
var packageJson = JSON.parse(fs6.readFileSync(config.packageJsonPath, "utf-8"));
|
|
452
675
|
var allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
|
|
453
676
|
var xpineDistDir = getXPineDistDir();
|
|
454
677
|
async function buildApp(args) {
|
|
@@ -456,12 +679,12 @@ async function buildApp(args) {
|
|
|
456
679
|
const removePreviousBuild = args?.removePreviousBuild || false;
|
|
457
680
|
const disableTailwind = args?.disableTailwind || false;
|
|
458
681
|
try {
|
|
459
|
-
if (removePreviousBuild)
|
|
460
|
-
const srcDirFiles =
|
|
682
|
+
if (removePreviousBuild) fs6.removeSync(config.distDir);
|
|
683
|
+
const srcDirFiles = globSync2(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
|
|
461
684
|
const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev);
|
|
462
685
|
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
463
686
|
await buildClientSideFiles([alpineDataFile], isDev);
|
|
464
|
-
|
|
687
|
+
fs6.removeSync(config.distTempFolder);
|
|
465
688
|
await buildCSS(disableTailwind);
|
|
466
689
|
await buildPublicFolderSymlinks();
|
|
467
690
|
await buildOnLoadFile(componentData, isDev);
|
|
@@ -481,7 +704,7 @@ async function buildAppFiles(files, isDev) {
|
|
|
481
704
|
return fileName === "+config";
|
|
482
705
|
});
|
|
483
706
|
const backendFiles = files.filter((file) => extensions.find((ext) => file.endsWith(ext))).filter((file) => !file.startsWith(config.publicDir));
|
|
484
|
-
|
|
707
|
+
fs6.ensureDirSync(config.distDir);
|
|
485
708
|
await build({
|
|
486
709
|
entryPoints: backendFiles,
|
|
487
710
|
format: "esm",
|
|
@@ -505,10 +728,10 @@ async function buildAppFiles(files, isDev) {
|
|
|
505
728
|
};
|
|
506
729
|
}
|
|
507
730
|
async function buildClientSideFiles(alpineDataFiles = [], isDev) {
|
|
508
|
-
const tempFilePath =
|
|
509
|
-
|
|
731
|
+
const tempFilePath = path6.join(config.distTempFolder, "./app.ts");
|
|
732
|
+
fs6.ensureFileSync(tempFilePath);
|
|
510
733
|
const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
|
|
511
|
-
const clientFiles =
|
|
734
|
+
const clientFiles = globSync2(
|
|
512
735
|
config.publicDir + "/**/*.{js,ts}",
|
|
513
736
|
{
|
|
514
737
|
ignore: pagesScriptsGlob
|
|
@@ -524,7 +747,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev) {
|
|
|
524
747
|
minify: !isDev,
|
|
525
748
|
sourcemap: isDev ? "inline" : false
|
|
526
749
|
});
|
|
527
|
-
const pagesFiles =
|
|
750
|
+
const pagesFiles = globSync2(pagesScriptsGlob);
|
|
528
751
|
await build({
|
|
529
752
|
entryPoints: pagesFiles || [],
|
|
530
753
|
bundle: true,
|
|
@@ -535,14 +758,14 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev) {
|
|
|
535
758
|
await logSize(config.distPublicDir, "client");
|
|
536
759
|
}
|
|
537
760
|
function writeDevServerClientSideCode(tempFilePath) {
|
|
538
|
-
const devServerPath =
|
|
539
|
-
const content =
|
|
540
|
-
|
|
761
|
+
const devServerPath = path6.join(xpineDistDir, "./src/static/dev-server.js");
|
|
762
|
+
const content = fs6.readFileSync(devServerPath, "utf-8");
|
|
763
|
+
fs6.appendFileSync(tempFilePath, "\n" + content);
|
|
541
764
|
}
|
|
542
765
|
function writeSpaClientSideCode(tempFilePath) {
|
|
543
|
-
const spaPath =
|
|
544
|
-
const content =
|
|
545
|
-
|
|
766
|
+
const spaPath = path6.join(xpineDistDir, "./src/static/spa.js");
|
|
767
|
+
const content = fs6.readFileSync(spaPath, "utf-8");
|
|
768
|
+
fs6.appendFileSync(tempFilePath, "\n" + content);
|
|
546
769
|
}
|
|
547
770
|
async function buildAlpineDataFile(componentData, dataFiles) {
|
|
548
771
|
const output = {
|
|
@@ -588,23 +811,23 @@ async function buildAlpineDataFile(componentData, dataFiles) {
|
|
|
588
811
|
output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
|
|
589
812
|
}
|
|
590
813
|
const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
|
|
591
|
-
|
|
592
|
-
|
|
814
|
+
fs6.ensureFileSync(config.alpineDataPath);
|
|
815
|
+
fs6.writeFileSync(config.alpineDataPath, result);
|
|
593
816
|
return config.alpineDataPath;
|
|
594
817
|
}
|
|
595
818
|
async function buildCSS(disableTailwind) {
|
|
596
|
-
const cssFiles =
|
|
819
|
+
const cssFiles = globSync2(config.srcDir + "/**/*.css");
|
|
597
820
|
for (const file of cssFiles) {
|
|
598
|
-
const fileContents =
|
|
821
|
+
const fileContents = fs6.readFileSync(file, "utf-8");
|
|
599
822
|
const result = disableTailwind ? fileContents : await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
|
|
600
823
|
const newPath = file.replace(config.srcDir, config.distDir);
|
|
601
|
-
|
|
602
|
-
|
|
824
|
+
fs6.ensureFileSync(newPath);
|
|
825
|
+
fs6.writeFileSync(newPath, result.css);
|
|
603
826
|
}
|
|
604
827
|
logSize(config.distPublicDir, "css");
|
|
605
828
|
}
|
|
606
829
|
async function buildPublicFolderSymlinks() {
|
|
607
|
-
const files =
|
|
830
|
+
const files = globSync2(config.publicDir + "/**/*.*", {
|
|
608
831
|
ignore: "/**/*.{css,js,ts,tsx,jsx}"
|
|
609
832
|
});
|
|
610
833
|
for (const file of files) {
|
|
@@ -613,19 +836,19 @@ async function buildPublicFolderSymlinks() {
|
|
|
613
836
|
const splitNewPath = newPath.split("/");
|
|
614
837
|
splitNewPath.pop();
|
|
615
838
|
const newDir = splitNewPath.join("/");
|
|
616
|
-
|
|
617
|
-
|
|
839
|
+
fs6.ensureDirSync(newDir);
|
|
840
|
+
fs6.symlinkSync(file, newPath);
|
|
618
841
|
} catch {
|
|
619
842
|
}
|
|
620
843
|
}
|
|
621
844
|
}
|
|
622
845
|
async function logSize(pathName, type, validExtensions = [".js", ".css"]) {
|
|
623
|
-
const files =
|
|
846
|
+
const files = globSync2(pathName + "/**/*" + (type === "css" ? ".css" : ""));
|
|
624
847
|
const fileSizes = files.map((file) => {
|
|
625
848
|
if (!validExtensions.find((ext) => file.endsWith(ext))) return false;
|
|
626
849
|
return {
|
|
627
850
|
file,
|
|
628
|
-
size:
|
|
851
|
+
size: fs6.statSync(file).size / (1024 * 1e3)
|
|
629
852
|
};
|
|
630
853
|
}).filter(Boolean);
|
|
631
854
|
const totalSize = fileSizes.reduce((total, current) => {
|
|
@@ -661,15 +884,16 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
661
884
|
if (componentImport?.onInit) await componentImport.onInit();
|
|
662
885
|
const outputPath = componentDynamicPaths?.length ? componentDynamicPaths.reduce((total, current) => {
|
|
663
886
|
return total.replace(`/[${current}]`, "");
|
|
664
|
-
},
|
|
887
|
+
}, path6.dirname(builtComponentPath)) : path6.dirname(builtComponentPath);
|
|
665
888
|
if (typeof config2?.staticPaths === "boolean") {
|
|
889
|
+
const urlPath = filePathToURLPath(outputPath);
|
|
666
890
|
try {
|
|
667
891
|
const req = { params: {} };
|
|
668
892
|
const data = config2?.data ? await config2.data(req) : null;
|
|
669
|
-
const staticComponentOutput = await componentFn({ data });
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data }) : staticComponentOutput) + staticComment
|
|
893
|
+
const staticComponentOutput = await componentFn({ data, path: urlPath });
|
|
894
|
+
fs6.writeFileSync(
|
|
895
|
+
path6.join(outputPath, "./index.html"),
|
|
896
|
+
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data, path: urlPath }) : staticComponentOutput) + staticComment
|
|
673
897
|
);
|
|
674
898
|
} catch (err) {
|
|
675
899
|
console.error(err);
|
|
@@ -684,13 +908,14 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
684
908
|
...componentDynamicPaths?.length ? dynamicPath : {}
|
|
685
909
|
}
|
|
686
910
|
};
|
|
911
|
+
const updatedOutDir = path6.join(outputPath, `./${componentDynamicPaths.map((key) => dynamicPath[key]).join("/")}`);
|
|
912
|
+
const urlPath = filePathToURLPath(updatedOutDir);
|
|
687
913
|
const data = config2?.data ? await config2.data(req) : null;
|
|
688
|
-
const staticComponentOutput = await componentFn({ req, data });
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data }) : staticComponentOutput) + staticComment
|
|
914
|
+
const staticComponentOutput = await componentFn({ req, data, path: urlPath });
|
|
915
|
+
fs6.ensureDirSync(updatedOutDir);
|
|
916
|
+
fs6.writeFileSync(
|
|
917
|
+
path6.join(updatedOutDir, "./index.html"),
|
|
918
|
+
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data, path: urlPath }) : staticComponentOutput) + staticComment
|
|
694
919
|
);
|
|
695
920
|
} catch (err) {
|
|
696
921
|
console.log("Could not build static component", component.path);
|
|
@@ -738,8 +963,8 @@ async function buildOnLoadFile(componentData, isDev) {
|
|
|
738
963
|
context.runArrayQueue();
|
|
739
964
|
}
|
|
740
965
|
`;
|
|
741
|
-
const onLoadFilePath =
|
|
742
|
-
|
|
966
|
+
const onLoadFilePath = path6.join(config.distDir, "./__xpineOnLoad.ts");
|
|
967
|
+
fs6.writeFileSync(onLoadFilePath, output);
|
|
743
968
|
await build({
|
|
744
969
|
entryPoints: [onLoadFilePath],
|
|
745
970
|
format: "esm",
|
|
@@ -757,15 +982,15 @@ async function buildOnLoadFile(componentData, isDev) {
|
|
|
757
982
|
}
|
|
758
983
|
|
|
759
984
|
// src/runDevServer.ts
|
|
760
|
-
import
|
|
985
|
+
import path8 from "path";
|
|
761
986
|
|
|
762
987
|
// src/util/env.ts
|
|
763
988
|
import dotenv from "dotenv";
|
|
764
|
-
import
|
|
989
|
+
import path7 from "path";
|
|
765
990
|
import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
|
|
766
991
|
async function setupEnv() {
|
|
767
992
|
if (process.env.HAS_SETUP_ENV) return;
|
|
768
|
-
dotenv.config({ path:
|
|
993
|
+
dotenv.config({ path: path7.join(config.rootDir, `./.env.${process.env.STAGE || "dev"}`) });
|
|
769
994
|
await loadSecretsManagerSecrets();
|
|
770
995
|
process.env.HAS_SETUP_ENV = "true";
|
|
771
996
|
}
|
|
@@ -801,7 +1026,7 @@ async function runDevServer() {
|
|
|
801
1026
|
const watcher = chokidar.watch(config.srcDir, {
|
|
802
1027
|
ignoreInitial: true,
|
|
803
1028
|
// Ignore map and prisma files
|
|
804
|
-
ignored: (pathName) => pathName.endsWith(".map") || pathName.startsWith(
|
|
1029
|
+
ignored: (pathName) => pathName.endsWith(".map") || pathName.startsWith(path8.join(config.serverDir, "./prisma"))
|
|
805
1030
|
});
|
|
806
1031
|
watcher.on("all", async (event, path9) => {
|
|
807
1032
|
const shouldReloadServer = path9.startsWith(config.serverDir) && !path9.startsWith(config.runDir) || ["add", "unlink"].includes(event) && path9.startsWith(config.pagesDir);
|
|
@@ -821,10 +1046,10 @@ async function runDevServer() {
|
|
|
821
1046
|
const startServer2 = (await import(config.serverDistAppPath + `?cache=${Date.now()}`)).default;
|
|
822
1047
|
appServer = await startServer2();
|
|
823
1048
|
}
|
|
824
|
-
const wsApp =
|
|
1049
|
+
const wsApp = express2();
|
|
825
1050
|
const wsServer = http.createServer(wsApp);
|
|
826
1051
|
expressWs(wsApp, wsServer);
|
|
827
|
-
class RefreshEmitter extends
|
|
1052
|
+
class RefreshEmitter extends EventEmitter2 {
|
|
828
1053
|
}
|
|
829
1054
|
;
|
|
830
1055
|
const refreshEmitter = new RefreshEmitter();
|
|
@@ -847,7 +1072,7 @@ function asyncServerClose(server) {
|
|
|
847
1072
|
});
|
|
848
1073
|
}
|
|
849
1074
|
function createRebuildEmitter(delay = 500) {
|
|
850
|
-
class RebuildEmitter extends
|
|
1075
|
+
class RebuildEmitter extends EventEmitter2 {
|
|
851
1076
|
}
|
|
852
1077
|
;
|
|
853
1078
|
const rebuildEmitter = new RebuildEmitter();
|
|
@@ -872,213 +1097,6 @@ function createRebuildEmitter(delay = 500) {
|
|
|
872
1097
|
return rebuildEmitter;
|
|
873
1098
|
}
|
|
874
1099
|
|
|
875
|
-
// src/express.ts
|
|
876
|
-
import express2 from "express";
|
|
877
|
-
import { globSync as globSync2 } from "glob";
|
|
878
|
-
|
|
879
|
-
// src/auth.ts
|
|
880
|
-
import jsonwebtoken from "jsonwebtoken";
|
|
881
|
-
var { verify, sign } = jsonwebtoken;
|
|
882
|
-
async function signUser(email, username) {
|
|
883
|
-
return new Promise((resolve, reject) => {
|
|
884
|
-
sign(
|
|
885
|
-
{
|
|
886
|
-
user: {
|
|
887
|
-
email,
|
|
888
|
-
username
|
|
889
|
-
}
|
|
890
|
-
},
|
|
891
|
-
// @ts-ignore
|
|
892
|
-
process.env.JWT_PRIVATE_KEY,
|
|
893
|
-
{ expiresIn: "30d" },
|
|
894
|
-
(err, token) => {
|
|
895
|
-
if (err) reject(err);
|
|
896
|
-
resolve(token);
|
|
897
|
-
}
|
|
898
|
-
);
|
|
899
|
-
});
|
|
900
|
-
}
|
|
901
|
-
async function verifyUser(token) {
|
|
902
|
-
return new Promise((resolve, reject) => {
|
|
903
|
-
verify(token, process.env.JWT_PRIVATE_KEY, (err, authorizedData) => {
|
|
904
|
-
if (err) reject(err);
|
|
905
|
-
resolve(authorizedData);
|
|
906
|
-
});
|
|
907
|
-
});
|
|
908
|
-
}
|
|
909
|
-
function getTokenFromRequest(req) {
|
|
910
|
-
const { authorization } = req.headers;
|
|
911
|
-
if (!authorization) return null;
|
|
912
|
-
const token = authorization.split(" ").pop() || "";
|
|
913
|
-
return token || null;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// src/express.ts
|
|
917
|
-
import requestIP from "request-ip";
|
|
918
|
-
import fs6 from "fs-extra";
|
|
919
|
-
import path8 from "path";
|
|
920
|
-
import EventEmitter2 from "events";
|
|
921
|
-
var OnInitEmitter = class extends EventEmitter2 {
|
|
922
|
-
};
|
|
923
|
-
var onInitEmitter = new OnInitEmitter();
|
|
924
|
-
onInitEmitter.on("triggerOnInit", async (paths) => {
|
|
925
|
-
for (const routePath of paths) {
|
|
926
|
-
const pathImport = await import(routePath.path + `?cache=${Date.now()}`);
|
|
927
|
-
if (pathImport?.config?.onInit) await pathImport.config.onInit();
|
|
928
|
-
}
|
|
929
|
-
});
|
|
930
|
-
function getAllBuiltRoutes() {
|
|
931
|
-
const routes = globSync2(config.pagesDir + "/**/*.{tsx,ts}");
|
|
932
|
-
return routes.map((route) => {
|
|
933
|
-
const routeFormatted = route.split(config.pagesDir).pop().replace(".tsx", "").replace(".js", "").replace(".ts", "");
|
|
934
|
-
if (routeFormatted.endsWith("+config")) return;
|
|
935
|
-
const routeFormattedWithIndex = routeFormatted.replace(/\/index$/g, "");
|
|
936
|
-
return {
|
|
937
|
-
route: routeFormattedWithIndex,
|
|
938
|
-
path: route.replace(config.srcDir, config.distDir).replace(".tsx", ".js").replace(".ts", ".js"),
|
|
939
|
-
originalRoute: route
|
|
940
|
-
};
|
|
941
|
-
}).filter(Boolean);
|
|
942
|
-
}
|
|
943
|
-
async function createRouter() {
|
|
944
|
-
const isDev = process.env.NODE_ENV === "development";
|
|
945
|
-
const methods = ["get", "post", "put", "patch", "delete"];
|
|
946
|
-
const router = express2.Router();
|
|
947
|
-
const routeMap = getAllBuiltRoutes();
|
|
948
|
-
const routeResults = [];
|
|
949
|
-
const configFiles = globSync2(config.pagesDir + "/**/+config.{tsx,ts}");
|
|
950
|
-
await triggerXPineOnLoad();
|
|
951
|
-
for (const route of routeMap) {
|
|
952
|
-
const isJSX = route.originalRoute.endsWith(".tsx") || route.originalRoute.endsWith(".jsx");
|
|
953
|
-
const slugRoute = route.route.replace(/[ ]/g, "");
|
|
954
|
-
const foundMethod = methods.find((method) => slugRoute.endsWith(`.${method}`));
|
|
955
|
-
const isDynamicRoute = slugRoute.match(regex_default.isDynamicRoute);
|
|
956
|
-
let formattedRouteItem = slugRoute;
|
|
957
|
-
if (foundMethod) formattedRouteItem = formattedRouteItem.split(".").shift();
|
|
958
|
-
if (isDynamicRoute) {
|
|
959
|
-
const result = [...formattedRouteItem.matchAll(regex_default.dynamicRoutes)];
|
|
960
|
-
for (const match of result) {
|
|
961
|
-
formattedRouteItem = formattedRouteItem.replace(match[0], ":" + match[2]);
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
const componentImport = await import(route.path);
|
|
965
|
-
const componentFn = isDev ? null : componentImport?.default;
|
|
966
|
-
if (componentImport?.config?.onInit) {
|
|
967
|
-
await componentImport.config?.onInit();
|
|
968
|
-
}
|
|
969
|
-
let config2 = {};
|
|
970
|
-
const configFilePaths = getConfigFiles(route.originalRoute, configFiles);
|
|
971
|
-
if (!isDev) {
|
|
972
|
-
config2 = configFilePaths && await getCompleteConfig(configFilePaths, Date.now());
|
|
973
|
-
if (componentImport?.config) {
|
|
974
|
-
config2 = {
|
|
975
|
-
...config2,
|
|
976
|
-
...componentImport.config
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
routeResults.push({
|
|
981
|
-
formattedRouteItem,
|
|
982
|
-
foundMethod,
|
|
983
|
-
route
|
|
984
|
-
});
|
|
985
|
-
router[foundMethod || "get"](formattedRouteItem, async (req, res) => {
|
|
986
|
-
try {
|
|
987
|
-
const staticPath = routeHasStaticPath(formattedRouteItem, req.params);
|
|
988
|
-
if (staticPath && !isDev) {
|
|
989
|
-
res.sendFile(staticPath);
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
if (componentFn && !isDev) {
|
|
993
|
-
if (isJSX) {
|
|
994
|
-
const data = config2?.data ? await config2.data(req) : null;
|
|
995
|
-
const originalResult = await componentFn({ req, res, data });
|
|
996
|
-
const output = config2?.wrapper ? await config2.wrapper({ req, children: originalResult, config: config2, data }) : originalResult;
|
|
997
|
-
res.send(doctypeHTML + output);
|
|
998
|
-
} else {
|
|
999
|
-
await componentFn(req, res);
|
|
1000
|
-
}
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
|
-
await triggerXPineOnLoad(true);
|
|
1004
|
-
const componentImportDev = await import(route.path + `?cache=${Date.now()}`);
|
|
1005
|
-
const componentFnDev = componentImportDev.default;
|
|
1006
|
-
onInitEmitter.emit("triggerOnInit", getAllBuiltRoutes());
|
|
1007
|
-
if (isJSX) {
|
|
1008
|
-
let config3 = configFilePaths && await getCompleteConfig(configFilePaths, Date.now());
|
|
1009
|
-
if (componentImportDev?.config) {
|
|
1010
|
-
config3 = {
|
|
1011
|
-
...config3,
|
|
1012
|
-
...componentImportDev.config
|
|
1013
|
-
};
|
|
1014
|
-
}
|
|
1015
|
-
const data = config3?.data ? await config3.data(req) : null;
|
|
1016
|
-
const originalResult = await componentFnDev({ req, res, data, config: config3 });
|
|
1017
|
-
const output = config3?.wrapper ? await config3.wrapper({ req, children: originalResult, config: config3, data }) : originalResult;
|
|
1018
|
-
context.clear();
|
|
1019
|
-
res.send(doctypeHTML + output);
|
|
1020
|
-
} else {
|
|
1021
|
-
await componentFnDev(req, res);
|
|
1022
|
-
}
|
|
1023
|
-
} catch (err) {
|
|
1024
|
-
console.error(err);
|
|
1025
|
-
res.status(err?.status || 500).send(err?.message || "Error");
|
|
1026
|
-
}
|
|
1027
|
-
});
|
|
1028
|
-
}
|
|
1029
|
-
return {
|
|
1030
|
-
router,
|
|
1031
|
-
routeResults
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
async function verifyUserMiddleware(req, _res, next) {
|
|
1035
|
-
const { usertoken } = req.cookies;
|
|
1036
|
-
if (!usertoken) {
|
|
1037
|
-
req.user = null;
|
|
1038
|
-
}
|
|
1039
|
-
try {
|
|
1040
|
-
const { user } = await verifyUser(usertoken);
|
|
1041
|
-
req.user = user;
|
|
1042
|
-
} catch (err) {
|
|
1043
|
-
req.user = null;
|
|
1044
|
-
}
|
|
1045
|
-
next();
|
|
1046
|
-
}
|
|
1047
|
-
async function createXPineRouter(app, beforeErrorRoute) {
|
|
1048
|
-
app.use(express2.static(config.distPublicDir));
|
|
1049
|
-
app.use(verifyUserMiddleware);
|
|
1050
|
-
app.use(requestIP.mw());
|
|
1051
|
-
const { router, routeResults } = await createRouter();
|
|
1052
|
-
app.use(function replaceableRouter(req, res, next) {
|
|
1053
|
-
router(req, res, next);
|
|
1054
|
-
});
|
|
1055
|
-
const found404 = routeResults?.find((item) => item?.formattedRouteItem === "/404");
|
|
1056
|
-
const import404 = process.env.NODE_ENV === "development" || !found404 ? null : (await import(found404.route.path)).default;
|
|
1057
|
-
if (beforeErrorRoute) beforeErrorRoute(app);
|
|
1058
|
-
app.use(async function(req, res) {
|
|
1059
|
-
res.status(404);
|
|
1060
|
-
if (import404) {
|
|
1061
|
-
res.send(doctypeHTML + await import404(req, res));
|
|
1062
|
-
} else if (found404 && process.env.NODE_ENV === "development") {
|
|
1063
|
-
const import404Item = (await import(found404.route.path + `?cache=${Date.now()}`)).default;
|
|
1064
|
-
res.send(doctypeHTML + await import404Item(req, res));
|
|
1065
|
-
} else {
|
|
1066
|
-
res.send("Error");
|
|
1067
|
-
}
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
function routeHasStaticPath(route, params) {
|
|
1071
|
-
const paramEntries = Object.entries(params);
|
|
1072
|
-
let routeToStaticPath = route;
|
|
1073
|
-
for (const [key, value] of paramEntries) {
|
|
1074
|
-
routeToStaticPath = routeToStaticPath.replace(`:${key}`, value);
|
|
1075
|
-
}
|
|
1076
|
-
routeToStaticPath += "/index.html";
|
|
1077
|
-
const outputPath = path8.join(config.distPagesDir, routeToStaticPath);
|
|
1078
|
-
if (fs6.existsSync(outputPath)) return outputPath;
|
|
1079
|
-
return false;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
1100
|
// src/util/html.ts
|
|
1083
1101
|
var html = class {
|
|
1084
1102
|
static attributeObjectToString(props) {
|
|
@@ -1118,6 +1136,7 @@ export {
|
|
|
1118
1136
|
createContext,
|
|
1119
1137
|
createRouter,
|
|
1120
1138
|
createXPineRouter,
|
|
1139
|
+
filePathToURLPath,
|
|
1121
1140
|
fromRoot,
|
|
1122
1141
|
getComponentDynamicPaths,
|
|
1123
1142
|
getTokenFromRequest,
|