@geekmidas/cli 1.3.0 → 1.5.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/CHANGELOG.md +12 -0
- package/dist/{Route53Provider-xrWuBXih.cjs → Route53Provider-Bs7Arms9.cjs} +3 -2
- package/dist/Route53Provider-Bs7Arms9.cjs.map +1 -0
- package/dist/{Route53Provider-DOWmFnwN.mjs → Route53Provider-C8mS0zY6.mjs} +3 -2
- package/dist/Route53Provider-C8mS0zY6.mjs.map +1 -0
- package/dist/{config-C1bidhvG.mjs → config-DfCJ29PQ.mjs} +2 -2
- package/dist/{config-C1bidhvG.mjs.map → config-DfCJ29PQ.mjs.map} +1 -1
- package/dist/{config-C1dM7aZb.cjs → config-ZQM1vBoz.cjs} +2 -2
- package/dist/{config-C1dM7aZb.cjs.map → config-ZQM1vBoz.cjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +2 -2
- package/dist/{index-DzmZ6SUW.d.cts → index-B58qjyBd.d.cts} +27 -1
- package/dist/index-B58qjyBd.d.cts.map +1 -0
- package/dist/{index-DvpWzLD7.d.mts → index-C0SpUT9Y.d.mts} +27 -1
- package/dist/index-C0SpUT9Y.d.mts.map +1 -0
- package/dist/index.cjs +117 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +117 -49
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-9k6a6VA4.mjs → openapi-BcSjLfWq.mjs} +2 -2
- package/dist/{openapi-9k6a6VA4.mjs.map → openapi-BcSjLfWq.mjs.map} +1 -1
- package/dist/{openapi-Dcja4e1C.cjs → openapi-D6Hcfov0.cjs} +2 -2
- package/dist/{openapi-Dcja4e1C.cjs.map → openapi-D6Hcfov0.cjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.mjs +3 -3
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +1 -1
- package/dist/workspace/index.d.mts +1 -1
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-CeFgIDC-.cjs → workspace-2Do2YcGZ.cjs} +5 -1
- package/dist/{workspace-CeFgIDC-.cjs.map → workspace-2Do2YcGZ.cjs.map} +1 -1
- package/dist/{workspace-Cb_I7oCJ.mjs → workspace-BW2iU37P.mjs} +5 -1
- package/dist/{workspace-Cb_I7oCJ.mjs.map → workspace-BW2iU37P.mjs.map} +1 -1
- package/package.json +2 -2
- package/src/deploy/__tests__/Route53Provider.spec.ts +23 -0
- package/src/deploy/__tests__/env-resolver.spec.ts +384 -2
- package/src/deploy/__tests__/index.spec.ts +393 -5
- package/src/deploy/__tests__/sniffer.spec.ts +104 -93
- package/src/deploy/dns/Route53Provider.ts +4 -1
- package/src/deploy/env-resolver.ts +20 -0
- package/src/deploy/index.ts +83 -24
- package/src/deploy/sniffer.ts +39 -7
- package/src/init/generators/monorepo.ts +7 -1
- package/src/init/generators/web.ts +45 -2
- package/src/workspace/schema.ts +8 -0
- package/src/workspace/types.ts +23 -0
- package/dist/Route53Provider-DOWmFnwN.mjs.map +0 -1
- package/dist/Route53Provider-xrWuBXih.cjs.map +0 -1
- package/dist/index-DvpWzLD7.d.mts.map +0 -1
- package/dist/index-DzmZ6SUW.d.cts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
import { __require } from "./chunk-Duj1WY3L.mjs";
|
|
3
|
-
import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-
|
|
4
|
-
import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-
|
|
3
|
+
import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-BW2iU37P.mjs";
|
|
4
|
+
import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-DfCJ29PQ.mjs";
|
|
5
5
|
import { getCredentialsPath, getDokployCredentials, getDokployRegistryId, getDokployToken, removeDokployCredentials, storeDokployCredentials, storeDokployRegistryId } from "./credentials-s1kLcIzK.mjs";
|
|
6
|
-
import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-
|
|
6
|
+
import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-BcSjLfWq.mjs";
|
|
7
7
|
import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-DmCbr6DI.mjs";
|
|
8
8
|
import { DokployApi } from "./dokploy-api-z0833e7r.mjs";
|
|
9
9
|
import { encryptSecrets } from "./encryption-BOH5M-f-.mjs";
|
|
@@ -32,7 +32,7 @@ import prompts from "prompts";
|
|
|
32
32
|
|
|
33
33
|
//#region package.json
|
|
34
34
|
var name = "@geekmidas/cli";
|
|
35
|
-
var version = "1.
|
|
35
|
+
var version = "1.4.0";
|
|
36
36
|
var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
|
|
37
37
|
var private$1 = false;
|
|
38
38
|
var type = "module";
|
|
@@ -2203,7 +2203,7 @@ async function createDnsProvider(options) {
|
|
|
2203
2203
|
return new HostingerProvider();
|
|
2204
2204
|
}
|
|
2205
2205
|
if (provider === "route53") {
|
|
2206
|
-
const { Route53Provider } = await import("./Route53Provider-
|
|
2206
|
+
const { Route53Provider } = await import("./Route53Provider-C8mS0zY6.mjs");
|
|
2207
2207
|
const route53Config = config$1;
|
|
2208
2208
|
return new Route53Provider({
|
|
2209
2209
|
region: route53Config.region,
|
|
@@ -4137,33 +4137,6 @@ function isMainFrontendApp(appName, app, allApps) {
|
|
|
4137
4137
|
for (const [name$1, a] of Object.entries(allApps)) if (a.type === "frontend") return name$1 === appName;
|
|
4138
4138
|
return false;
|
|
4139
4139
|
}
|
|
4140
|
-
/**
|
|
4141
|
-
* Generate public URL build args for a frontend app based on its dependencies.
|
|
4142
|
-
*
|
|
4143
|
-
* @param app - The frontend app configuration
|
|
4144
|
-
* @param deployedUrls - Map of app name to deployed public URL
|
|
4145
|
-
* @returns Array of build args like 'NEXT_PUBLIC_API_URL=https://api.example.com'
|
|
4146
|
-
*/
|
|
4147
|
-
function generatePublicUrlBuildArgs(app, deployedUrls) {
|
|
4148
|
-
const buildArgs = [];
|
|
4149
|
-
for (const dep of app.dependencies) {
|
|
4150
|
-
const publicUrl = deployedUrls[dep];
|
|
4151
|
-
if (publicUrl) {
|
|
4152
|
-
const envVarName = `NEXT_PUBLIC_${dep.toUpperCase()}_URL`;
|
|
4153
|
-
buildArgs.push(`${envVarName}=${publicUrl}`);
|
|
4154
|
-
}
|
|
4155
|
-
}
|
|
4156
|
-
return buildArgs;
|
|
4157
|
-
}
|
|
4158
|
-
/**
|
|
4159
|
-
* Get public URL arg names from app dependencies.
|
|
4160
|
-
*
|
|
4161
|
-
* @param app - The frontend app configuration
|
|
4162
|
-
* @returns Array of arg names like 'NEXT_PUBLIC_API_URL'
|
|
4163
|
-
*/
|
|
4164
|
-
function getPublicUrlArgNames(app) {
|
|
4165
|
-
return app.dependencies.map((dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`);
|
|
4166
|
-
}
|
|
4167
4140
|
|
|
4168
4141
|
//#endregion
|
|
4169
4142
|
//#region src/deploy/env-resolver.ts
|
|
@@ -4224,6 +4197,12 @@ function resolveEnvVar(varName, context) {
|
|
|
4224
4197
|
if (context.masterKey) return context.masterKey;
|
|
4225
4198
|
break;
|
|
4226
4199
|
}
|
|
4200
|
+
if (context.dependencyUrls && varName.endsWith("_URL")) {
|
|
4201
|
+
let depName;
|
|
4202
|
+
if (varName.startsWith("NEXT_PUBLIC_")) depName = varName.slice(12, -4).toLowerCase();
|
|
4203
|
+
else depName = varName.slice(0, -4).toLowerCase();
|
|
4204
|
+
if (context.dependencyUrls[depName]) return context.dependencyUrls[depName];
|
|
4205
|
+
}
|
|
4227
4206
|
if (context.userSecrets) {
|
|
4228
4207
|
if (context.userSecrets.custom[varName]) return context.userSecrets.custom[varName];
|
|
4229
4208
|
if (varName in context.userSecrets.urls) return context.userSecrets.urls[varName];
|
|
@@ -4633,14 +4612,29 @@ function resolveSnifferFile(baseName) {
|
|
|
4633
4612
|
*/
|
|
4634
4613
|
async function sniffAppEnvironment(app, appName, workspacePath, options = {}) {
|
|
4635
4614
|
const { logWarnings = true } = options;
|
|
4636
|
-
if (app.type === "frontend")
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4615
|
+
if (app.type === "frontend") {
|
|
4616
|
+
const depVars = (app.dependencies ?? []).map((dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`);
|
|
4617
|
+
if (app.config) {
|
|
4618
|
+
const sniffedVars = [];
|
|
4619
|
+
const configPaths = [];
|
|
4620
|
+
if (app.config.client) configPaths.push(app.config.client);
|
|
4621
|
+
if (app.config.server) configPaths.push(app.config.server);
|
|
4622
|
+
for (const configPath of configPaths) {
|
|
4623
|
+
const result = await sniffEntryFile(configPath, app.path, workspacePath);
|
|
4624
|
+
if (logWarnings && result.error) console.warn(`[sniffer] ${appName}: Config file "${configPath}" threw error during sniffing (env vars still captured): ${result.error.message}`);
|
|
4625
|
+
sniffedVars.push(...result.envVars);
|
|
4626
|
+
}
|
|
4627
|
+
const allVars = [...new Set([...depVars, ...sniffedVars])];
|
|
4628
|
+
return {
|
|
4629
|
+
appName,
|
|
4630
|
+
requiredEnvVars: allVars
|
|
4631
|
+
};
|
|
4632
|
+
}
|
|
4633
|
+
return {
|
|
4634
|
+
appName,
|
|
4635
|
+
requiredEnvVars: depVars
|
|
4636
|
+
};
|
|
4637
|
+
}
|
|
4644
4638
|
if (app.entry) {
|
|
4645
4639
|
const result = await sniffEntryFile(app.entry, app.path, workspacePath);
|
|
4646
4640
|
if (logWarnings && result.error) console.warn(`[sniffer] ${appName}: Entry file threw error during sniffing (env vars still captured): ${result.error.message}`);
|
|
@@ -5596,6 +5590,10 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
5596
5590
|
buildArgs
|
|
5597
5591
|
});
|
|
5598
5592
|
const backendHost = resolveHost(appName, app, stage, dokployConfig, false);
|
|
5593
|
+
const dependencyUrls = {};
|
|
5594
|
+
if (app.dependencies) {
|
|
5595
|
+
for (const dep of app.dependencies) if (publicUrls[dep]) dependencyUrls[dep] = publicUrls[dep];
|
|
5596
|
+
}
|
|
5599
5597
|
const envContext = {
|
|
5600
5598
|
app,
|
|
5601
5599
|
appName,
|
|
@@ -5615,7 +5613,8 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
5615
5613
|
appHostname: backendHost,
|
|
5616
5614
|
frontendUrls,
|
|
5617
5615
|
userSecrets: stageSecrets ?? void 0,
|
|
5618
|
-
masterKey: appSecrets?.masterKey
|
|
5616
|
+
masterKey: appSecrets?.masterKey,
|
|
5617
|
+
dependencyUrls
|
|
5619
5618
|
};
|
|
5620
5619
|
const appRequirements = sniffedApps.get(appName);
|
|
5621
5620
|
const sniffedVars = appRequirements?.requiredEnvVars ?? [];
|
|
@@ -5701,8 +5700,33 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
5701
5700
|
else logger$1.log(` Found existing application: ${application.applicationId}`);
|
|
5702
5701
|
}
|
|
5703
5702
|
setApplicationId(state, appName, application.applicationId);
|
|
5704
|
-
const
|
|
5705
|
-
if (
|
|
5703
|
+
const dependencyUrls = {};
|
|
5704
|
+
if (app.dependencies) {
|
|
5705
|
+
for (const dep of app.dependencies) if (publicUrls[dep]) dependencyUrls[dep] = publicUrls[dep];
|
|
5706
|
+
}
|
|
5707
|
+
const isMainFrontend = isMainFrontendApp(appName, app, workspace.apps);
|
|
5708
|
+
const frontendHost = resolveHost(appName, app, stage, dokployConfig, isMainFrontend);
|
|
5709
|
+
const envContext = {
|
|
5710
|
+
app,
|
|
5711
|
+
appName,
|
|
5712
|
+
stage,
|
|
5713
|
+
state,
|
|
5714
|
+
appHostname: frontendHost,
|
|
5715
|
+
frontendUrls: [],
|
|
5716
|
+
userSecrets: stageSecrets ?? void 0,
|
|
5717
|
+
dependencyUrls
|
|
5718
|
+
};
|
|
5719
|
+
const sniffedVars = sniffedApps.get(appName)?.requiredEnvVars ?? [];
|
|
5720
|
+
const { valid, missing, resolved } = validateEnvVars(sniffedVars, envContext);
|
|
5721
|
+
if (!valid) throw new Error(formatMissingVarsError(appName, missing, stage));
|
|
5722
|
+
if (Object.keys(resolved).length > 0) logger$1.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
|
|
5723
|
+
const buildArgs = [];
|
|
5724
|
+
const publicUrlArgNames = [];
|
|
5725
|
+
for (const [key, value] of Object.entries(resolved)) if (key.startsWith("NEXT_PUBLIC_")) {
|
|
5726
|
+
buildArgs.push(`${key}=${value}`);
|
|
5727
|
+
publicUrlArgNames.push(key);
|
|
5728
|
+
}
|
|
5729
|
+
if (buildArgs.length > 0) logger$1.log(` Build args: ${publicUrlArgNames.join(", ")}`);
|
|
5706
5730
|
const imageName = `${workspace.name}-${appName}`;
|
|
5707
5731
|
const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
|
|
5708
5732
|
logger$1.log(` Building Docker image: ${imageRef}`);
|
|
@@ -5716,19 +5740,18 @@ async function workspaceDeployCommand(workspace, options) {
|
|
|
5716
5740
|
appName
|
|
5717
5741
|
},
|
|
5718
5742
|
buildArgs,
|
|
5719
|
-
publicUrlArgs:
|
|
5743
|
+
publicUrlArgs: publicUrlArgNames
|
|
5720
5744
|
});
|
|
5721
5745
|
const envVars = [
|
|
5722
5746
|
`NODE_ENV=production`,
|
|
5723
5747
|
`PORT=${app.port}`,
|
|
5724
5748
|
`STAGE=${stage}`
|
|
5725
5749
|
];
|
|
5750
|
+
for (const [key, value] of Object.entries(resolved)) envVars.push(`${key}=${value}`);
|
|
5726
5751
|
await api.saveDockerProvider(application.applicationId, imageRef, { registryId });
|
|
5727
5752
|
await api.saveApplicationEnv(application.applicationId, envVars.join("\n"));
|
|
5728
5753
|
logger$1.log(` Deploying to Dokploy...`);
|
|
5729
5754
|
await api.deployApplication(application.applicationId);
|
|
5730
|
-
const isMainFrontend = isMainFrontendApp(appName, app, workspace.apps);
|
|
5731
|
-
const frontendHost = resolveHost(appName, app, stage, dokployConfig, isMainFrontend);
|
|
5732
5755
|
const existingFrontendDomains = await api.getDomainsByApplicationId(application.applicationId);
|
|
5733
5756
|
const existingFrontendDomain = existingFrontendDomains.find((d) => d.host === frontendHost);
|
|
5734
5757
|
if (existingFrontendDomain) {
|
|
@@ -7083,6 +7106,7 @@ function generateMonorepoFiles(options, _template) {
|
|
|
7083
7106
|
"@biomejs/biome": "~2.3.0",
|
|
7084
7107
|
"@geekmidas/cli": GEEKMIDAS_VERSIONS["@geekmidas/cli"],
|
|
7085
7108
|
esbuild: "~0.27.0",
|
|
7109
|
+
tsx: "~4.20.0",
|
|
7086
7110
|
turbo: "~2.3.0",
|
|
7087
7111
|
typescript: "~5.8.2",
|
|
7088
7112
|
vitest: "~4.0.0"
|
|
@@ -7329,7 +7353,8 @@ export default defineWorkspace({
|
|
|
7329
7353
|
port: 3000,
|
|
7330
7354
|
routes: '${getRoutesGlob()}',
|
|
7331
7355
|
envParser: './src/config/env#envParser',
|
|
7332
|
-
logger: './src/config/logger#logger'
|
|
7356
|
+
logger: './src/config/logger#logger',
|
|
7357
|
+
dependencies: ['auth'],`;
|
|
7333
7358
|
if (telescope) config$1 += `
|
|
7334
7359
|
telescope: {
|
|
7335
7360
|
enabled: true,
|
|
@@ -7354,6 +7379,10 @@ export default defineWorkspace({
|
|
|
7354
7379
|
path: 'apps/web',
|
|
7355
7380
|
port: 3001,
|
|
7356
7381
|
dependencies: ['api', 'auth'],
|
|
7382
|
+
config: {
|
|
7383
|
+
client: './src/config/client.ts',
|
|
7384
|
+
server: './src/config/server.ts',
|
|
7385
|
+
},
|
|
7357
7386
|
client: {
|
|
7358
7387
|
output: './src/api',
|
|
7359
7388
|
},
|
|
@@ -9948,12 +9977,42 @@ export function getQueryClient() {
|
|
|
9948
9977
|
if (!browserQueryClient) browserQueryClient = makeQueryClient();
|
|
9949
9978
|
return browserQueryClient;
|
|
9950
9979
|
}
|
|
9980
|
+
`;
|
|
9981
|
+
const clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';
|
|
9982
|
+
|
|
9983
|
+
// Client config - only NEXT_PUBLIC_* vars (available in browser)
|
|
9984
|
+
// These values are inlined at build time by Next.js
|
|
9985
|
+
const envParser = new EnvironmentParser({
|
|
9986
|
+
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
|
|
9987
|
+
NEXT_PUBLIC_AUTH_URL: process.env.NEXT_PUBLIC_AUTH_URL,
|
|
9988
|
+
});
|
|
9989
|
+
|
|
9990
|
+
export const clientConfig = envParser
|
|
9991
|
+
.create((get) => ({
|
|
9992
|
+
apiUrl: get('NEXT_PUBLIC_API_URL').string(),
|
|
9993
|
+
authUrl: get('NEXT_PUBLIC_AUTH_URL').string(),
|
|
9994
|
+
}))
|
|
9995
|
+
.parse();
|
|
9996
|
+
`;
|
|
9997
|
+
const serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';
|
|
9998
|
+
|
|
9999
|
+
// Server config - all env vars (server-side only, not exposed to browser)
|
|
10000
|
+
// Access these only in Server Components, Route Handlers, or Server Actions
|
|
10001
|
+
const envParser = new EnvironmentParser({ ...process.env });
|
|
10002
|
+
|
|
10003
|
+
export const serverConfig = envParser
|
|
10004
|
+
.create((get) => ({
|
|
10005
|
+
// Add server-only secrets here
|
|
10006
|
+
// Example: stripeSecretKey: get('STRIPE_SECRET_KEY').string(),
|
|
10007
|
+
}))
|
|
10008
|
+
.parse();
|
|
9951
10009
|
`;
|
|
9952
10010
|
const authClientTs = `import { createAuthClient } from 'better-auth/react';
|
|
9953
10011
|
import { magicLinkClient } from 'better-auth/client/plugins';
|
|
10012
|
+
import { clientConfig } from '~/config/client';
|
|
9954
10013
|
|
|
9955
10014
|
export const authClient = createAuthClient({
|
|
9956
|
-
baseURL:
|
|
10015
|
+
baseURL: clientConfig.authUrl,
|
|
9957
10016
|
plugins: [magicLinkClient()],
|
|
9958
10017
|
});
|
|
9959
10018
|
|
|
@@ -9974,9 +10033,10 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
9974
10033
|
`;
|
|
9975
10034
|
const apiIndexTs = `import { createApi } from './openapi';
|
|
9976
10035
|
import { getQueryClient } from '~/lib/query-client';
|
|
10036
|
+
import { clientConfig } from '~/config/client';
|
|
9977
10037
|
|
|
9978
10038
|
export const api = createApi({
|
|
9979
|
-
baseURL:
|
|
10039
|
+
baseURL: clientConfig.apiUrl,
|
|
9980
10040
|
queryClient: getQueryClient(),
|
|
9981
10041
|
});
|
|
9982
10042
|
`;
|
|
@@ -10097,6 +10157,14 @@ node_modules/
|
|
|
10097
10157
|
path: "apps/web/src/app/page.tsx",
|
|
10098
10158
|
content: pageTsx
|
|
10099
10159
|
},
|
|
10160
|
+
{
|
|
10161
|
+
path: "apps/web/src/config/client.ts",
|
|
10162
|
+
content: clientConfigTs
|
|
10163
|
+
},
|
|
10164
|
+
{
|
|
10165
|
+
path: "apps/web/src/config/server.ts",
|
|
10166
|
+
content: serverConfigTs
|
|
10167
|
+
},
|
|
10100
10168
|
{
|
|
10101
10169
|
path: "apps/web/src/lib/query-client.ts",
|
|
10102
10170
|
content: queryClientTs
|