@geekmidas/cli 1.9.0 → 1.9.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.
- package/CHANGELOG.md +6 -0
- package/dist/{HostingerProvider-CEsQbmpY.cjs → HostingerProvider-5KYmwoK2.cjs} +1 -1
- package/dist/{HostingerProvider-CEsQbmpY.cjs.map → HostingerProvider-5KYmwoK2.cjs.map} +1 -1
- package/dist/{HostingerProvider-DkahM5AP.mjs → HostingerProvider-ANWchdiK.mjs} +1 -1
- package/dist/{HostingerProvider-DkahM5AP.mjs.map → HostingerProvider-ANWchdiK.mjs.map} +1 -1
- package/dist/{LocalStateProvider-Roi202l7.cjs → LocalStateProvider-CLifRC0Y.cjs} +1 -1
- package/dist/{LocalStateProvider-Roi202l7.cjs.map → LocalStateProvider-CLifRC0Y.cjs.map} +1 -1
- package/dist/{LocalStateProvider-DXIwWb7k.mjs → LocalStateProvider-Dp0KkRcw.mjs} +1 -1
- package/dist/{LocalStateProvider-DXIwWb7k.mjs.map → LocalStateProvider-Dp0KkRcw.mjs.map} +1 -1
- package/dist/{Route53Provider-Ckq_n5Be.mjs → Route53Provider-QoPgcXxn.mjs} +1 -1
- package/dist/{Route53Provider-Ckq_n5Be.mjs.map → Route53Provider-QoPgcXxn.mjs.map} +1 -1
- package/dist/{Route53Provider-BqXeHzuc.cjs → Route53Provider-owQQ4pn6.cjs} +1 -1
- package/dist/{Route53Provider-BqXeHzuc.cjs.map → Route53Provider-owQQ4pn6.cjs.map} +1 -1
- package/dist/{SSMStateProvider-BReQA5re.cjs → SSMStateProvider-CT8tjl9o.cjs} +1 -1
- package/dist/{SSMStateProvider-BReQA5re.cjs.map → SSMStateProvider-CT8tjl9o.cjs.map} +1 -1
- package/dist/{SSMStateProvider-wddd0_-d.mjs → SSMStateProvider-CksOTB8M.mjs} +1 -1
- package/dist/{SSMStateProvider-wddd0_-d.mjs.map → SSMStateProvider-CksOTB8M.mjs.map} +1 -1
- package/dist/{backup-provisioner-BAExdDtc.mjs → backup-provisioner-BEXoHTuC.mjs} +1 -1
- package/dist/{backup-provisioner-BAExdDtc.mjs.map → backup-provisioner-BEXoHTuC.mjs.map} +1 -1
- package/dist/{backup-provisioner-C8VK63I-.cjs → backup-provisioner-C4noe75O.cjs} +1 -1
- package/dist/{backup-provisioner-C8VK63I-.cjs.map → backup-provisioner-C4noe75O.cjs.map} +1 -1
- package/dist/{bundler-BxHyDhdt.mjs → bundler-DQYjKFPm.mjs} +1 -1
- package/dist/{bundler-BxHyDhdt.mjs.map → bundler-DQYjKFPm.mjs.map} +1 -1
- package/dist/{bundler-CuMIfXw5.cjs → bundler-NpfYPBUo.cjs} +1 -1
- package/dist/{bundler-CuMIfXw5.cjs.map → bundler-NpfYPBUo.cjs.map} +1 -1
- package/dist/config.d.mts +2 -2
- package/dist/fullstack-secrets-COWz084x.cjs +238 -0
- package/dist/fullstack-secrets-COWz084x.cjs.map +1 -0
- package/dist/fullstack-secrets-UZAFWuH4.mjs +202 -0
- package/dist/fullstack-secrets-UZAFWuH4.mjs.map +1 -0
- package/dist/{index-BVNXOydm.d.mts → index-Bt2kX0-R.d.mts} +2 -2
- package/dist/{index-BVNXOydm.d.mts.map → index-Bt2kX0-R.d.mts.map} +1 -1
- package/dist/index.cjs +141 -276
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +128 -263
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-react-query-DaTMSPD5.mjs → openapi-react-query-C4UdILaI.mjs} +1 -1
- package/dist/{openapi-react-query-DaTMSPD5.mjs.map → openapi-react-query-C4UdILaI.mjs.map} +1 -1
- package/dist/{openapi-react-query-BeXvk-wa.cjs → openapi-react-query-DYbBq-WJ.cjs} +1 -1
- package/dist/{openapi-react-query-BeXvk-wa.cjs.map → openapi-react-query-DYbBq-WJ.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/reconcile-7yarEvmK.cjs +36 -0
- package/dist/reconcile-7yarEvmK.cjs.map +1 -0
- package/dist/reconcile-D2WCDQue.mjs +36 -0
- package/dist/reconcile-D2WCDQue.mjs.map +1 -0
- package/dist/{sync-BnqNNc6O.mjs → sync-6FoT41G3.mjs} +1 -1
- package/dist/{sync-CHfhmXF3.mjs → sync-CbeKrnQV.mjs} +1 -1
- package/dist/{sync-CHfhmXF3.mjs.map → sync-CbeKrnQV.mjs.map} +1 -1
- package/dist/{sync-BOS0jKLn.cjs → sync-DdkKaHqP.cjs} +1 -1
- package/dist/{sync-BOS0jKLn.cjs.map → sync-DdkKaHqP.cjs.map} +1 -1
- package/dist/sync-RsnjXYwG.cjs +4 -0
- package/dist/{types-eTlj5f2M.d.mts → types-wXMIMOyK.d.mts} +1 -1
- package/dist/{types-eTlj5f2M.d.mts.map → types-wXMIMOyK.d.mts.map} +1 -1
- package/dist/workspace/index.d.mts +2 -2
- package/package.json +3 -3
- package/src/dev/__tests__/index.spec.ts +49 -0
- package/src/dev/index.ts +84 -63
- package/src/index.ts +79 -1
- package/src/init/versions.ts +4 -4
- package/src/secrets/__tests__/reconcile.spec.ts +123 -0
- package/src/secrets/reconcile.ts +53 -0
- package/src/setup/fullstack-secrets.ts +2 -0
- package/dist/sync-BxFB34zW.cjs +0 -4
package/dist/index.cjs
CHANGED
|
@@ -8,8 +8,9 @@ const require_storage = require('./storage-CoCNe0Pt.cjs');
|
|
|
8
8
|
const require_dokploy_api = require('./dokploy-api-DLgvEQlr.cjs');
|
|
9
9
|
const require_encryption = require('./encryption-BE0UOb8j.cjs');
|
|
10
10
|
const require_CachedStateProvider = require('./CachedStateProvider-D73dCqfH.cjs');
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
const require_fullstack_secrets = require('./fullstack-secrets-COWz084x.cjs');
|
|
12
|
+
const require_openapi_react_query = require('./openapi-react-query-DYbBq-WJ.cjs');
|
|
13
|
+
const require_sync = require('./sync-DdkKaHqP.cjs');
|
|
13
14
|
const node_fs = require_chunk.__toESM(require("node:fs"));
|
|
14
15
|
const node_path = require_chunk.__toESM(require("node:path"));
|
|
15
16
|
const commander = require_chunk.__toESM(require("commander"));
|
|
@@ -34,7 +35,7 @@ const prompts = require_chunk.__toESM(require("prompts"));
|
|
|
34
35
|
|
|
35
36
|
//#region package.json
|
|
36
37
|
var name = "@geekmidas/cli";
|
|
37
|
-
var version = "1.
|
|
38
|
+
var version = "1.9.0";
|
|
38
39
|
var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
|
|
39
40
|
var private$1 = false;
|
|
40
41
|
var type = "module";
|
|
@@ -1740,6 +1741,66 @@ var EntryRunner = class {
|
|
|
1740
1741
|
}
|
|
1741
1742
|
}
|
|
1742
1743
|
};
|
|
1744
|
+
/**
|
|
1745
|
+
* Generate the content of the dev server entry file (server.ts).
|
|
1746
|
+
* Uses dynamic import for createApp so Credentials are populated
|
|
1747
|
+
* before any app modules evaluate.
|
|
1748
|
+
* @internal Exported for testing
|
|
1749
|
+
*/
|
|
1750
|
+
function generateServerEntryContent(options) {
|
|
1751
|
+
const { secretsJsonPath, runtime = "node", enableOpenApi = false, appImportPath = "./app.js" } = options;
|
|
1752
|
+
const credentialsInjection = secretsJsonPath ? `import { Credentials } from '@geekmidas/envkit/credentials';
|
|
1753
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
1754
|
+
|
|
1755
|
+
// Inject dev secrets into Credentials (must happen before app import)
|
|
1756
|
+
const secretsPath = '${secretsJsonPath}';
|
|
1757
|
+
if (existsSync(secretsPath)) {
|
|
1758
|
+
Object.assign(Credentials, JSON.parse(readFileSync(secretsPath, 'utf-8')));
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
` : "";
|
|
1762
|
+
const serveCode = runtime === "bun" ? `Bun.serve({
|
|
1763
|
+
port,
|
|
1764
|
+
fetch: app.fetch,
|
|
1765
|
+
});` : `const { serve } = await import('@hono/node-server');
|
|
1766
|
+
const server = serve({
|
|
1767
|
+
fetch: app.fetch,
|
|
1768
|
+
port,
|
|
1769
|
+
});
|
|
1770
|
+
// Inject WebSocket support if available
|
|
1771
|
+
const injectWs = (app as any).__injectWebSocket;
|
|
1772
|
+
if (injectWs) {
|
|
1773
|
+
injectWs(server);
|
|
1774
|
+
console.log('🔌 Telescope real-time updates enabled');
|
|
1775
|
+
}`;
|
|
1776
|
+
return `#!/usr/bin/env node
|
|
1777
|
+
/**
|
|
1778
|
+
* Development server entry point
|
|
1779
|
+
* This file is auto-generated by 'gkm dev'
|
|
1780
|
+
*/
|
|
1781
|
+
${credentialsInjection}
|
|
1782
|
+
const port = process.argv.includes('--port')
|
|
1783
|
+
? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])
|
|
1784
|
+
: 3000;
|
|
1785
|
+
|
|
1786
|
+
// Dynamic import so Credentials are populated before env.ts evaluates
|
|
1787
|
+
const { createApp } = await import('${appImportPath}');
|
|
1788
|
+
|
|
1789
|
+
// createApp is async to support optional WebSocket setup
|
|
1790
|
+
const { app, start } = await createApp(undefined, ${enableOpenApi});
|
|
1791
|
+
|
|
1792
|
+
// Start the server
|
|
1793
|
+
start({
|
|
1794
|
+
port,
|
|
1795
|
+
serve: async (app, port) => {
|
|
1796
|
+
${serveCode}
|
|
1797
|
+
},
|
|
1798
|
+
}).catch((error) => {
|
|
1799
|
+
console.error('Failed to start server:', error);
|
|
1800
|
+
process.exit(1);
|
|
1801
|
+
});
|
|
1802
|
+
`;
|
|
1803
|
+
}
|
|
1743
1804
|
var DevServer = class {
|
|
1744
1805
|
serverProcess = null;
|
|
1745
1806
|
isRunning = false;
|
|
@@ -1833,58 +1894,12 @@ var DevServer = class {
|
|
|
1833
1894
|
}
|
|
1834
1895
|
async createServerEntry() {
|
|
1835
1896
|
const { writeFile: fsWriteFile } = await import("node:fs/promises");
|
|
1836
|
-
const { relative: relative$6, dirname: dirname$11 } = await import("node:path");
|
|
1837
1897
|
const serverPath = (0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts");
|
|
1838
|
-
const
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
const secretsPath = '${this.secretsJsonPath}';
|
|
1844
|
-
if (existsSync(secretsPath)) {
|
|
1845
|
-
Object.assign(Credentials, JSON.parse(readFileSync(secretsPath, 'utf-8')));
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
` : "";
|
|
1849
|
-
const serveCode = this.runtime === "bun" ? `Bun.serve({
|
|
1850
|
-
port,
|
|
1851
|
-
fetch: app.fetch,
|
|
1852
|
-
});` : `const { serve } = await import('@hono/node-server');
|
|
1853
|
-
const server = serve({
|
|
1854
|
-
fetch: app.fetch,
|
|
1855
|
-
port,
|
|
1856
|
-
});
|
|
1857
|
-
// Inject WebSocket support if available
|
|
1858
|
-
const injectWs = (app as any).__injectWebSocket;
|
|
1859
|
-
if (injectWs) {
|
|
1860
|
-
injectWs(server);
|
|
1861
|
-
console.log('🔌 Telescope real-time updates enabled');
|
|
1862
|
-
}`;
|
|
1863
|
-
const content = `#!/usr/bin/env node
|
|
1864
|
-
/**
|
|
1865
|
-
* Development server entry point
|
|
1866
|
-
* This file is auto-generated by 'gkm dev'
|
|
1867
|
-
*/
|
|
1868
|
-
${credentialsInjection}import { createApp } from './${relativeAppPath.startsWith(".") ? relativeAppPath : `./${relativeAppPath}`}';
|
|
1869
|
-
|
|
1870
|
-
const port = process.argv.includes('--port')
|
|
1871
|
-
? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])
|
|
1872
|
-
: 3000;
|
|
1873
|
-
|
|
1874
|
-
// createApp is async to support optional WebSocket setup
|
|
1875
|
-
const { app, start } = await createApp(undefined, ${this.enableOpenApi});
|
|
1876
|
-
|
|
1877
|
-
// Start the server
|
|
1878
|
-
start({
|
|
1879
|
-
port,
|
|
1880
|
-
serve: async (app, port) => {
|
|
1881
|
-
${serveCode}
|
|
1882
|
-
},
|
|
1883
|
-
}).catch((error) => {
|
|
1884
|
-
console.error('Failed to start server:', error);
|
|
1885
|
-
process.exit(1);
|
|
1886
|
-
});
|
|
1887
|
-
`;
|
|
1898
|
+
const content = generateServerEntryContent({
|
|
1899
|
+
secretsJsonPath: this.secretsJsonPath,
|
|
1900
|
+
runtime: this.runtime,
|
|
1901
|
+
enableOpenApi: this.enableOpenApi
|
|
1902
|
+
});
|
|
1888
1903
|
await fsWriteFile(serverPath, content);
|
|
1889
1904
|
}
|
|
1890
1905
|
};
|
|
@@ -2137,7 +2152,7 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
|
|
|
2137
2152
|
let masterKey;
|
|
2138
2153
|
if (context.production?.bundle && !skipBundle) {
|
|
2139
2154
|
logger$9.log(`\n📦 Bundling production server...`);
|
|
2140
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
2155
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-NpfYPBUo.cjs"));
|
|
2141
2156
|
const allConstructs = [
|
|
2142
2157
|
...endpoints.map((e) => e.construct),
|
|
2143
2158
|
...functions.map((f) => f.construct),
|
|
@@ -2416,11 +2431,11 @@ async function createDnsProvider(options) {
|
|
|
2416
2431
|
if (isDnsProvider(config.provider)) return config.provider;
|
|
2417
2432
|
const provider = config.provider;
|
|
2418
2433
|
if (provider === "hostinger") {
|
|
2419
|
-
const { HostingerProvider } = await Promise.resolve().then(() => require("./HostingerProvider-
|
|
2434
|
+
const { HostingerProvider } = await Promise.resolve().then(() => require("./HostingerProvider-5KYmwoK2.cjs"));
|
|
2420
2435
|
return new HostingerProvider();
|
|
2421
2436
|
}
|
|
2422
2437
|
if (provider === "route53") {
|
|
2423
|
-
const { Route53Provider } = await Promise.resolve().then(() => require("./Route53Provider-
|
|
2438
|
+
const { Route53Provider } = await Promise.resolve().then(() => require("./Route53Provider-owQQ4pn6.cjs"));
|
|
2424
2439
|
const route53Config = config;
|
|
2425
2440
|
return new Route53Provider({
|
|
2426
2441
|
region: route53Config.region,
|
|
@@ -4668,19 +4683,19 @@ function isStateProvider(value) {
|
|
|
4668
4683
|
async function createStateProvider(options) {
|
|
4669
4684
|
const { config, workspaceRoot, workspaceName } = options;
|
|
4670
4685
|
if (!config) {
|
|
4671
|
-
const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-
|
|
4686
|
+
const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CLifRC0Y.cjs"));
|
|
4672
4687
|
return new LocalStateProvider(workspaceRoot);
|
|
4673
4688
|
}
|
|
4674
4689
|
if (isStateProvider(config.provider)) return config.provider;
|
|
4675
4690
|
const provider = config.provider;
|
|
4676
4691
|
if (provider === "local") {
|
|
4677
|
-
const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-
|
|
4692
|
+
const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CLifRC0Y.cjs"));
|
|
4678
4693
|
return new LocalStateProvider(workspaceRoot);
|
|
4679
4694
|
}
|
|
4680
4695
|
if (provider === "ssm") {
|
|
4681
4696
|
if (!workspaceName) throw new Error("Workspace name is required for SSM state provider. Set \"name\" in gkm.config.ts.");
|
|
4682
|
-
const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-
|
|
4683
|
-
const { SSMStateProvider } = await Promise.resolve().then(() => require("./SSMStateProvider-
|
|
4697
|
+
const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CLifRC0Y.cjs"));
|
|
4698
|
+
const { SSMStateProvider } = await Promise.resolve().then(() => require("./SSMStateProvider-CT8tjl9o.cjs"));
|
|
4684
4699
|
const { CachedStateProvider: CachedStateProvider$1 } = await Promise.resolve().then(() => require("./CachedStateProvider-D_uISMmJ.cjs"));
|
|
4685
4700
|
const ssmConfig = config;
|
|
4686
4701
|
const local = new LocalStateProvider(workspaceRoot);
|
|
@@ -5355,8 +5370,8 @@ async function provisionServices(api, projectId, environmentId, projectName, ser
|
|
|
5355
5370
|
else logger$3.log(` ⚠ Cached ID invalid, will create new`);
|
|
5356
5371
|
}
|
|
5357
5372
|
if (!redis) {
|
|
5358
|
-
const { randomBytes: randomBytes$
|
|
5359
|
-
const databasePassword = randomBytes$
|
|
5373
|
+
const { randomBytes: randomBytes$2 } = await import("node:crypto");
|
|
5374
|
+
const databasePassword = randomBytes$2(16).toString("hex");
|
|
5360
5375
|
const result = await api.findOrCreateRedis(redisName, projectId, environmentId, { databasePassword });
|
|
5361
5376
|
redis = result.redis;
|
|
5362
5377
|
created = result.created;
|
|
@@ -5780,7 +5795,7 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
5780
5795
|
}
|
|
5781
5796
|
if (workspace.deploy?.backups && provisionedPostgres) {
|
|
5782
5797
|
logger$3.log("\n💾 Provisioning backup destination...");
|
|
5783
|
-
const { provisionBackupDestination } = await Promise.resolve().then(() => require("./backup-provisioner-
|
|
5798
|
+
const { provisionBackupDestination } = await Promise.resolve().then(() => require("./backup-provisioner-C4noe75O.cjs"));
|
|
5784
5799
|
const backupState = await provisionBackupDestination({
|
|
5785
5800
|
api,
|
|
5786
5801
|
projectId: project.projectId,
|
|
@@ -6405,200 +6420,6 @@ function printStateDetails(state) {
|
|
|
6405
6420
|
}
|
|
6406
6421
|
}
|
|
6407
6422
|
|
|
6408
|
-
//#endregion
|
|
6409
|
-
//#region src/secrets/generator.ts
|
|
6410
|
-
/**
|
|
6411
|
-
* Generate a secure random password using URL-safe base64 characters.
|
|
6412
|
-
* @param length Password length (default: 32)
|
|
6413
|
-
*/
|
|
6414
|
-
function generateSecurePassword(length = 32) {
|
|
6415
|
-
return (0, node_crypto.randomBytes)(Math.ceil(length * 3 / 4)).toString("base64url").slice(0, length);
|
|
6416
|
-
}
|
|
6417
|
-
/** Default service configurations */
|
|
6418
|
-
const SERVICE_DEFAULTS = {
|
|
6419
|
-
postgres: {
|
|
6420
|
-
host: "postgres",
|
|
6421
|
-
port: 5432,
|
|
6422
|
-
username: "app",
|
|
6423
|
-
database: "app"
|
|
6424
|
-
},
|
|
6425
|
-
redis: {
|
|
6426
|
-
host: "redis",
|
|
6427
|
-
port: 6379,
|
|
6428
|
-
username: "default"
|
|
6429
|
-
},
|
|
6430
|
-
rabbitmq: {
|
|
6431
|
-
host: "rabbitmq",
|
|
6432
|
-
port: 5672,
|
|
6433
|
-
username: "app",
|
|
6434
|
-
vhost: "/"
|
|
6435
|
-
}
|
|
6436
|
-
};
|
|
6437
|
-
/**
|
|
6438
|
-
* Generate credentials for a specific service.
|
|
6439
|
-
*/
|
|
6440
|
-
function generateServiceCredentials(service) {
|
|
6441
|
-
const defaults = SERVICE_DEFAULTS[service];
|
|
6442
|
-
return {
|
|
6443
|
-
...defaults,
|
|
6444
|
-
password: generateSecurePassword()
|
|
6445
|
-
};
|
|
6446
|
-
}
|
|
6447
|
-
/**
|
|
6448
|
-
* Generate credentials for multiple services.
|
|
6449
|
-
*/
|
|
6450
|
-
function generateServicesCredentials(services) {
|
|
6451
|
-
const result = {};
|
|
6452
|
-
for (const service of services) result[service] = generateServiceCredentials(service);
|
|
6453
|
-
return result;
|
|
6454
|
-
}
|
|
6455
|
-
/**
|
|
6456
|
-
* Generate connection URL for PostgreSQL.
|
|
6457
|
-
*/
|
|
6458
|
-
function generatePostgresUrl(creds) {
|
|
6459
|
-
const { username, password, host, port, database } = creds;
|
|
6460
|
-
return `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
|
|
6461
|
-
}
|
|
6462
|
-
/**
|
|
6463
|
-
* Generate connection URL for Redis.
|
|
6464
|
-
*/
|
|
6465
|
-
function generateRedisUrl(creds) {
|
|
6466
|
-
const { password, host, port } = creds;
|
|
6467
|
-
return `redis://:${encodeURIComponent(password)}@${host}:${port}`;
|
|
6468
|
-
}
|
|
6469
|
-
/**
|
|
6470
|
-
* Generate connection URL for RabbitMQ.
|
|
6471
|
-
*/
|
|
6472
|
-
function generateRabbitmqUrl(creds) {
|
|
6473
|
-
const { username, password, host, port, vhost } = creds;
|
|
6474
|
-
const encodedVhost = encodeURIComponent(vhost ?? "/");
|
|
6475
|
-
return `amqp://${username}:${encodeURIComponent(password)}@${host}:${port}/${encodedVhost}`;
|
|
6476
|
-
}
|
|
6477
|
-
/**
|
|
6478
|
-
* Generate connection URLs from service credentials.
|
|
6479
|
-
*/
|
|
6480
|
-
function generateConnectionUrls(services) {
|
|
6481
|
-
const urls = {};
|
|
6482
|
-
if (services.postgres) urls.DATABASE_URL = generatePostgresUrl(services.postgres);
|
|
6483
|
-
if (services.redis) urls.REDIS_URL = generateRedisUrl(services.redis);
|
|
6484
|
-
if (services.rabbitmq) urls.RABBITMQ_URL = generateRabbitmqUrl(services.rabbitmq);
|
|
6485
|
-
return urls;
|
|
6486
|
-
}
|
|
6487
|
-
/**
|
|
6488
|
-
* Create a new StageSecrets object with generated credentials.
|
|
6489
|
-
*/
|
|
6490
|
-
function createStageSecrets(stage, services) {
|
|
6491
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6492
|
-
const serviceCredentials = generateServicesCredentials(services);
|
|
6493
|
-
const urls = generateConnectionUrls(serviceCredentials);
|
|
6494
|
-
return {
|
|
6495
|
-
stage,
|
|
6496
|
-
createdAt: now,
|
|
6497
|
-
updatedAt: now,
|
|
6498
|
-
services: serviceCredentials,
|
|
6499
|
-
urls,
|
|
6500
|
-
custom: {}
|
|
6501
|
-
};
|
|
6502
|
-
}
|
|
6503
|
-
/**
|
|
6504
|
-
* Rotate password for a specific service.
|
|
6505
|
-
*/
|
|
6506
|
-
function rotateServicePassword(secrets, service) {
|
|
6507
|
-
const currentCreds = secrets.services[service];
|
|
6508
|
-
if (!currentCreds) throw new Error(`Service "${service}" not configured in secrets`);
|
|
6509
|
-
const newCreds = {
|
|
6510
|
-
...currentCreds,
|
|
6511
|
-
password: generateSecurePassword()
|
|
6512
|
-
};
|
|
6513
|
-
const newServices = {
|
|
6514
|
-
...secrets.services,
|
|
6515
|
-
[service]: newCreds
|
|
6516
|
-
};
|
|
6517
|
-
return {
|
|
6518
|
-
...secrets,
|
|
6519
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6520
|
-
services: newServices,
|
|
6521
|
-
urls: generateConnectionUrls(newServices)
|
|
6522
|
-
};
|
|
6523
|
-
}
|
|
6524
|
-
|
|
6525
|
-
//#endregion
|
|
6526
|
-
//#region src/setup/fullstack-secrets.ts
|
|
6527
|
-
/**
|
|
6528
|
-
* Generate a secure random password for database users.
|
|
6529
|
-
* Uses a combination of timestamp and random bytes for uniqueness.
|
|
6530
|
-
*/
|
|
6531
|
-
function generateDbPassword() {
|
|
6532
|
-
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
|
|
6533
|
-
}
|
|
6534
|
-
/**
|
|
6535
|
-
* Generate database URL for an app.
|
|
6536
|
-
* All apps connect to the same database, but use different users/schemas.
|
|
6537
|
-
*/
|
|
6538
|
-
function generateDbUrl(appName, password, projectName, host = "localhost", port = 5432) {
|
|
6539
|
-
const userName = appName.replace(/-/g, "_");
|
|
6540
|
-
const dbName = `${projectName.replace(/-/g, "_")}_dev`;
|
|
6541
|
-
return `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;
|
|
6542
|
-
}
|
|
6543
|
-
/**
|
|
6544
|
-
* Generate fullstack-aware custom secrets for a workspace.
|
|
6545
|
-
*
|
|
6546
|
-
* Generates:
|
|
6547
|
-
* - Common secrets: NODE_ENV, PORT, LOG_LEVEL, JWT_SECRET
|
|
6548
|
-
* - Per-app database passwords and URLs for backend apps with db service
|
|
6549
|
-
* - Better-auth secrets for apps using the better-auth framework
|
|
6550
|
-
*/
|
|
6551
|
-
function generateFullstackCustomSecrets(workspace) {
|
|
6552
|
-
const hasDb = !!workspace.services.db;
|
|
6553
|
-
const customs = {
|
|
6554
|
-
NODE_ENV: "development",
|
|
6555
|
-
PORT: "3000",
|
|
6556
|
-
LOG_LEVEL: "debug",
|
|
6557
|
-
JWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
6558
|
-
};
|
|
6559
|
-
if (!hasDb) return customs;
|
|
6560
|
-
const frontendPorts = [];
|
|
6561
|
-
for (const [appName, appConfig] of Object.entries(workspace.apps)) {
|
|
6562
|
-
if (appConfig.type === "frontend") {
|
|
6563
|
-
frontendPorts.push(appConfig.port);
|
|
6564
|
-
continue;
|
|
6565
|
-
}
|
|
6566
|
-
const password = generateDbPassword();
|
|
6567
|
-
const upperName = appName.toUpperCase();
|
|
6568
|
-
customs[`${upperName}_DATABASE_URL`] = generateDbUrl(appName, password, workspace.name);
|
|
6569
|
-
customs[`${upperName}_DB_PASSWORD`] = password;
|
|
6570
|
-
if (appConfig.framework === "better-auth") {
|
|
6571
|
-
customs.AUTH_PORT = String(appConfig.port);
|
|
6572
|
-
customs.AUTH_URL = `http://localhost:${appConfig.port}`;
|
|
6573
|
-
customs.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${generateSecurePassword(16)}`;
|
|
6574
|
-
customs.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;
|
|
6575
|
-
}
|
|
6576
|
-
}
|
|
6577
|
-
if (customs.BETTER_AUTH_SECRET) {
|
|
6578
|
-
const allPorts = Object.values(workspace.apps).map((a) => a.port);
|
|
6579
|
-
customs.BETTER_AUTH_TRUSTED_ORIGINS = allPorts.map((p) => `http://localhost:${p}`).join(",");
|
|
6580
|
-
}
|
|
6581
|
-
return customs;
|
|
6582
|
-
}
|
|
6583
|
-
/**
|
|
6584
|
-
* Extract *_DB_PASSWORD keys from secrets and write docker/.env.
|
|
6585
|
-
*
|
|
6586
|
-
* The docker/.env file contains database passwords that the PostgreSQL
|
|
6587
|
-
* init script reads to create per-app database users.
|
|
6588
|
-
*/
|
|
6589
|
-
async function writeDockerEnvFromSecrets(secrets, workspaceRoot) {
|
|
6590
|
-
const dbPasswordEntries = Object.entries(secrets.custom).filter(([key]) => key.endsWith("_DB_PASSWORD"));
|
|
6591
|
-
if (dbPasswordEntries.length === 0) return;
|
|
6592
|
-
const envContent = `# Auto-generated docker environment file
|
|
6593
|
-
# Contains database passwords for docker-compose postgres init
|
|
6594
|
-
# This file is gitignored - do not commit to version control
|
|
6595
|
-
${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join("\n")}
|
|
6596
|
-
`;
|
|
6597
|
-
const envPath = (0, node_path.join)(workspaceRoot, "docker", ".env");
|
|
6598
|
-
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(envPath), { recursive: true });
|
|
6599
|
-
await (0, node_fs_promises.writeFile)(envPath, envContent);
|
|
6600
|
-
}
|
|
6601
|
-
|
|
6602
6423
|
//#endregion
|
|
6603
6424
|
//#region src/init/versions.ts
|
|
6604
6425
|
const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
@@ -6624,14 +6445,14 @@ const GEEKMIDAS_VERSIONS = {
|
|
|
6624
6445
|
"@geekmidas/audit": "~1.0.0",
|
|
6625
6446
|
"@geekmidas/auth": "~1.0.0",
|
|
6626
6447
|
"@geekmidas/cache": "~1.0.0",
|
|
6627
|
-
"@geekmidas/client": "~
|
|
6448
|
+
"@geekmidas/client": "~3.0.0",
|
|
6628
6449
|
"@geekmidas/cloud": "~1.0.0",
|
|
6629
|
-
"@geekmidas/constructs": "~
|
|
6450
|
+
"@geekmidas/constructs": "~2.0.0",
|
|
6630
6451
|
"@geekmidas/db": "~1.0.0",
|
|
6631
6452
|
"@geekmidas/emailkit": "~1.0.0",
|
|
6632
6453
|
"@geekmidas/envkit": "~1.0.3",
|
|
6633
6454
|
"@geekmidas/errors": "~1.0.0",
|
|
6634
|
-
"@geekmidas/events": "~1.
|
|
6455
|
+
"@geekmidas/events": "~1.1.0",
|
|
6635
6456
|
"@geekmidas/logger": "~1.0.0",
|
|
6636
6457
|
"@geekmidas/rate-limit": "~1.0.0",
|
|
6637
6458
|
"@geekmidas/schema": "~1.0.0",
|
|
@@ -6639,7 +6460,7 @@ const GEEKMIDAS_VERSIONS = {
|
|
|
6639
6460
|
"@geekmidas/storage": "~1.0.0",
|
|
6640
6461
|
"@geekmidas/studio": "~1.0.0",
|
|
6641
6462
|
"@geekmidas/telescope": "~1.0.0",
|
|
6642
|
-
"@geekmidas/testkit": "~1.0.
|
|
6463
|
+
"@geekmidas/testkit": "~1.0.2",
|
|
6643
6464
|
"@geekmidas/cli": CLI_VERSION
|
|
6644
6465
|
};
|
|
6645
6466
|
|
|
@@ -10948,10 +10769,10 @@ async function initCommand(projectName, options = {}) {
|
|
|
10948
10769
|
const dbApps = [];
|
|
10949
10770
|
if (isFullstack && services.db) dbApps.push({
|
|
10950
10771
|
name: "api",
|
|
10951
|
-
password: generateDbPassword()
|
|
10772
|
+
password: require_fullstack_secrets.generateDbPassword()
|
|
10952
10773
|
}, {
|
|
10953
10774
|
name: "auth",
|
|
10954
|
-
password: generateDbPassword()
|
|
10775
|
+
password: require_fullstack_secrets.generateDbPassword()
|
|
10955
10776
|
});
|
|
10956
10777
|
const appFiles = baseTemplate ? [
|
|
10957
10778
|
...generatePackageJson(templateOptions, baseTemplate),
|
|
@@ -11000,7 +10821,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
11000
10821
|
const secretServices = [];
|
|
11001
10822
|
if (services.db) secretServices.push("postgres");
|
|
11002
10823
|
if (services.cache) secretServices.push("redis");
|
|
11003
|
-
const devSecrets = createStageSecrets("development", secretServices);
|
|
10824
|
+
const devSecrets = require_fullstack_secrets.createStageSecrets("development", secretServices);
|
|
11004
10825
|
const customSecrets = {
|
|
11005
10826
|
NODE_ENV: "development",
|
|
11006
10827
|
PORT: "3000",
|
|
@@ -11010,7 +10831,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
11010
10831
|
if (isFullstack && dbApps.length > 0) {
|
|
11011
10832
|
for (const app of dbApps) {
|
|
11012
10833
|
const urlKey = `${app.name.toUpperCase()}_DATABASE_URL`;
|
|
11013
|
-
customSecrets[urlKey] = generateDbUrl(app.name, app.password, name$1);
|
|
10834
|
+
customSecrets[urlKey] = require_fullstack_secrets.generateDbUrl(app.name, app.password, name$1);
|
|
11014
10835
|
const passwordKey = `${app.name.toUpperCase()}_DB_PASSWORD`;
|
|
11015
10836
|
customSecrets[passwordKey] = app.password;
|
|
11016
10837
|
}
|
|
@@ -11137,12 +10958,12 @@ async function secretsInitCommand(options) {
|
|
|
11137
10958
|
const config = await require_config.loadConfig();
|
|
11138
10959
|
const services = getServicesFromConfig(config.docker?.compose?.services);
|
|
11139
10960
|
if (services.length === 0) logger$2.warn("No services configured in docker.compose.services. Creating secrets with empty services.");
|
|
11140
|
-
const secrets = createStageSecrets(stage, services);
|
|
10961
|
+
const secrets = require_fullstack_secrets.createStageSecrets(stage, services);
|
|
11141
10962
|
try {
|
|
11142
10963
|
const loaded = await require_config.loadWorkspaceConfig();
|
|
11143
10964
|
const isMultiApp = Object.keys(loaded.workspace.apps).length > 1;
|
|
11144
10965
|
if (isMultiApp) {
|
|
11145
|
-
const customSecrets = generateFullstackCustomSecrets(loaded.workspace);
|
|
10966
|
+
const customSecrets = require_fullstack_secrets.generateFullstackCustomSecrets(loaded.workspace);
|
|
11146
10967
|
secrets.custom = customSecrets;
|
|
11147
10968
|
logger$2.log(" Detected workspace mode — generating per-app secrets");
|
|
11148
10969
|
}
|
|
@@ -11243,13 +11064,13 @@ async function secretsRotateCommand(options) {
|
|
|
11243
11064
|
logger$2.error(`Service "${service}" not configured in stage "${stage}"`);
|
|
11244
11065
|
process.exit(1);
|
|
11245
11066
|
}
|
|
11246
|
-
const updated = rotateServicePassword(secrets, service);
|
|
11067
|
+
const updated = require_fullstack_secrets.rotateServicePassword(secrets, service);
|
|
11247
11068
|
await require_storage.writeStageSecrets(updated);
|
|
11248
11069
|
logger$2.log(`\n✓ Password rotated for ${service} in stage "${stage}"`);
|
|
11249
11070
|
} else {
|
|
11250
11071
|
let updated = secrets;
|
|
11251
11072
|
const services = Object.keys(secrets.services);
|
|
11252
|
-
for (const svc of services) updated = rotateServicePassword(updated, svc);
|
|
11073
|
+
for (const svc of services) updated = require_fullstack_secrets.rotateServicePassword(updated, svc);
|
|
11253
11074
|
await require_storage.writeStageSecrets(updated);
|
|
11254
11075
|
logger$2.log(`\n✓ Passwords rotated for all services in stage "${stage}": ${services.join(", ")}`);
|
|
11255
11076
|
}
|
|
@@ -11342,7 +11163,7 @@ async function setupCommand(options = {}) {
|
|
|
11342
11163
|
process.exit(1);
|
|
11343
11164
|
}
|
|
11344
11165
|
if (isMultiApp && workspace.services.db) {
|
|
11345
|
-
await writeDockerEnvFromSecrets(secrets, workspace.root);
|
|
11166
|
+
await require_fullstack_secrets.writeDockerEnvFromSecrets(secrets, workspace.root);
|
|
11346
11167
|
logger$1.log("📄 Generated docker/.env with database passwords");
|
|
11347
11168
|
}
|
|
11348
11169
|
if (!options.skipDocker) {
|
|
@@ -11396,10 +11217,10 @@ async function generateFreshSecrets(stage, workspace, options) {
|
|
|
11396
11217
|
const serviceNames = [];
|
|
11397
11218
|
if (workspace.services.db) serviceNames.push("postgres");
|
|
11398
11219
|
if (workspace.services.cache) serviceNames.push("redis");
|
|
11399
|
-
const secrets = createStageSecrets(stage, serviceNames);
|
|
11220
|
+
const secrets = require_fullstack_secrets.createStageSecrets(stage, serviceNames);
|
|
11400
11221
|
const isMultiApp = Object.keys(workspace.apps).length > 1;
|
|
11401
11222
|
if (isMultiApp) {
|
|
11402
|
-
const customSecrets = generateFullstackCustomSecrets(workspace);
|
|
11223
|
+
const customSecrets = require_fullstack_secrets.generateFullstackCustomSecrets(workspace);
|
|
11403
11224
|
secrets.custom = customSecrets;
|
|
11404
11225
|
} else secrets.custom = {
|
|
11405
11226
|
NODE_ENV: "development",
|
|
@@ -11943,8 +11764,19 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
|
|
|
11943
11764
|
const globalOptions = program.opts();
|
|
11944
11765
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11945
11766
|
const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await Promise.resolve().then(() => require("./config.cjs"));
|
|
11946
|
-
const { pushSecrets: pushSecrets$1 } = await Promise.resolve().then(() => require("./sync-
|
|
11767
|
+
const { pushSecrets: pushSecrets$1 } = await Promise.resolve().then(() => require("./sync-RsnjXYwG.cjs"));
|
|
11768
|
+
const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-7yarEvmK.cjs"));
|
|
11769
|
+
const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await Promise.resolve().then(() => require("./storage-C7pmBq1u.cjs"));
|
|
11947
11770
|
const { workspace } = await loadWorkspaceConfig$1();
|
|
11771
|
+
const secrets = await readStageSecrets$1(options.stage, workspace.root);
|
|
11772
|
+
if (secrets) {
|
|
11773
|
+
const result = reconcileMissingSecrets(secrets, workspace);
|
|
11774
|
+
if (result) {
|
|
11775
|
+
await writeStageSecrets$1(result.secrets, workspace.root);
|
|
11776
|
+
console.log(` Reconciled ${result.addedKeys.length} missing secret(s):`);
|
|
11777
|
+
for (const key of result.addedKeys) console.log(` + ${key}`);
|
|
11778
|
+
}
|
|
11779
|
+
}
|
|
11948
11780
|
await pushSecrets$1(options.stage, workspace);
|
|
11949
11781
|
console.log(`\n✓ Secrets pushed for stage "${options.stage}"`);
|
|
11950
11782
|
} catch (error) {
|
|
@@ -11957,14 +11789,21 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
|
|
|
11957
11789
|
const globalOptions = program.opts();
|
|
11958
11790
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11959
11791
|
const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await Promise.resolve().then(() => require("./config.cjs"));
|
|
11960
|
-
const { pullSecrets: pullSecrets$1 } = await Promise.resolve().then(() => require("./sync-
|
|
11792
|
+
const { pullSecrets: pullSecrets$1 } = await Promise.resolve().then(() => require("./sync-RsnjXYwG.cjs"));
|
|
11961
11793
|
const { writeStageSecrets: writeStageSecrets$1 } = await Promise.resolve().then(() => require("./storage-C7pmBq1u.cjs"));
|
|
11794
|
+
const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-7yarEvmK.cjs"));
|
|
11962
11795
|
const { workspace } = await loadWorkspaceConfig$1();
|
|
11963
|
-
|
|
11796
|
+
let secrets = await pullSecrets$1(options.stage, workspace);
|
|
11964
11797
|
if (!secrets) {
|
|
11965
11798
|
console.error(`No remote secrets found for stage "${options.stage}".`);
|
|
11966
11799
|
process.exit(1);
|
|
11967
11800
|
}
|
|
11801
|
+
const result = reconcileMissingSecrets(secrets, workspace);
|
|
11802
|
+
if (result) {
|
|
11803
|
+
secrets = result.secrets;
|
|
11804
|
+
console.log(` Reconciled ${result.addedKeys.length} missing secret(s):`);
|
|
11805
|
+
for (const key of result.addedKeys) console.log(` + ${key}`);
|
|
11806
|
+
}
|
|
11968
11807
|
await writeStageSecrets$1(secrets, workspace.root);
|
|
11969
11808
|
console.log(`\n✓ Secrets pulled for stage "${options.stage}"`);
|
|
11970
11809
|
} catch (error) {
|
|
@@ -11972,6 +11811,32 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
|
|
|
11972
11811
|
process.exit(1);
|
|
11973
11812
|
}
|
|
11974
11813
|
});
|
|
11814
|
+
program.command("secrets:reconcile").description("Backfill missing custom secrets from workspace config").option("--stage <stage>", "Stage name", "development").action(async (options) => {
|
|
11815
|
+
try {
|
|
11816
|
+
const globalOptions = program.opts();
|
|
11817
|
+
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11818
|
+
const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await Promise.resolve().then(() => require("./config.cjs"));
|
|
11819
|
+
const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-7yarEvmK.cjs"));
|
|
11820
|
+
const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await Promise.resolve().then(() => require("./storage-C7pmBq1u.cjs"));
|
|
11821
|
+
const { workspace } = await loadWorkspaceConfig$1();
|
|
11822
|
+
const secrets = await readStageSecrets$1(options.stage, workspace.root);
|
|
11823
|
+
if (!secrets) {
|
|
11824
|
+
console.error(`No secrets found for stage "${options.stage}". Run "gkm secrets:init --stage ${options.stage}" first.`);
|
|
11825
|
+
process.exit(1);
|
|
11826
|
+
}
|
|
11827
|
+
const result = reconcileMissingSecrets(secrets, workspace);
|
|
11828
|
+
if (!result) {
|
|
11829
|
+
console.log(`\n✓ Secrets for stage "${options.stage}" are up-to-date`);
|
|
11830
|
+
return;
|
|
11831
|
+
}
|
|
11832
|
+
await writeStageSecrets$1(result.secrets, workspace.root);
|
|
11833
|
+
console.log(`\n✓ Reconciled ${result.addedKeys.length} missing secret(s) for stage "${options.stage}":`);
|
|
11834
|
+
for (const key of result.addedKeys) console.log(` + ${key}`);
|
|
11835
|
+
} catch (error) {
|
|
11836
|
+
console.error(error instanceof Error ? error.message : "Command failed");
|
|
11837
|
+
process.exit(1);
|
|
11838
|
+
}
|
|
11839
|
+
});
|
|
11975
11840
|
program.command("deploy").description("Deploy application to a provider").requiredOption("--provider <provider>", "Deploy provider (docker, dokploy, aws-lambda)").requiredOption("--stage <stage>", "Deployment stage (e.g., production, staging)").option("--tag <tag>", "Image tag (default: stage-timestamp)").option("--skip-push", "Skip pushing image to registry").option("--skip-build", "Skip build step (use existing build)").action(async (options) => {
|
|
11976
11841
|
try {
|
|
11977
11842
|
const globalOptions = program.opts();
|