@geekmidas/cli 0.31.0 ā 0.33.0
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.cjs +173 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +171 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/dev/__tests__/entry.spec.ts +3 -3
- package/src/dev/index.ts +10 -2
- package/src/init/generators/auth.ts +2 -1
package/dist/index.mjs
CHANGED
|
@@ -26,7 +26,7 @@ import prompts from "prompts";
|
|
|
26
26
|
|
|
27
27
|
//#region package.json
|
|
28
28
|
var name = "@geekmidas/cli";
|
|
29
|
-
var version = "0.
|
|
29
|
+
var version = "0.33.0";
|
|
30
30
|
var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
|
|
31
31
|
var private$1 = false;
|
|
32
32
|
var type = "module";
|
|
@@ -1011,6 +1011,7 @@ function getProductionConfigFromGkm(config$1) {
|
|
|
1011
1011
|
return void 0;
|
|
1012
1012
|
}
|
|
1013
1013
|
async function devCommand(options) {
|
|
1014
|
+
if (options.entry) return entryDevCommand(options);
|
|
1014
1015
|
const defaultEnv = loadEnvFiles(".env");
|
|
1015
1016
|
if (defaultEnv.loaded.length > 0) logger$8.log(`š¦ Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1016
1017
|
const appName = getAppNameFromCwd();
|
|
@@ -1522,6 +1523,168 @@ async function buildServer(config$1, context, provider, enableOpenApi, appRoot =
|
|
|
1522
1523
|
subscriberGenerator.build(context, allSubscribers, outputDir, { provider })
|
|
1523
1524
|
]);
|
|
1524
1525
|
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Find the directory containing .gkm/secrets/.
|
|
1528
|
+
* Walks up from cwd until it finds one, or returns cwd.
|
|
1529
|
+
* @internal Exported for testing
|
|
1530
|
+
*/
|
|
1531
|
+
function findSecretsRoot(startDir) {
|
|
1532
|
+
let dir = startDir;
|
|
1533
|
+
while (dir !== "/") {
|
|
1534
|
+
if (existsSync(join(dir, ".gkm", "secrets"))) return dir;
|
|
1535
|
+
const parent = dirname(dir);
|
|
1536
|
+
if (parent === dir) break;
|
|
1537
|
+
dir = parent;
|
|
1538
|
+
}
|
|
1539
|
+
return startDir;
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* Create a wrapper script that injects secrets before importing the entry file.
|
|
1543
|
+
* @internal Exported for testing
|
|
1544
|
+
*/
|
|
1545
|
+
async function createEntryWrapper(wrapperPath, entryPath, secretsJsonPath) {
|
|
1546
|
+
const credentialsInjection = secretsJsonPath ? `import { Credentials } from '@geekmidas/envkit/credentials';
|
|
1547
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
1548
|
+
|
|
1549
|
+
// Inject dev secrets into Credentials (before app import)
|
|
1550
|
+
const secretsPath = '${secretsJsonPath}';
|
|
1551
|
+
if (existsSync(secretsPath)) {
|
|
1552
|
+
Object.assign(Credentials, JSON.parse(readFileSync(secretsPath, 'utf-8')));
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
` : "";
|
|
1556
|
+
const content = `#!/usr/bin/env node
|
|
1557
|
+
/**
|
|
1558
|
+
* Entry wrapper generated by 'gkm dev --entry'
|
|
1559
|
+
*/
|
|
1560
|
+
${credentialsInjection}// Import and run the user's entry file (dynamic import ensures secrets load first)
|
|
1561
|
+
await import('${entryPath}');
|
|
1562
|
+
`;
|
|
1563
|
+
await writeFile(wrapperPath, content);
|
|
1564
|
+
}
|
|
1565
|
+
/**
|
|
1566
|
+
* Run any TypeScript file with secret injection.
|
|
1567
|
+
* Does not require gkm.config.ts.
|
|
1568
|
+
*/
|
|
1569
|
+
async function entryDevCommand(options) {
|
|
1570
|
+
const { entry, port = 3e3, watch = true } = options;
|
|
1571
|
+
if (!entry) throw new Error("--entry requires a file path");
|
|
1572
|
+
const entryPath = resolve(process.cwd(), entry);
|
|
1573
|
+
if (!existsSync(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
|
|
1574
|
+
logger$8.log(`š Starting entry file: ${entry}`);
|
|
1575
|
+
const defaultEnv = loadEnvFiles(".env");
|
|
1576
|
+
if (defaultEnv.loaded.length > 0) logger$8.log(`š¦ Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1577
|
+
const secretsRoot = findSecretsRoot(process.cwd());
|
|
1578
|
+
logger$8.log(`š Secrets root: ${secretsRoot}`);
|
|
1579
|
+
const appName = getAppNameFromCwd() ?? void 0;
|
|
1580
|
+
if (appName) logger$8.log(`š¦ App name: ${appName}`);
|
|
1581
|
+
const appSecrets = await loadSecretsForApp(secretsRoot, appName);
|
|
1582
|
+
if (Object.keys(appSecrets).length > 0) logger$8.log(`š Loaded ${Object.keys(appSecrets).length} secret(s)`);
|
|
1583
|
+
else logger$8.log(`ā ļø No secrets found in ${secretsRoot}/.gkm/secrets/`);
|
|
1584
|
+
let secretsJsonPath;
|
|
1585
|
+
if (Object.keys(appSecrets).length > 0) {
|
|
1586
|
+
const secretsDir = join(secretsRoot, ".gkm");
|
|
1587
|
+
await mkdir(secretsDir, { recursive: true });
|
|
1588
|
+
secretsJsonPath = join(secretsDir, "dev-secrets.json");
|
|
1589
|
+
await writeFile(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
|
|
1590
|
+
}
|
|
1591
|
+
const wrapperDir = join(process.cwd(), ".gkm");
|
|
1592
|
+
await mkdir(wrapperDir, { recursive: true });
|
|
1593
|
+
const wrapperPath = join(wrapperDir, "entry-wrapper.ts");
|
|
1594
|
+
await createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);
|
|
1595
|
+
const runner = new EntryRunner(wrapperPath, entryPath, watch, port);
|
|
1596
|
+
await runner.start();
|
|
1597
|
+
let isShuttingDown = false;
|
|
1598
|
+
const shutdown = () => {
|
|
1599
|
+
if (isShuttingDown) return;
|
|
1600
|
+
isShuttingDown = true;
|
|
1601
|
+
logger$8.log("\nš Shutting down...");
|
|
1602
|
+
runner.stop();
|
|
1603
|
+
process.exit(0);
|
|
1604
|
+
};
|
|
1605
|
+
process.on("SIGINT", shutdown);
|
|
1606
|
+
process.on("SIGTERM", shutdown);
|
|
1607
|
+
await new Promise(() => {});
|
|
1608
|
+
}
|
|
1609
|
+
/**
|
|
1610
|
+
* Runs and watches a TypeScript entry file using tsx.
|
|
1611
|
+
*/
|
|
1612
|
+
var EntryRunner = class {
|
|
1613
|
+
childProcess = null;
|
|
1614
|
+
watcher = null;
|
|
1615
|
+
isRunning = false;
|
|
1616
|
+
constructor(wrapperPath, entryPath, watch, port) {
|
|
1617
|
+
this.wrapperPath = wrapperPath;
|
|
1618
|
+
this.entryPath = entryPath;
|
|
1619
|
+
this.watch = watch;
|
|
1620
|
+
this.port = port;
|
|
1621
|
+
}
|
|
1622
|
+
async start() {
|
|
1623
|
+
await this.runProcess();
|
|
1624
|
+
if (this.watch) {
|
|
1625
|
+
const watchDir = dirname(this.entryPath);
|
|
1626
|
+
this.watcher = chokidar.watch(watchDir, {
|
|
1627
|
+
ignored: /(^|[/\\])\../,
|
|
1628
|
+
persistent: true,
|
|
1629
|
+
ignoreInitial: true
|
|
1630
|
+
});
|
|
1631
|
+
let restartTimeout = null;
|
|
1632
|
+
this.watcher.on("change", (path) => {
|
|
1633
|
+
logger$8.log(`š File changed: ${path}`);
|
|
1634
|
+
if (restartTimeout) clearTimeout(restartTimeout);
|
|
1635
|
+
restartTimeout = setTimeout(async () => {
|
|
1636
|
+
logger$8.log("š Restarting...");
|
|
1637
|
+
await this.restart();
|
|
1638
|
+
}, 300);
|
|
1639
|
+
});
|
|
1640
|
+
logger$8.log(`š Watching for changes in: ${watchDir}`);
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
async runProcess() {
|
|
1644
|
+
const env = {
|
|
1645
|
+
...process.env,
|
|
1646
|
+
PORT: String(this.port)
|
|
1647
|
+
};
|
|
1648
|
+
this.childProcess = spawn("npx", ["tsx", this.wrapperPath], {
|
|
1649
|
+
stdio: "inherit",
|
|
1650
|
+
env,
|
|
1651
|
+
detached: true
|
|
1652
|
+
});
|
|
1653
|
+
this.isRunning = true;
|
|
1654
|
+
this.childProcess.on("error", (error) => {
|
|
1655
|
+
logger$8.error("ā Process error:", error);
|
|
1656
|
+
});
|
|
1657
|
+
this.childProcess.on("exit", (code) => {
|
|
1658
|
+
if (code !== null && code !== 0 && code !== 143) logger$8.error(`ā Process exited with code ${code}`);
|
|
1659
|
+
this.isRunning = false;
|
|
1660
|
+
});
|
|
1661
|
+
await new Promise((resolve$1) => setTimeout(resolve$1, 500));
|
|
1662
|
+
if (this.isRunning) logger$8.log(`\nš Running at http://localhost:${this.port}`);
|
|
1663
|
+
}
|
|
1664
|
+
async restart() {
|
|
1665
|
+
this.stopProcess();
|
|
1666
|
+
await new Promise((resolve$1) => setTimeout(resolve$1, 500));
|
|
1667
|
+
await this.runProcess();
|
|
1668
|
+
}
|
|
1669
|
+
stop() {
|
|
1670
|
+
this.watcher?.close();
|
|
1671
|
+
this.stopProcess();
|
|
1672
|
+
}
|
|
1673
|
+
stopProcess() {
|
|
1674
|
+
if (this.childProcess && this.isRunning) {
|
|
1675
|
+
const pid = this.childProcess.pid;
|
|
1676
|
+
if (pid) try {
|
|
1677
|
+
process.kill(-pid, "SIGTERM");
|
|
1678
|
+
} catch {
|
|
1679
|
+
try {
|
|
1680
|
+
process.kill(pid, "SIGTERM");
|
|
1681
|
+
} catch {}
|
|
1682
|
+
}
|
|
1683
|
+
this.childProcess = null;
|
|
1684
|
+
this.isRunning = false;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1525
1688
|
var DevServer = class {
|
|
1526
1689
|
serverProcess = null;
|
|
1527
1690
|
isRunning = false;
|
|
@@ -4332,7 +4495,7 @@ const GEEKMIDAS_VERSIONS = {
|
|
|
4332
4495
|
"@geekmidas/constructs": "~0.6.0",
|
|
4333
4496
|
"@geekmidas/db": "~0.3.0",
|
|
4334
4497
|
"@geekmidas/emailkit": "~0.2.0",
|
|
4335
|
-
"@geekmidas/envkit": "~0.
|
|
4498
|
+
"@geekmidas/envkit": "~0.5.0",
|
|
4336
4499
|
"@geekmidas/errors": "~0.1.0",
|
|
4337
4500
|
"@geekmidas/events": "~0.2.0",
|
|
4338
4501
|
"@geekmidas/logger": "~0.4.0",
|
|
@@ -4361,7 +4524,7 @@ function generateAuthAppFiles(options) {
|
|
|
4361
4524
|
private: true,
|
|
4362
4525
|
type: "module",
|
|
4363
4526
|
scripts: {
|
|
4364
|
-
dev: "
|
|
4527
|
+
dev: "gkm dev --entry ./src/index.ts",
|
|
4365
4528
|
build: "tsc",
|
|
4366
4529
|
start: "node dist/index.js",
|
|
4367
4530
|
typecheck: "tsc --noEmit"
|
|
@@ -4377,6 +4540,7 @@ function generateAuthAppFiles(options) {
|
|
|
4377
4540
|
pg: "~8.13.0"
|
|
4378
4541
|
},
|
|
4379
4542
|
devDependencies: {
|
|
4543
|
+
"@geekmidas/cli": GEEKMIDAS_VERSIONS["@geekmidas/cli"],
|
|
4380
4544
|
"@types/node": "~22.0.0",
|
|
4381
4545
|
"@types/pg": "~8.11.0",
|
|
4382
4546
|
tsx: "~4.20.0",
|
|
@@ -7218,14 +7382,16 @@ program.command("build").description("Build handlers from endpoints, functions,
|
|
|
7218
7382
|
process.exit(1);
|
|
7219
7383
|
}
|
|
7220
7384
|
});
|
|
7221
|
-
program.command("dev").description("Start development server with automatic reload").option("-p, --port <port>", "Port to run the development server on").option("--enable-openapi", "Enable OpenAPI documentation for development server", true).action(async (options) => {
|
|
7385
|
+
program.command("dev").description("Start development server with automatic reload").option("-p, --port <port>", "Port to run the development server on").option("--entry <file>", "Entry file to run (bypasses gkm config)").option("--watch", "Watch for file changes (default: true with --entry)").option("--no-watch", "Disable file watching").option("--enable-openapi", "Enable OpenAPI documentation for development server", true).action(async (options) => {
|
|
7222
7386
|
try {
|
|
7223
7387
|
const globalOptions = program.opts();
|
|
7224
7388
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
7225
7389
|
await devCommand({
|
|
7226
7390
|
port: options.port ? Number.parseInt(options.port, 10) : 3e3,
|
|
7227
7391
|
portExplicit: !!options.port,
|
|
7228
|
-
enableOpenApi: options.enableOpenapi ?? true
|
|
7392
|
+
enableOpenApi: options.enableOpenapi ?? true,
|
|
7393
|
+
entry: options.entry,
|
|
7394
|
+
watch: options.watch
|
|
7229
7395
|
});
|
|
7230
7396
|
} catch (error) {
|
|
7231
7397
|
console.error(error instanceof Error ? error.message : "Command failed");
|