@mesh-tech/mesh-cli 0.1.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/bin/mesh.d.ts +16 -0
- package/dist/bin/mesh.d.ts.map +1 -0
- package/dist/bin/mesh.js +40 -0
- package/dist/bin/mesh.js.map +1 -0
- package/dist/src/commands/create-app.d.ts +10 -0
- package/dist/src/commands/create-app.d.ts.map +1 -0
- package/dist/src/commands/create-app.js +176 -0
- package/dist/src/commands/create-app.js.map +1 -0
- package/dist/src/commands/db/connect.d.ts +13 -0
- package/dist/src/commands/db/connect.d.ts.map +1 -0
- package/dist/src/commands/db/connect.js +68 -0
- package/dist/src/commands/db/connect.js.map +1 -0
- package/dist/src/commands/db/credentials.d.ts +16 -0
- package/dist/src/commands/db/credentials.d.ts.map +1 -0
- package/dist/src/commands/db/credentials.js +56 -0
- package/dist/src/commands/db/credentials.js.map +1 -0
- package/dist/src/commands/db/env.d.ts +15 -0
- package/dist/src/commands/db/env.d.ts.map +1 -0
- package/dist/src/commands/db/env.js +50 -0
- package/dist/src/commands/db/env.js.map +1 -0
- package/dist/src/commands/db/exec.d.ts +54 -0
- package/dist/src/commands/db/exec.d.ts.map +1 -0
- package/dist/src/commands/db/exec.js +331 -0
- package/dist/src/commands/db/exec.js.map +1 -0
- package/dist/src/commands/db/index.d.ts +12 -0
- package/dist/src/commands/db/index.d.ts.map +1 -0
- package/dist/src/commands/db/index.js +62 -0
- package/dist/src/commands/db/index.js.map +1 -0
- package/dist/src/commands/db/psql.d.ts +16 -0
- package/dist/src/commands/db/psql.d.ts.map +1 -0
- package/dist/src/commands/db/psql.js +133 -0
- package/dist/src/commands/db/psql.js.map +1 -0
- package/dist/src/commands/deploy.d.ts +24 -0
- package/dist/src/commands/deploy.d.ts.map +1 -0
- package/dist/src/commands/deploy.js +228 -0
- package/dist/src/commands/deploy.js.map +1 -0
- package/dist/src/commands/dev.d.ts +17 -0
- package/dist/src/commands/dev.d.ts.map +1 -0
- package/dist/src/commands/dev.js +1248 -0
- package/dist/src/commands/dev.js.map +1 -0
- package/dist/src/commands/devbox.d.ts +22 -0
- package/dist/src/commands/devbox.d.ts.map +1 -0
- package/dist/src/commands/devbox.js +463 -0
- package/dist/src/commands/devbox.js.map +1 -0
- package/dist/src/commands/login.d.ts +47 -0
- package/dist/src/commands/login.d.ts.map +1 -0
- package/dist/src/commands/login.js +344 -0
- package/dist/src/commands/login.js.map +1 -0
- package/dist/src/commands/registry.d.ts +20 -0
- package/dist/src/commands/registry.d.ts.map +1 -0
- package/dist/src/commands/registry.js +336 -0
- package/dist/src/commands/registry.js.map +1 -0
- package/dist/src/commands/secrets/exec.d.ts +17 -0
- package/dist/src/commands/secrets/exec.d.ts.map +1 -0
- package/dist/src/commands/secrets/exec.js +132 -0
- package/dist/src/commands/secrets/exec.js.map +1 -0
- package/dist/src/commands/secrets/index.d.ts +10 -0
- package/dist/src/commands/secrets/index.d.ts.map +1 -0
- package/dist/src/commands/secrets/index.js +35 -0
- package/dist/src/commands/secrets/index.js.map +1 -0
- package/dist/src/commands/secrets/set.d.ts +22 -0
- package/dist/src/commands/secrets/set.d.ts.map +1 -0
- package/dist/src/commands/secrets/set.js +234 -0
- package/dist/src/commands/secrets/set.js.map +1 -0
- package/dist/src/commands/stack.d.ts +17 -0
- package/dist/src/commands/stack.d.ts.map +1 -0
- package/dist/src/commands/stack.js +175 -0
- package/dist/src/commands/stack.js.map +1 -0
- package/dist/src/commands/tunnel/index.d.ts +14 -0
- package/dist/src/commands/tunnel/index.d.ts.map +1 -0
- package/dist/src/commands/tunnel/index.js +217 -0
- package/dist/src/commands/tunnel/index.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +7 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/utils/bastion.d.ts +43 -0
- package/dist/src/utils/bastion.d.ts.map +1 -0
- package/dist/src/utils/bastion.js +77 -0
- package/dist/src/utils/bastion.js.map +1 -0
- package/dist/src/utils/context.d.ts +29 -0
- package/dist/src/utils/context.d.ts.map +1 -0
- package/dist/src/utils/context.js +132 -0
- package/dist/src/utils/context.js.map +1 -0
- package/dist/src/utils/credentials.d.ts +61 -0
- package/dist/src/utils/credentials.d.ts.map +1 -0
- package/dist/src/utils/credentials.js +145 -0
- package/dist/src/utils/credentials.js.map +1 -0
- package/dist/src/utils/index.d.ts +9 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +9 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/log.d.ts +8 -0
- package/dist/src/utils/log.d.ts.map +1 -0
- package/dist/src/utils/log.js +17 -0
- package/dist/src/utils/log.js.map +1 -0
- package/dist/src/utils/pulumi.d.ts +24 -0
- package/dist/src/utils/pulumi.d.ts.map +1 -0
- package/dist/src/utils/pulumi.js +63 -0
- package/dist/src/utils/pulumi.js.map +1 -0
- package/package.json +50 -0
- package/templates/api-web-db/api/.dockerignore +2 -0
- package/templates/api-web-db/api/Dockerfile +16 -0
- package/templates/api-web-db/api/package.json.hbs +21 -0
- package/templates/api-web-db/api/src/index.ts.hbs +123 -0
- package/templates/api-web-db/api/tsconfig.json +13 -0
- package/templates/api-web-db/package.json.hbs +27 -0
- package/templates/api-web-db/sst.config.ts.hbs +151 -0
- package/templates/api-web-db/tsconfig.json +11 -0
- package/templates/api-web-db/web/.dockerignore +3 -0
- package/templates/api-web-db/web/Dockerfile +17 -0
- package/templates/api-web-db/web/app/lib/db.server.ts +36 -0
- package/templates/api-web-db/web/app/root.tsx +29 -0
- package/templates/api-web-db/web/app/routes/home.tsx.hbs +114 -0
- package/templates/api-web-db/web/app/routes.ts +3 -0
- package/templates/api-web-db/web/package.json.hbs +30 -0
- package/templates/api-web-db/web/prisma/schema.prisma +25 -0
- package/templates/api-web-db/web/prisma.config.ts +18 -0
- package/templates/api-web-db/web/react-router.config.ts +5 -0
- package/templates/api-web-db/web/tsconfig.json +19 -0
- package/templates/api-web-db/web/vite.config.ts +9 -0
- package/templates/temporal-api-worker/README.md.hbs +133 -0
- package/templates/temporal-api-worker/api/.dockerignore +4 -0
- package/templates/temporal-api-worker/api/Dockerfile +13 -0
- package/templates/temporal-api-worker/api/package.json.hbs +23 -0
- package/templates/temporal-api-worker/api/src/encryption-codec.ts +133 -0
- package/templates/temporal-api-worker/api/src/index.ts.hbs +145 -0
- package/templates/temporal-api-worker/api/tsconfig.json +14 -0
- package/templates/temporal-api-worker/package.json.hbs +29 -0
- package/templates/temporal-api-worker/sst.config.ts.hbs +161 -0
- package/templates/temporal-api-worker/tsconfig.json +10 -0
- package/templates/temporal-api-worker/worker/.dockerignore +4 -0
- package/templates/temporal-api-worker/worker/Dockerfile +11 -0
- package/templates/temporal-api-worker/worker/package.json.hbs +25 -0
- package/templates/temporal-api-worker/worker/src/activities.ts.hbs +49 -0
- package/templates/temporal-api-worker/worker/src/bundle-workflows.ts +38 -0
- package/templates/temporal-api-worker/worker/src/encryption-codec.ts +156 -0
- package/templates/temporal-api-worker/worker/src/worker.ts.hbs +93 -0
- package/templates/temporal-api-worker/worker/src/workflows.ts.hbs +60 -0
- package/templates/temporal-api-worker/worker/tsconfig.json +14 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database credential utilities
|
|
3
|
+
*/
|
|
4
|
+
import { SecretsManagerClient, GetSecretValueCommand, } from "@aws-sdk/client-secrets-manager";
|
|
5
|
+
import { logInfo, logSuccess } from "./log.js";
|
|
6
|
+
/**
|
|
7
|
+
* Get DATABASE_URL from Secrets Manager.
|
|
8
|
+
*
|
|
9
|
+
* Credential path patterns:
|
|
10
|
+
* - With app: mesh/{tenant}/{stage}/{app}/db-credentials
|
|
11
|
+
* - Without app: mesh/{tenant}/{stage}/db-credentials
|
|
12
|
+
*
|
|
13
|
+
* Returns the DATABASE_URL string directly. Use rewriteDatabaseUrl() to
|
|
14
|
+
* modify host/port for tunnel usage.
|
|
15
|
+
*/
|
|
16
|
+
export async function getDatabaseUrl(tenant, stage, options) {
|
|
17
|
+
const secretsManager = new SecretsManagerClient({});
|
|
18
|
+
// Build secret path - with or without app name
|
|
19
|
+
const secretName = options?.app
|
|
20
|
+
? `mesh/${tenant}/${stage}/${options.app}/db-credentials`
|
|
21
|
+
: `mesh/${tenant}/${stage}/db-credentials`;
|
|
22
|
+
logInfo(`Looking up credentials at ${secretName}...`);
|
|
23
|
+
try {
|
|
24
|
+
const response = await secretsManager.send(new GetSecretValueCommand({ SecretId: secretName }));
|
|
25
|
+
if (response.SecretString) {
|
|
26
|
+
const secret = JSON.parse(response.SecretString);
|
|
27
|
+
// Handle DATABASE_URL format (preferred)
|
|
28
|
+
if (secret.DATABASE_URL) {
|
|
29
|
+
const parsed = new URL(secret.DATABASE_URL);
|
|
30
|
+
logSuccess(`Got credentials for user: ${parsed.username}`);
|
|
31
|
+
return secret.DATABASE_URL;
|
|
32
|
+
}
|
|
33
|
+
// Handle individual fields format (legacy)
|
|
34
|
+
if (secret.username && secret.password) {
|
|
35
|
+
logSuccess(`Got credentials for user: ${secret.username}`);
|
|
36
|
+
const database = secret.dbname ?? secret.database ?? "postgres";
|
|
37
|
+
return `postgresql://${secret.username}:${encodeURIComponent(secret.password)}@${secret.host ?? "localhost"}:${secret.port ?? 5432}/${database}`;
|
|
38
|
+
}
|
|
39
|
+
throw new Error(`Secret ${secretName} has unexpected format (needs DATABASE_URL or username/password)`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error.message?.includes("unexpected format")) {
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
// Secret not found - will be caught by caller
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Could not find credentials at ${secretName}`);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @deprecated Use getDatabaseUrl instead - returns DATABASE_URL directly
|
|
52
|
+
*/
|
|
53
|
+
export async function getDbCredentials(tenant, stage, _platformEnv, rdsHost, rdsPort, options) {
|
|
54
|
+
const databaseUrl = await getDatabaseUrl(tenant, stage, options);
|
|
55
|
+
const parsed = new URL(databaseUrl);
|
|
56
|
+
return {
|
|
57
|
+
username: parsed.username,
|
|
58
|
+
password: decodeURIComponent(parsed.password),
|
|
59
|
+
host: rdsHost,
|
|
60
|
+
port: rdsPort,
|
|
61
|
+
database: parsed.pathname.slice(1),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Rewrite DATABASE_URL with new endpoint and/or SSL mode.
|
|
66
|
+
* Preserves username, password, database name, and other query params.
|
|
67
|
+
*
|
|
68
|
+
* Used by both mesh-env-exec (for sst dev) and mesh db exec (for ad-hoc commands).
|
|
69
|
+
*/
|
|
70
|
+
export function rewriteDatabaseUrl(url, options) {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = new URL(url);
|
|
73
|
+
// Rewrite endpoint if provided
|
|
74
|
+
if (options.endpoint) {
|
|
75
|
+
if (options.endpoint.includes(":")) {
|
|
76
|
+
const colonIndex = options.endpoint.lastIndexOf(":");
|
|
77
|
+
parsed.hostname = options.endpoint.slice(0, colonIndex);
|
|
78
|
+
parsed.port = options.endpoint.slice(colonIndex + 1);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
parsed.hostname = options.endpoint;
|
|
82
|
+
parsed.port = parsed.port || "5432";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Set SSL mode if provided
|
|
86
|
+
if (options.sslMode) {
|
|
87
|
+
parsed.searchParams.set("sslmode", options.sslMode);
|
|
88
|
+
// For Prisma: accept invalid/self-signed certificates through tunnels
|
|
89
|
+
if (options.sslMode === "require" || options.sslMode === "no-verify") {
|
|
90
|
+
parsed.searchParams.set("sslaccept", "accept_invalid_certs");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return parsed.toString();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// If URL parsing fails, return original
|
|
97
|
+
return url;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Build a DATABASE_URL from credentials.
|
|
102
|
+
*/
|
|
103
|
+
export function buildDatabaseUrl(creds, options) {
|
|
104
|
+
const host = options?.endpoint?.split(":")[0] ?? creds.host;
|
|
105
|
+
const port = options?.endpoint?.split(":")[1] ?? String(creds.port);
|
|
106
|
+
let url = `postgresql://${creds.username}:${encodeURIComponent(creds.password)}@${host}:${port}/${creds.database}`;
|
|
107
|
+
if (options?.sslMode) {
|
|
108
|
+
url += `?sslmode=${options.sslMode}`;
|
|
109
|
+
if (options.sslMode === "require" || options.sslMode === "no-verify") {
|
|
110
|
+
url += "&sslaccept=accept_invalid_certs";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return url;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Try to read database info from SST outputs (when sst dev has run).
|
|
117
|
+
*/
|
|
118
|
+
export async function readSstOutputs() {
|
|
119
|
+
const fs = await import("fs");
|
|
120
|
+
if (!fs.existsSync(".sst/outputs.json")) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const content = fs.readFileSync(".sst/outputs.json", "utf-8");
|
|
125
|
+
const outputs = JSON.parse(content);
|
|
126
|
+
if (outputs.databaseUrl) {
|
|
127
|
+
logInfo("Found SST outputs with database config");
|
|
128
|
+
// Extract secret ARN from URL if present
|
|
129
|
+
const secretArnMatch = outputs.databaseUrl.match(/secretArn=([^&]+)/);
|
|
130
|
+
const secretArn = secretArnMatch
|
|
131
|
+
? decodeURIComponent(secretArnMatch[1])
|
|
132
|
+
: undefined;
|
|
133
|
+
return {
|
|
134
|
+
databaseUrl: outputs.databaseUrl,
|
|
135
|
+
databaseName: outputs.databaseName,
|
|
136
|
+
secretArn,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Ignore parse errors
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../../src/utils/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities with colored output
|
|
3
|
+
*/
|
|
4
|
+
export declare function logInfo(message: string): void;
|
|
5
|
+
export declare function logSuccess(message: string): void;
|
|
6
|
+
export declare function logWarn(message: string): void;
|
|
7
|
+
export declare function logError(message: string): void;
|
|
8
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../../src/utils/log.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities with colored output
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
export function logInfo(message) {
|
|
6
|
+
console.error(chalk.blue("ℹ"), message);
|
|
7
|
+
}
|
|
8
|
+
export function logSuccess(message) {
|
|
9
|
+
console.error(chalk.green("✓"), message);
|
|
10
|
+
}
|
|
11
|
+
export function logWarn(message) {
|
|
12
|
+
console.error(chalk.yellow("⚠"), message);
|
|
13
|
+
}
|
|
14
|
+
export function logError(message) {
|
|
15
|
+
console.error(chalk.red("✗"), message);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../../src/utils/log.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulumi-related utilities shared across CLI commands.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Find the Pulumi app root by walking up from a starting directory.
|
|
6
|
+
* Returns the first directory containing `Pulumi.yaml`, or null.
|
|
7
|
+
*/
|
|
8
|
+
export declare function findAppRoot(startDir: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Find Pulumi.<stack>.yaml files in a directory.
|
|
11
|
+
* Returns an array of stack names (without the Pulumi. prefix and .yaml suffix).
|
|
12
|
+
*/
|
|
13
|
+
export declare function findStackConfigs(appRoot: string): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Get the currently selected Pulumi stack name, or null.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getCurrentStack(appRoot: string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Read a config value from Pulumi.<stack>.yaml.
|
|
20
|
+
* Simple regex-based parser — handles single-line string values.
|
|
21
|
+
* For complex values, use `pulumi config` CLI instead.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readStackConfig(appRoot: string, stack: string, key: string): string | null;
|
|
24
|
+
//# sourceMappingURL=pulumi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulumi.d.ts","sourceRoot":"","sources":["../../../src/utils/pulumi.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ3D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAI1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU1F"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulumi-related utilities shared across CLI commands.
|
|
3
|
+
*/
|
|
4
|
+
import { execFileSync } from "child_process";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
/**
|
|
8
|
+
* Find the Pulumi app root by walking up from a starting directory.
|
|
9
|
+
* Returns the first directory containing `Pulumi.yaml`, or null.
|
|
10
|
+
*/
|
|
11
|
+
export function findAppRoot(startDir) {
|
|
12
|
+
let dir = startDir;
|
|
13
|
+
while (true) {
|
|
14
|
+
if (fs.existsSync(path.join(dir, "Pulumi.yaml")))
|
|
15
|
+
return dir;
|
|
16
|
+
const parent = path.dirname(dir);
|
|
17
|
+
if (parent === dir)
|
|
18
|
+
return null;
|
|
19
|
+
dir = parent;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Find Pulumi.<stack>.yaml files in a directory.
|
|
24
|
+
* Returns an array of stack names (without the Pulumi. prefix and .yaml suffix).
|
|
25
|
+
*/
|
|
26
|
+
export function findStackConfigs(appRoot) {
|
|
27
|
+
return fs.readdirSync(appRoot)
|
|
28
|
+
.filter((f) => /^Pulumi\..+\.yaml$/.test(f) && f !== "Pulumi.yaml")
|
|
29
|
+
.map((f) => f.replace(/^Pulumi\./, "").replace(/\.yaml$/, ""));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the currently selected Pulumi stack name, or null.
|
|
33
|
+
*/
|
|
34
|
+
export function getCurrentStack(appRoot) {
|
|
35
|
+
try {
|
|
36
|
+
const result = execFileSync("pulumi", ["stack", "--show-name"], {
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
cwd: appRoot,
|
|
39
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
40
|
+
});
|
|
41
|
+
return result.trim() || null;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Read a config value from Pulumi.<stack>.yaml.
|
|
49
|
+
* Simple regex-based parser — handles single-line string values.
|
|
50
|
+
* For complex values, use `pulumi config` CLI instead.
|
|
51
|
+
*/
|
|
52
|
+
export function readStackConfig(appRoot, stack, key) {
|
|
53
|
+
const configFile = path.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
54
|
+
if (!fs.existsSync(configFile))
|
|
55
|
+
return null;
|
|
56
|
+
const content = fs.readFileSync(configFile, "utf-8");
|
|
57
|
+
const pattern = new RegExp(`^\\s+${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*(.+)$`, "m");
|
|
58
|
+
const match = content.match(pattern);
|
|
59
|
+
if (!match)
|
|
60
|
+
return null;
|
|
61
|
+
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=pulumi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulumi.js","sourceRoot":"","sources":["../../../src/utils/pulumi.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC;SAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,aAAa,CAAC;SAClE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE;YAC9D,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,KAAa,EAAE,GAAW;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC;IAC9D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAChG,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mesh-tech/mesh-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Mesh platform development — auth, deploy, registry, tunnels, and more",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/mesh-tech/mesh-platform.git",
|
|
10
|
+
"directory": "libs/mesh-cli"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"mesh": "./dist/bin/mesh.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"templates"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public",
|
|
21
|
+
"registry": "https://registry.npmjs.org"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"prepublishOnly": "tsc"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/src/index.d.ts",
|
|
32
|
+
"default": "./dist/src/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@aws-sdk/client-secrets-manager": "^3.700.0",
|
|
40
|
+
"@aws-sdk/client-ssm": "^3.700.0",
|
|
41
|
+
"@inquirer/input": "^5.0.8",
|
|
42
|
+
"@inquirer/password": "^5.0.8",
|
|
43
|
+
"chalk": "^5.3.0",
|
|
44
|
+
"commander": "^12.1.0",
|
|
45
|
+
"handlebars": "^4.7.8"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=20.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
FROM node:22-alpine AS builder
|
|
2
|
+
WORKDIR /app
|
|
3
|
+
COPY package.json ./
|
|
4
|
+
RUN npm install
|
|
5
|
+
COPY tsconfig.json ./
|
|
6
|
+
COPY src ./src
|
|
7
|
+
RUN npm run build
|
|
8
|
+
|
|
9
|
+
FROM node:22-alpine
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
COPY package.json ./
|
|
12
|
+
RUN npm install --omit=dev
|
|
13
|
+
COPY --from=builder /app/dist ./dist
|
|
14
|
+
ENV NODE_ENV=production PORT=3001
|
|
15
|
+
EXPOSE 3001
|
|
16
|
+
CMD ["node", "dist/index.js"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}-api",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "tsx watch src/index.ts",
|
|
6
|
+
"build": "tsc",
|
|
7
|
+
"start": "node dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@aws-sdk/client-secrets-manager": "^3.964.0",
|
|
11
|
+
"@hono/node-server": "^1.13.7",
|
|
12
|
+
"hono": "^4.6.14",
|
|
13
|
+
"pg": "^8.16.3"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^22.10.5",
|
|
17
|
+
"@types/pg": "^8.16.0",
|
|
18
|
+
"tsx": "^4.19.2",
|
|
19
|
+
"typescript": "^5.7.2"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { serve } from "@hono/node-server";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { cors } from "hono/cors";
|
|
4
|
+
import { logger } from "hono/logger";
|
|
5
|
+
import { Pool } from "pg";
|
|
6
|
+
import {
|
|
7
|
+
SecretsManagerClient,
|
|
8
|
+
GetSecretValueCommand,
|
|
9
|
+
} from "@aws-sdk/client-secrets-manager";
|
|
10
|
+
|
|
11
|
+
const app = new Hono();
|
|
12
|
+
|
|
13
|
+
// Middleware
|
|
14
|
+
app.use("*", logger());
|
|
15
|
+
app.use("*", cors());
|
|
16
|
+
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Database Connection
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
21
|
+
let dbPool: Pool | null = null;
|
|
22
|
+
|
|
23
|
+
async function getDbPassword(): Promise<string> {
|
|
24
|
+
const secretArn = process.env.DB_SECRET_ARN;
|
|
25
|
+
if (!secretArn) {
|
|
26
|
+
throw new Error("DB_SECRET_ARN not configured");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const client = new SecretsManagerClient({ region: "us-east-1" });
|
|
30
|
+
const response = await client.send(
|
|
31
|
+
new GetSecretValueCommand({ SecretId: secretArn })
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (!response.SecretString) {
|
|
35
|
+
throw new Error("No secret value found");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const secret = JSON.parse(response.SecretString);
|
|
39
|
+
return secret.password;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function getDbPool(): Promise<Pool> {
|
|
43
|
+
if (dbPool) return dbPool;
|
|
44
|
+
|
|
45
|
+
const password = await getDbPassword();
|
|
46
|
+
|
|
47
|
+
dbPool = new Pool({
|
|
48
|
+
host: process.env.DB_HOST || "localhost",
|
|
49
|
+
port: parseInt(process.env.DB_PORT || "5432", 10),
|
|
50
|
+
database: process.env.DB_NAME || "postgres",
|
|
51
|
+
user: process.env.DB_USER || "postgres",
|
|
52
|
+
password,
|
|
53
|
+
ssl: { rejectUnauthorized: false },
|
|
54
|
+
max: 10,
|
|
55
|
+
idleTimeoutMillis: 30000,
|
|
56
|
+
connectionTimeoutMillis: 5000,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return dbPool;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// Routes
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
// Root - API info
|
|
67
|
+
app.get("/", (c) =>
|
|
68
|
+
c.json({
|
|
69
|
+
name: "{{name}}-api",
|
|
70
|
+
version: "1.0.0",
|
|
71
|
+
endpoints: ["/health", "/hello", "/db"],
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Health check (required for ALB)
|
|
76
|
+
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
77
|
+
|
|
78
|
+
// Hello endpoint
|
|
79
|
+
app.get("/hello", (c) => {
|
|
80
|
+
return c.json({
|
|
81
|
+
message: "Hello from {{name}} API!",
|
|
82
|
+
stage: process.env.STAGE || "unknown",
|
|
83
|
+
timestamp: new Date().toISOString(),
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Database endpoint
|
|
88
|
+
app.get("/db", async (c) => {
|
|
89
|
+
try {
|
|
90
|
+
const pool = await getDbPool();
|
|
91
|
+
const result = await pool.query(
|
|
92
|
+
"SELECT version(), current_database(), current_user"
|
|
93
|
+
);
|
|
94
|
+
const row = result.rows[0];
|
|
95
|
+
|
|
96
|
+
return c.json({
|
|
97
|
+
status: "connected",
|
|
98
|
+
database: row.current_database,
|
|
99
|
+
user: row.current_user,
|
|
100
|
+
version: row.version,
|
|
101
|
+
timestamp: new Date().toISOString(),
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return c.json(
|
|
105
|
+
{
|
|
106
|
+
status: "error",
|
|
107
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
108
|
+
},
|
|
109
|
+
500
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// =============================================================================
|
|
115
|
+
// Start Server
|
|
116
|
+
// =============================================================================
|
|
117
|
+
|
|
118
|
+
const port = parseInt(process.env.PORT || "3001", 10);
|
|
119
|
+
console.log(`API server starting on port ${port}...`);
|
|
120
|
+
|
|
121
|
+
serve({ fetch: app.fetch, port });
|
|
122
|
+
|
|
123
|
+
console.log(`API server running at http://localhost:${port}`);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"typecheck": "tsc --noEmit",
|
|
7
|
+
"sst:patch": "patch-sst-pulumi .",
|
|
8
|
+
"dev": "pnpm run sst:patch && sst dev",
|
|
9
|
+
"deploy": "pnpm run sst:patch && sst deploy",
|
|
10
|
+
"deploy:dev": "pnpm run sst:patch && sst deploy --stage dev",
|
|
11
|
+
"deploy:prod": "pnpm run sst:patch && sst deploy --stage prod",
|
|
12
|
+
"remove": "sst remove"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@mesh-tech/infra-components": "workspace:*",
|
|
16
|
+
"@pulumi/aws": "6.66.2",
|
|
17
|
+
"@pulumi/docker-build": "^0.0.15",
|
|
18
|
+
"@pulumi/eks": "4.2.0",
|
|
19
|
+
"@pulumi/kubernetes": "4.24.1",
|
|
20
|
+
"@pulumi/pulumi": "3.214.1",
|
|
21
|
+
"sst": "^3.3.61"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@aws-sdk/credential-providers": "^3.964.0",
|
|
25
|
+
"typescript": "^5.7.2"
|
|
26
|
+
}
|
|
27
|
+
}
|