@geekmidas/cli 0.38.0 → 0.39.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 +154 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +135 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/build/index.ts +23 -6
- package/src/deploy/docker.ts +20 -20
- package/src/deploy/index.ts +20 -19
- package/src/dev/index.ts +144 -9
- package/src/index.ts +18 -1
- package/src/init/generators/auth.ts +2 -0
package/dist/index.cjs
CHANGED
|
@@ -240,7 +240,7 @@ async function prompt$1(message, hidden = false) {
|
|
|
240
240
|
if (!process.stdin.isTTY) throw new Error("Interactive input required. Please provide --token option.");
|
|
241
241
|
if (hidden) {
|
|
242
242
|
process.stdout.write(message);
|
|
243
|
-
return new Promise((resolve$
|
|
243
|
+
return new Promise((resolve$2, reject) => {
|
|
244
244
|
let value = "";
|
|
245
245
|
const cleanup = () => {
|
|
246
246
|
process.stdin.setRawMode(false);
|
|
@@ -257,7 +257,7 @@ async function prompt$1(message, hidden = false) {
|
|
|
257
257
|
if (c === "\n" || c === "\r") {
|
|
258
258
|
cleanup();
|
|
259
259
|
process.stdout.write("\n");
|
|
260
|
-
resolve$
|
|
260
|
+
resolve$2(value);
|
|
261
261
|
} else if (c === "") {
|
|
262
262
|
cleanup();
|
|
263
263
|
process.stdout.write("\n");
|
|
@@ -892,15 +892,15 @@ function loadEnvFiles(envConfig, cwd = process.cwd()) {
|
|
|
892
892
|
* @internal Exported for testing
|
|
893
893
|
*/
|
|
894
894
|
async function isPortAvailable(port) {
|
|
895
|
-
return new Promise((resolve$
|
|
895
|
+
return new Promise((resolve$2) => {
|
|
896
896
|
const server = (0, node_net.createServer)();
|
|
897
897
|
server.once("error", (err) => {
|
|
898
|
-
if (err.code === "EADDRINUSE") resolve$
|
|
899
|
-
else resolve$
|
|
898
|
+
if (err.code === "EADDRINUSE") resolve$2(false);
|
|
899
|
+
else resolve$2(false);
|
|
900
900
|
});
|
|
901
901
|
server.once("listening", () => {
|
|
902
902
|
server.close();
|
|
903
|
-
resolve$
|
|
903
|
+
resolve$2(true);
|
|
904
904
|
});
|
|
905
905
|
server.listen(port);
|
|
906
906
|
});
|
|
@@ -1491,7 +1491,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1491
1491
|
};
|
|
1492
1492
|
process.on("SIGINT", shutdown);
|
|
1493
1493
|
process.on("SIGTERM", shutdown);
|
|
1494
|
-
return new Promise((resolve$
|
|
1494
|
+
return new Promise((resolve$2, reject) => {
|
|
1495
1495
|
turboProcess.on("error", (error) => {
|
|
1496
1496
|
logger$8.error("❌ Turbo error:", error);
|
|
1497
1497
|
reject(error);
|
|
@@ -1499,7 +1499,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1499
1499
|
turboProcess.on("exit", (code) => {
|
|
1500
1500
|
if (endpointWatcher) endpointWatcher.close().catch(() => {});
|
|
1501
1501
|
if (code !== null && code !== 0) reject(new Error(`Turbo exited with code ${code}`));
|
|
1502
|
-
else resolve$
|
|
1502
|
+
else resolve$2();
|
|
1503
1503
|
});
|
|
1504
1504
|
});
|
|
1505
1505
|
}
|
|
@@ -1542,19 +1542,43 @@ function findSecretsRoot(startDir) {
|
|
|
1542
1542
|
return startDir;
|
|
1543
1543
|
}
|
|
1544
1544
|
/**
|
|
1545
|
-
*
|
|
1546
|
-
*
|
|
1545
|
+
* Generate the credentials injection code snippet.
|
|
1546
|
+
* This is the common logic used by both entry wrapper and exec preload.
|
|
1547
|
+
* @internal
|
|
1547
1548
|
*/
|
|
1548
|
-
|
|
1549
|
-
|
|
1549
|
+
function generateCredentialsInjection(secretsJsonPath) {
|
|
1550
|
+
return `import { Credentials } from '@geekmidas/envkit/credentials';
|
|
1550
1551
|
import { existsSync, readFileSync } from 'node:fs';
|
|
1551
1552
|
|
|
1552
|
-
// Inject dev secrets into Credentials
|
|
1553
|
+
// Inject dev secrets into Credentials
|
|
1553
1554
|
const secretsPath = '${secretsJsonPath}';
|
|
1554
1555
|
if (existsSync(secretsPath)) {
|
|
1555
|
-
|
|
1556
|
+
const secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));
|
|
1557
|
+
Object.assign(Credentials, secrets);
|
|
1558
|
+
// Debug: uncomment to verify preload is running
|
|
1559
|
+
// console.log('[gkm preload] Injected', Object.keys(secrets).length, 'credentials');
|
|
1556
1560
|
}
|
|
1557
|
-
|
|
1561
|
+
`;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Create a preload script that injects secrets into Credentials.
|
|
1565
|
+
* Used by `gkm exec` to inject secrets before running any command.
|
|
1566
|
+
* @internal Exported for testing
|
|
1567
|
+
*/
|
|
1568
|
+
async function createCredentialsPreload(preloadPath, secretsJsonPath) {
|
|
1569
|
+
const content = `/**
|
|
1570
|
+
* Credentials preload generated by 'gkm exec'
|
|
1571
|
+
* This file is loaded via NODE_OPTIONS="--import <path>"
|
|
1572
|
+
*/
|
|
1573
|
+
${generateCredentialsInjection(secretsJsonPath)}`;
|
|
1574
|
+
await (0, node_fs_promises.writeFile)(preloadPath, content);
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Create a wrapper script that injects secrets before importing the entry file.
|
|
1578
|
+
* @internal Exported for testing
|
|
1579
|
+
*/
|
|
1580
|
+
async function createEntryWrapper(wrapperPath, entryPath, secretsJsonPath) {
|
|
1581
|
+
const credentialsInjection = secretsJsonPath ? `${generateCredentialsInjection(secretsJsonPath)}
|
|
1558
1582
|
` : "";
|
|
1559
1583
|
const content = `#!/usr/bin/env node
|
|
1560
1584
|
/**
|
|
@@ -1685,12 +1709,12 @@ var EntryRunner = class {
|
|
|
1685
1709
|
if (code !== null && code !== 0 && code !== 143) logger$8.error(`❌ Process exited with code ${code}`);
|
|
1686
1710
|
this.isRunning = false;
|
|
1687
1711
|
});
|
|
1688
|
-
await new Promise((resolve$
|
|
1712
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, 500));
|
|
1689
1713
|
if (this.isRunning) logger$8.log(`\n🎉 Running at http://localhost:${this.port}`);
|
|
1690
1714
|
}
|
|
1691
1715
|
async restart() {
|
|
1692
1716
|
this.stopProcess();
|
|
1693
|
-
await new Promise((resolve$
|
|
1717
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, 500));
|
|
1694
1718
|
await this.runProcess();
|
|
1695
1719
|
}
|
|
1696
1720
|
stop() {
|
|
@@ -1762,7 +1786,7 @@ var DevServer = class {
|
|
|
1762
1786
|
if (code !== null && code !== 0 && signal !== "SIGTERM") logger$8.error(`❌ Server exited with code ${code}`);
|
|
1763
1787
|
this.isRunning = false;
|
|
1764
1788
|
});
|
|
1765
|
-
await new Promise((resolve$
|
|
1789
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, 1e3));
|
|
1766
1790
|
if (this.isRunning) {
|
|
1767
1791
|
logger$8.log(`\n🎉 Server running at http://localhost:${this.actualPort}`);
|
|
1768
1792
|
if (this.enableOpenApi) logger$8.log(`📚 API Docs available at http://localhost:${this.actualPort}/__docs`);
|
|
@@ -1797,7 +1821,7 @@ var DevServer = class {
|
|
|
1797
1821
|
let attempts = 0;
|
|
1798
1822
|
while (attempts < 30) {
|
|
1799
1823
|
if (await isPortAvailable(portToReuse)) break;
|
|
1800
|
-
await new Promise((resolve$
|
|
1824
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, 100));
|
|
1801
1825
|
attempts++;
|
|
1802
1826
|
}
|
|
1803
1827
|
this.requestedPort = portToReuse;
|
|
@@ -1805,9 +1829,9 @@ var DevServer = class {
|
|
|
1805
1829
|
}
|
|
1806
1830
|
async createServerEntry() {
|
|
1807
1831
|
const { writeFile: fsWriteFile } = await import("node:fs/promises");
|
|
1808
|
-
const { relative: relative$
|
|
1832
|
+
const { relative: relative$6, dirname: dirname$8 } = await import("node:path");
|
|
1809
1833
|
const serverPath = (0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts");
|
|
1810
|
-
const relativeAppPath = relative$
|
|
1834
|
+
const relativeAppPath = relative$6(dirname$8(serverPath), (0, node_path.join)(dirname$8(serverPath), "app.js"));
|
|
1811
1835
|
const credentialsInjection = this.secretsJsonPath ? `import { Credentials } from '@geekmidas/envkit/credentials';
|
|
1812
1836
|
import { existsSync, readFileSync } from 'node:fs';
|
|
1813
1837
|
|
|
@@ -1860,6 +1884,59 @@ start({
|
|
|
1860
1884
|
await fsWriteFile(serverPath, content);
|
|
1861
1885
|
}
|
|
1862
1886
|
};
|
|
1887
|
+
/**
|
|
1888
|
+
* Run a command with secrets injected into Credentials.
|
|
1889
|
+
* Uses Node's --import flag to preload a script that populates Credentials
|
|
1890
|
+
* before the command loads any modules that depend on them.
|
|
1891
|
+
*
|
|
1892
|
+
* @example
|
|
1893
|
+
* ```bash
|
|
1894
|
+
* gkm exec -- npx @better-auth/cli migrate
|
|
1895
|
+
* gkm exec -- npx prisma migrate dev
|
|
1896
|
+
* ```
|
|
1897
|
+
*/
|
|
1898
|
+
async function execCommand(commandArgs, options = {}) {
|
|
1899
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1900
|
+
if (commandArgs.length === 0) throw new Error("No command specified. Usage: gkm exec -- <command>");
|
|
1901
|
+
const defaultEnv = loadEnvFiles(".env");
|
|
1902
|
+
if (defaultEnv.loaded.length > 0) logger$8.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1903
|
+
const { credentials, secretsJsonPath, appName } = await prepareEntryCredentials({ cwd });
|
|
1904
|
+
if (appName) logger$8.log(`📦 App: ${appName}`);
|
|
1905
|
+
const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
|
|
1906
|
+
if (secretCount > 0) logger$8.log(`🔐 Loaded ${secretCount} secret(s)`);
|
|
1907
|
+
const preloadDir = (0, node_path.join)(cwd, ".gkm");
|
|
1908
|
+
await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
|
|
1909
|
+
const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.ts");
|
|
1910
|
+
await createCredentialsPreload(preloadPath, secretsJsonPath);
|
|
1911
|
+
const [cmd, ...args] = commandArgs;
|
|
1912
|
+
if (!cmd) throw new Error("No command specified");
|
|
1913
|
+
logger$8.log(`🚀 Running: ${commandArgs.join(" ")}`);
|
|
1914
|
+
const existingNodeOptions = process.env.NODE_OPTIONS ?? "";
|
|
1915
|
+
const tsxImport = "--import tsx";
|
|
1916
|
+
const preloadImport = `--import ${preloadPath}`;
|
|
1917
|
+
const nodeOptions = [
|
|
1918
|
+
existingNodeOptions,
|
|
1919
|
+
tsxImport,
|
|
1920
|
+
preloadImport
|
|
1921
|
+
].filter(Boolean).join(" ");
|
|
1922
|
+
const child = (0, node_child_process.spawn)(cmd, args, {
|
|
1923
|
+
cwd,
|
|
1924
|
+
stdio: "inherit",
|
|
1925
|
+
env: {
|
|
1926
|
+
...process.env,
|
|
1927
|
+
...credentials,
|
|
1928
|
+
NODE_OPTIONS: nodeOptions
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
const exitCode = await new Promise((resolve$2) => {
|
|
1932
|
+
child.on("close", (code) => resolve$2(code ?? 0));
|
|
1933
|
+
child.on("error", (error) => {
|
|
1934
|
+
logger$8.error(`Failed to run command: ${error.message}`);
|
|
1935
|
+
resolve$2(1);
|
|
1936
|
+
});
|
|
1937
|
+
});
|
|
1938
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
1939
|
+
}
|
|
1863
1940
|
|
|
1864
1941
|
//#endregion
|
|
1865
1942
|
//#region src/build/manifests.ts
|
|
@@ -1930,10 +2007,15 @@ const logger$6 = console;
|
|
|
1930
2007
|
async function buildCommand(options) {
|
|
1931
2008
|
const loadedConfig = await require_config.loadWorkspaceConfig();
|
|
1932
2009
|
if (loadedConfig.type === "workspace") {
|
|
1933
|
-
|
|
1934
|
-
|
|
2010
|
+
const cwd = (0, node_path.resolve)(process.cwd());
|
|
2011
|
+
const workspaceRoot = (0, node_path.resolve)(loadedConfig.workspace.root);
|
|
2012
|
+
const isAtWorkspaceRoot = cwd === workspaceRoot;
|
|
2013
|
+
if (isAtWorkspaceRoot) {
|
|
2014
|
+
logger$6.log("📦 Detected workspace configuration");
|
|
2015
|
+
return workspaceBuildCommand(loadedConfig.workspace, options);
|
|
2016
|
+
}
|
|
1935
2017
|
}
|
|
1936
|
-
const config = await require_config.loadConfig();
|
|
2018
|
+
const config = loadedConfig.type === "workspace" ? (await require_config.loadAppConfig()).gkmConfig : await require_config.loadConfig();
|
|
1937
2019
|
const resolved = resolveProviders(config, options);
|
|
1938
2020
|
const productionConfigFromGkm = getProductionConfigFromGkm(config);
|
|
1939
2021
|
const production = normalizeProductionConfig(options.production ?? false, productionConfigFromGkm);
|
|
@@ -2099,7 +2181,7 @@ async function workspaceBuildCommand(workspace, options) {
|
|
|
2099
2181
|
try {
|
|
2100
2182
|
const turboCommand = getTurboCommand(pm);
|
|
2101
2183
|
logger$6.log(`Running: ${turboCommand}`);
|
|
2102
|
-
await new Promise((resolve$
|
|
2184
|
+
await new Promise((resolve$2, reject) => {
|
|
2103
2185
|
const child = (0, node_child_process.spawn)(turboCommand, {
|
|
2104
2186
|
shell: true,
|
|
2105
2187
|
cwd: workspace.root,
|
|
@@ -2110,7 +2192,7 @@ async function workspaceBuildCommand(workspace, options) {
|
|
|
2110
2192
|
}
|
|
2111
2193
|
});
|
|
2112
2194
|
child.on("close", (code) => {
|
|
2113
|
-
if (code === 0) resolve$
|
|
2195
|
+
if (code === 0) resolve$2();
|
|
2114
2196
|
else reject(new Error(`Turbo build failed with exit code ${code}`));
|
|
2115
2197
|
});
|
|
2116
2198
|
child.on("error", (err) => {
|
|
@@ -3377,26 +3459,22 @@ function getImageRef(registry, imageName, tag) {
|
|
|
3377
3459
|
}
|
|
3378
3460
|
/**
|
|
3379
3461
|
* Build Docker image
|
|
3462
|
+
* @param imageRef - Full image reference (registry/name:tag)
|
|
3463
|
+
* @param appName - Name of the app (used for Dockerfile.{appName} in workspaces)
|
|
3380
3464
|
*/
|
|
3381
|
-
async function buildImage(imageRef) {
|
|
3465
|
+
async function buildImage(imageRef, appName) {
|
|
3382
3466
|
logger$4.log(`\n🔨 Building Docker image: ${imageRef}`);
|
|
3383
3467
|
const cwd = process.cwd();
|
|
3384
|
-
const
|
|
3385
|
-
|
|
3468
|
+
const lockfilePath = findLockfilePath(cwd);
|
|
3469
|
+
const lockfileDir = lockfilePath ? (0, node_path.dirname)(lockfilePath) : cwd;
|
|
3470
|
+
const inMonorepo = lockfileDir !== cwd;
|
|
3471
|
+
if (appName || inMonorepo) logger$4.log(" Generating Dockerfile for monorepo (turbo prune)...");
|
|
3386
3472
|
else logger$4.log(" Generating Dockerfile...");
|
|
3387
3473
|
await dockerCommand({});
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
if (lockfilePath) {
|
|
3393
|
-
const monorepoRoot = (0, node_path.dirname)(lockfilePath);
|
|
3394
|
-
const appRelPath = (0, node_path.relative)(monorepoRoot, cwd);
|
|
3395
|
-
dockerfilePath = (0, node_path.join)(appRelPath, ".gkm/docker/Dockerfile");
|
|
3396
|
-
buildCwd = monorepoRoot;
|
|
3397
|
-
logger$4.log(` Building from monorepo root: ${monorepoRoot}`);
|
|
3398
|
-
}
|
|
3399
|
-
}
|
|
3474
|
+
const dockerfileSuffix = appName ? `.${appName}` : "";
|
|
3475
|
+
const dockerfilePath = `.gkm/docker/Dockerfile${dockerfileSuffix}`;
|
|
3476
|
+
const buildCwd = lockfilePath && (inMonorepo || appName) ? lockfileDir : cwd;
|
|
3477
|
+
if (buildCwd !== cwd) logger$4.log(` Building from workspace root: ${buildCwd}`);
|
|
3400
3478
|
try {
|
|
3401
3479
|
(0, node_child_process.execSync)(`DOCKER_BUILDKIT=1 docker build --platform linux/amd64 -f ${dockerfilePath} -t ${imageRef} .`, {
|
|
3402
3480
|
cwd: buildCwd,
|
|
@@ -3433,7 +3511,7 @@ async function deployDocker(options) {
|
|
|
3433
3511
|
const { stage, tag, skipPush, masterKey, config } = options;
|
|
3434
3512
|
const imageName = config.imageName;
|
|
3435
3513
|
const imageRef = getImageRef(config.registry, imageName, tag);
|
|
3436
|
-
await buildImage(imageRef);
|
|
3514
|
+
await buildImage(imageRef, config.appName);
|
|
3437
3515
|
if (!skipPush) if (!config.registry) logger$4.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
|
|
3438
3516
|
else await pushImage(imageRef);
|
|
3439
3517
|
logger$4.log("\n✅ Docker deployment ready!");
|
|
@@ -3737,7 +3815,7 @@ async function prompt(message, hidden = false) {
|
|
|
3737
3815
|
if (!process.stdin.isTTY) throw new Error("Interactive input required. Please configure manually.");
|
|
3738
3816
|
if (hidden) {
|
|
3739
3817
|
process.stdout.write(message);
|
|
3740
|
-
return new Promise((resolve$
|
|
3818
|
+
return new Promise((resolve$2) => {
|
|
3741
3819
|
let value = "";
|
|
3742
3820
|
const onData = (char) => {
|
|
3743
3821
|
const c = char.toString();
|
|
@@ -3746,7 +3824,7 @@ async function prompt(message, hidden = false) {
|
|
|
3746
3824
|
process.stdin.pause();
|
|
3747
3825
|
process.stdin.removeListener("data", onData);
|
|
3748
3826
|
process.stdout.write("\n");
|
|
3749
|
-
resolve$
|
|
3827
|
+
resolve$2(value);
|
|
3750
3828
|
} else if (c === "") {
|
|
3751
3829
|
process.stdin.setRawMode(false);
|
|
3752
3830
|
process.stdin.pause();
|
|
@@ -4145,11 +4223,25 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
4145
4223
|
await provisionServices(api, project.projectId, environmentId, workspace.name, dockerServices);
|
|
4146
4224
|
}
|
|
4147
4225
|
const deployedAppUrls = {};
|
|
4226
|
+
if (!skipBuild) {
|
|
4227
|
+
logger$1.log("\n🏗️ Building workspace...");
|
|
4228
|
+
try {
|
|
4229
|
+
await buildCommand({
|
|
4230
|
+
provider: "server",
|
|
4231
|
+
production: true,
|
|
4232
|
+
stage
|
|
4233
|
+
});
|
|
4234
|
+
logger$1.log(" ✓ Workspace build complete");
|
|
4235
|
+
} catch (error) {
|
|
4236
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
4237
|
+
logger$1.log(` ✗ Workspace build failed: ${message}`);
|
|
4238
|
+
throw error;
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4148
4241
|
logger$1.log("\n📦 Deploying applications...");
|
|
4149
4242
|
const results = [];
|
|
4150
4243
|
for (const appName of appsToDeployNames) {
|
|
4151
4244
|
const app = workspace.apps[appName];
|
|
4152
|
-
const appPath = app.path;
|
|
4153
4245
|
logger$1.log(`\n ${app.type === "backend" ? "⚙️" : "🌐"} Deploying ${appName}...`);
|
|
4154
4246
|
try {
|
|
4155
4247
|
const dokployAppName = `${workspace.name}-${appName}`;
|
|
@@ -4162,21 +4254,6 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
4162
4254
|
if (message.includes("already exists") || message.includes("duplicate")) logger$1.log(` Application already exists`);
|
|
4163
4255
|
else throw error;
|
|
4164
4256
|
}
|
|
4165
|
-
if (!skipBuild) {
|
|
4166
|
-
logger$1.log(` Building ${appName}...`);
|
|
4167
|
-
const originalCwd = process.cwd();
|
|
4168
|
-
const fullAppPath = `${workspace.root}/${appPath}`;
|
|
4169
|
-
try {
|
|
4170
|
-
process.chdir(fullAppPath);
|
|
4171
|
-
await buildCommand({
|
|
4172
|
-
provider: "server",
|
|
4173
|
-
production: true,
|
|
4174
|
-
stage
|
|
4175
|
-
});
|
|
4176
|
-
} finally {
|
|
4177
|
-
process.chdir(originalCwd);
|
|
4178
|
-
}
|
|
4179
|
-
}
|
|
4180
4257
|
const imageName = `${workspace.name}-${appName}`;
|
|
4181
4258
|
const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
|
|
4182
4259
|
logger$1.log(` Building Docker image: ${imageRef}`);
|
|
@@ -4186,7 +4263,8 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
4186
4263
|
skipPush: false,
|
|
4187
4264
|
config: {
|
|
4188
4265
|
registry,
|
|
4189
|
-
imageName
|
|
4266
|
+
imageName,
|
|
4267
|
+
appName
|
|
4190
4268
|
}
|
|
4191
4269
|
});
|
|
4192
4270
|
const envVars = [`NODE_ENV=production`, `PORT=${app.port}`];
|
|
@@ -4554,7 +4632,9 @@ function generateAuthAppFiles(options) {
|
|
|
4554
4632
|
dev: "gkm dev --entry ./src/index.ts",
|
|
4555
4633
|
build: "tsc",
|
|
4556
4634
|
start: "node dist/index.js",
|
|
4557
|
-
typecheck: "tsc --noEmit"
|
|
4635
|
+
typecheck: "tsc --noEmit",
|
|
4636
|
+
"db:migrate": "gkm exec -- npx @better-auth/cli migrate",
|
|
4637
|
+
"db:generate": "gkm exec -- npx @better-auth/cli generate"
|
|
4558
4638
|
},
|
|
4559
4639
|
dependencies: {
|
|
4560
4640
|
[modelsPackage]: "workspace:*",
|
|
@@ -7394,9 +7474,9 @@ async function testCommand(options = {}) {
|
|
|
7394
7474
|
NODE_ENV: "test"
|
|
7395
7475
|
}
|
|
7396
7476
|
});
|
|
7397
|
-
return new Promise((resolve$
|
|
7477
|
+
return new Promise((resolve$2, reject) => {
|
|
7398
7478
|
vitestProcess.on("close", (code) => {
|
|
7399
|
-
if (code === 0) resolve$
|
|
7479
|
+
if (code === 0) resolve$2();
|
|
7400
7480
|
else reject(new Error(`Tests failed with exit code ${code}`));
|
|
7401
7481
|
});
|
|
7402
7482
|
vitestProcess.on("error", (error) => {
|
|
@@ -7468,6 +7548,16 @@ program.command("dev").description("Start development server with automatic relo
|
|
|
7468
7548
|
process.exit(1);
|
|
7469
7549
|
}
|
|
7470
7550
|
});
|
|
7551
|
+
program.command("exec").description("Run a command with secrets injected into Credentials").argument("<command...>", "Command to run (use -- before command)").action(async (commandArgs) => {
|
|
7552
|
+
try {
|
|
7553
|
+
const globalOptions = program.opts();
|
|
7554
|
+
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
7555
|
+
await execCommand(commandArgs);
|
|
7556
|
+
} catch (error) {
|
|
7557
|
+
console.error(error instanceof Error ? error.message : "Command failed");
|
|
7558
|
+
process.exit(1);
|
|
7559
|
+
}
|
|
7560
|
+
});
|
|
7471
7561
|
program.command("test").description("Run tests with secrets loaded from environment").option("--stage <stage>", "Stage to load secrets from", "development").option("--run", "Run tests once without watch mode").option("--watch", "Enable watch mode").option("--coverage", "Generate coverage report").option("--ui", "Open Vitest UI").argument("[pattern]", "Pattern to filter tests").action(async (pattern, options) => {
|
|
7472
7562
|
try {
|
|
7473
7563
|
const globalOptions = program.opts();
|