create-meridian-app 0.1.13 → 0.1.15
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/{chunk-U5TMTVEV.js → chunk-DUCNQ62I.js} +7 -2
- package/dist/cli.js +34 -8
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -419,6 +419,7 @@ ${handlers.join("\n\n")}
|
|
|
419
419
|
|
|
420
420
|
// src/utils.ts
|
|
421
421
|
import path from "path";
|
|
422
|
+
import { randomBytes } from "crypto";
|
|
422
423
|
import fs from "fs/promises";
|
|
423
424
|
import { existsSync } from "fs";
|
|
424
425
|
import { execa } from "execa";
|
|
@@ -462,8 +463,8 @@ process.stdout.write(JSON.stringify({
|
|
|
462
463
|
dashboardPort: c?.admin?.port ?? 5174,
|
|
463
464
|
}))
|
|
464
465
|
`;
|
|
465
|
-
const scriptPath = path.join(rootDir,
|
|
466
|
-
await fs.writeFile(scriptPath, script, "utf-8");
|
|
466
|
+
const scriptPath = path.join(rootDir, `.meridian-ports-${randomBytes(8).toString("hex")}.mjs`);
|
|
467
|
+
await fs.writeFile(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
467
468
|
try {
|
|
468
469
|
const result = await execa("node", ["--import", "tsx/esm", scriptPath], { cwd: rootDir });
|
|
469
470
|
return JSON.parse(result.stdout);
|
|
@@ -480,6 +481,10 @@ async function runNew(projectName) {
|
|
|
480
481
|
console.log(chalk.bold(" Create Meridian App"));
|
|
481
482
|
console.log();
|
|
482
483
|
let name = projectName;
|
|
484
|
+
if (name && !/^[a-z0-9-_]+$/.test(name)) {
|
|
485
|
+
console.error(chalk.red(" \u2716 Project name must contain only lowercase letters, numbers, hyphens, and underscores"));
|
|
486
|
+
process.exit(1);
|
|
487
|
+
}
|
|
483
488
|
if (!name) {
|
|
484
489
|
const res = await prompts(
|
|
485
490
|
{
|
package/dist/cli.js
CHANGED
|
@@ -14,10 +14,11 @@ import {
|
|
|
14
14
|
toKebabCase,
|
|
15
15
|
toPascalCase,
|
|
16
16
|
writeFile
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DUCNQ62I.js";
|
|
18
18
|
|
|
19
19
|
// src/cli.ts
|
|
20
20
|
import { Command } from "commander";
|
|
21
|
+
import chalk13 from "chalk";
|
|
21
22
|
|
|
22
23
|
// src/commands/dev.ts
|
|
23
24
|
import path2 from "path";
|
|
@@ -131,6 +132,13 @@ function startDashboardServer(distDir, port, apiPort, apiHost = "localhost", adm
|
|
|
131
132
|
return;
|
|
132
133
|
}
|
|
133
134
|
let filePath = path.join(distDir, urlPath === "/" ? "index.html" : urlPath);
|
|
135
|
+
const resolvedFile = path.resolve(filePath);
|
|
136
|
+
const resolvedDist = path.resolve(distDir);
|
|
137
|
+
if (!resolvedFile.startsWith(resolvedDist + path.sep) && resolvedFile !== resolvedDist) {
|
|
138
|
+
res.writeHead(403);
|
|
139
|
+
res.end("Forbidden");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
134
142
|
if (!existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
135
143
|
filePath = path.join(distDir, "index.html");
|
|
136
144
|
}
|
|
@@ -306,9 +314,10 @@ const app = await bootstrap({ rootDir: ${JSON.stringify(rootDir)} })
|
|
|
306
314
|
await app.stop()
|
|
307
315
|
process.exit(0)
|
|
308
316
|
`;
|
|
309
|
-
const
|
|
317
|
+
const { randomBytes } = await import("crypto");
|
|
318
|
+
const scriptPath = path3.join(rootDir, `.meridian-migrate-${randomBytes(8).toString("hex")}.mjs`);
|
|
310
319
|
const { writeFile: writeFile2, unlink } = await import("fs/promises");
|
|
311
|
-
await writeFile2(scriptPath, script, "utf-8");
|
|
320
|
+
await writeFile2(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
312
321
|
try {
|
|
313
322
|
await execa3("node", ["--import", "tsx/esm", scriptPath], {
|
|
314
323
|
cwd: rootDir,
|
|
@@ -586,6 +595,12 @@ async function generateRoute(routePath, methods) {
|
|
|
586
595
|
}
|
|
587
596
|
const normalized = routePath.replace(/^\//, "");
|
|
588
597
|
const filePath = path10.join(rootDir, "src", "api", normalized, "route.ts");
|
|
598
|
+
const resolvedFile = path10.resolve(filePath);
|
|
599
|
+
const resolvedBase = path10.resolve(rootDir, "src", "api");
|
|
600
|
+
if (!resolvedFile.startsWith(resolvedBase + path10.sep)) {
|
|
601
|
+
console.error(chalk11.red(" \u2716 Invalid route path: must resolve within src/api/"));
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
589
604
|
if (existsSync8(filePath)) {
|
|
590
605
|
console.error(chalk11.red(` \u2716 Route already exists: src/api/${normalized}/route.ts`));
|
|
591
606
|
process.exit(1);
|
|
@@ -613,6 +628,7 @@ import chalk12 from "chalk";
|
|
|
613
628
|
import ora2 from "ora";
|
|
614
629
|
import prompts from "prompts";
|
|
615
630
|
import { execa as execa4 } from "execa";
|
|
631
|
+
var ROLES = ["super-admin", "admin", "moderator", "member"];
|
|
616
632
|
async function runUserCreate(opts) {
|
|
617
633
|
const rootDir = findProjectRoot();
|
|
618
634
|
if (!rootDir) {
|
|
@@ -623,6 +639,10 @@ async function runUserCreate(opts) {
|
|
|
623
639
|
);
|
|
624
640
|
process.exit(1);
|
|
625
641
|
}
|
|
642
|
+
if (opts.role && !ROLES.includes(opts.role)) {
|
|
643
|
+
console.error(chalk12.red(` \u2716 Invalid role "${opts.role}". Must be one of: ${ROLES.join(", ")}`));
|
|
644
|
+
process.exit(1);
|
|
645
|
+
}
|
|
626
646
|
const response = await prompts(
|
|
627
647
|
[
|
|
628
648
|
{
|
|
@@ -703,7 +723,7 @@ let output
|
|
|
703
723
|
try {
|
|
704
724
|
const result = await authService.register({
|
|
705
725
|
email: ${JSON.stringify(email)},
|
|
706
|
-
password:
|
|
726
|
+
password: process.env.MERIDIAN_USER_PASSWORD,
|
|
707
727
|
first_name: ${JSON.stringify(first_name || null)},
|
|
708
728
|
last_name: ${JSON.stringify(last_name || null)},
|
|
709
729
|
role: ${JSON.stringify(role)},
|
|
@@ -717,14 +737,15 @@ console.log(JSON.stringify(output))
|
|
|
717
737
|
await app.stop()
|
|
718
738
|
process.exit(output.success ? 0 : 1)
|
|
719
739
|
`;
|
|
720
|
-
const
|
|
740
|
+
const { randomBytes } = await import("crypto");
|
|
741
|
+
const scriptPath = path11.join(rootDir, `.meridian-user-create-${randomBytes(8).toString("hex")}.mjs`);
|
|
721
742
|
const { writeFile: writeFile2, unlink } = await import("fs/promises");
|
|
722
|
-
await writeFile2(scriptPath, script, "utf-8");
|
|
743
|
+
await writeFile2(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
723
744
|
try {
|
|
724
745
|
const result = await execa4("node", ["--import", "tsx/esm", scriptPath], {
|
|
725
746
|
cwd: rootDir,
|
|
726
747
|
stdio: "pipe",
|
|
727
|
-
env: { ...process.env, NODE_ENV: "development" }
|
|
748
|
+
env: { ...process.env, NODE_ENV: "development", MERIDIAN_USER_PASSWORD: password }
|
|
728
749
|
});
|
|
729
750
|
const lines = result.stdout.trim().split("\n");
|
|
730
751
|
const output = JSON.parse(lines[lines.length - 1]);
|
|
@@ -788,7 +809,12 @@ program.command("db:generate <name>").description("Generate a new migration file
|
|
|
788
809
|
});
|
|
789
810
|
});
|
|
790
811
|
program.command("serve-dashboard").description("Serve the admin dashboard as a static site").option("-p, --port <port>", "Port to serve on", "5174").action((options) => {
|
|
791
|
-
|
|
812
|
+
const port = Number(options.port);
|
|
813
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
814
|
+
console.error(chalk13.red(` \u2716 Invalid port: ${options.port}`));
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
runServeDashboard(port).catch((err) => {
|
|
792
818
|
console.error(err);
|
|
793
819
|
process.exit(1);
|
|
794
820
|
});
|
package/dist/index.js
CHANGED