@geekmidas/cli 0.39.0 → 0.41.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/{bundler-CyHg1v_T.cjs → bundler-BB-kETMd.cjs} +20 -49
- package/dist/bundler-BB-kETMd.cjs.map +1 -0
- package/dist/{bundler-DQIuE3Kn.mjs → bundler-DGry2vaR.mjs} +22 -51
- package/dist/bundler-DGry2vaR.mjs.map +1 -0
- package/dist/{config-BC5n1a2D.mjs → config-C0b0jdmU.mjs} +2 -2
- package/dist/{config-BC5n1a2D.mjs.map → config-C0b0jdmU.mjs.map} +1 -1
- package/dist/{config-BAE9LFC1.cjs → config-xVZsRjN7.cjs} +2 -2
- package/dist/{config-BAE9LFC1.cjs.map → config-xVZsRjN7.cjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +2 -2
- package/dist/dokploy-api-Bdmk5ImW.cjs +3 -0
- package/dist/{dokploy-api-C5czOZoc.cjs → dokploy-api-BdxOMH_V.cjs} +43 -1
- package/dist/{dokploy-api-C5czOZoc.cjs.map → dokploy-api-BdxOMH_V.cjs.map} +1 -1
- package/dist/{dokploy-api-B9qR2Yn1.mjs → dokploy-api-DWsqNjwP.mjs} +43 -1
- package/dist/{dokploy-api-B9qR2Yn1.mjs.map → dokploy-api-DWsqNjwP.mjs.map} +1 -1
- package/dist/dokploy-api-tZSZaHd9.mjs +3 -0
- package/dist/{encryption-JtMsiGNp.mjs → encryption-BC4MAODn.mjs} +1 -1
- package/dist/{encryption-JtMsiGNp.mjs.map → encryption-BC4MAODn.mjs.map} +1 -1
- package/dist/encryption-Biq0EZ4m.cjs +4 -0
- package/dist/encryption-CQXBZGkt.mjs +3 -0
- package/dist/{encryption-BAz0xQ1Q.cjs → encryption-DaCB_NmS.cjs} +13 -3
- package/dist/{encryption-BAz0xQ1Q.cjs.map → encryption-DaCB_NmS.cjs.map} +1 -1
- package/dist/{index-C7TkoYmt.d.mts → index-CXa3odEw.d.mts} +68 -7
- package/dist/index-CXa3odEw.d.mts.map +1 -0
- package/dist/{index-CpchsC9w.d.cts → index-E8Nu2Rxl.d.cts} +67 -6
- package/dist/index-E8Nu2Rxl.d.cts.map +1 -0
- package/dist/index.cjs +698 -127
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +677 -106
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-CjYeF-Tg.mjs → openapi-D3pA6FfZ.mjs} +2 -2
- package/dist/{openapi-CjYeF-Tg.mjs.map → openapi-D3pA6FfZ.mjs.map} +1 -1
- package/dist/{openapi-a-e3Y8WA.cjs → openapi-DhcCtKzM.cjs} +2 -2
- package/dist/{openapi-a-e3Y8WA.cjs.map → openapi-DhcCtKzM.cjs.map} +1 -1
- package/dist/{openapi-react-query-DvNpdDpM.cjs → openapi-react-query-C_MxpBgF.cjs} +1 -1
- package/dist/{openapi-react-query-DvNpdDpM.cjs.map → openapi-react-query-C_MxpBgF.cjs.map} +1 -1
- package/dist/{openapi-react-query-5rSortLH.mjs → openapi-react-query-ZoP9DPbY.mjs} +1 -1
- package/dist/{openapi-react-query-5rSortLH.mjs.map → openapi-react-query-ZoP9DPbY.mjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +3 -3
- package/dist/{types-K2uQJ-FO.d.mts → types-BtGL-8QS.d.mts} +1 -1
- package/dist/{types-K2uQJ-FO.d.mts.map → types-BtGL-8QS.d.mts.map} +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-My0A4IRO.cjs → workspace-BDAhr6Kb.cjs} +33 -4
- package/dist/{workspace-My0A4IRO.cjs.map → workspace-BDAhr6Kb.cjs.map} +1 -1
- package/dist/{workspace-DFJ3sWfY.mjs → workspace-D_6ZCaR_.mjs} +33 -4
- package/dist/{workspace-DFJ3sWfY.mjs.map → workspace-D_6ZCaR_.mjs.map} +1 -1
- package/package.json +5 -5
- package/src/build/bundler.ts +27 -79
- package/src/deploy/__tests__/domain.spec.ts +231 -0
- package/src/deploy/__tests__/secrets.spec.ts +300 -0
- package/src/deploy/__tests__/sniffer.spec.ts +221 -0
- package/src/deploy/docker.ts +40 -11
- package/src/deploy/dokploy-api.ts +99 -0
- package/src/deploy/domain.ts +125 -0
- package/src/deploy/index.ts +366 -148
- package/src/deploy/secrets.ts +182 -0
- package/src/deploy/sniffer.ts +180 -0
- package/src/dev/index.ts +11 -0
- package/src/docker/index.ts +24 -5
- package/src/docker/templates.ts +187 -1
- package/src/init/templates/api.ts +4 -4
- package/src/init/versions.ts +2 -2
- package/src/workspace/index.ts +2 -0
- package/src/workspace/schema.ts +32 -6
- package/src/workspace/types.ts +64 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/bundler-CyHg1v_T.cjs.map +0 -1
- package/dist/bundler-DQIuE3Kn.mjs.map +0 -1
- package/dist/dokploy-api-B0w17y4_.mjs +0 -3
- package/dist/dokploy-api-BnGeUqN4.cjs +0 -3
- package/dist/index-C7TkoYmt.d.mts.map +0 -1
- package/dist/index-CpchsC9w.d.cts.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"lodash.kebabcase": "^4.1.1",
|
|
49
49
|
"openapi-typescript": "^7.4.2",
|
|
50
50
|
"prompts": "~2.4.2",
|
|
51
|
-
"@geekmidas/
|
|
52
|
-
"@geekmidas/
|
|
53
|
-
"@geekmidas/schema": "~0.1.0",
|
|
51
|
+
"@geekmidas/logger": "~0.4.0",
|
|
52
|
+
"@geekmidas/constructs": "~0.7.0",
|
|
54
53
|
"@geekmidas/errors": "~0.1.0",
|
|
55
|
-
"@geekmidas/
|
|
54
|
+
"@geekmidas/schema": "~0.1.0",
|
|
55
|
+
"@geekmidas/envkit": "~0.6.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/lodash.kebabcase": "^4.1.9",
|
package/src/build/bundler.ts
CHANGED
|
@@ -1,50 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { mkdir, rename, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import type { Construct } from '@geekmidas/constructs';
|
|
6
5
|
|
|
7
|
-
const MIN_TSDOWN_VERSION = '0.11.0';
|
|
8
|
-
|
|
9
6
|
/**
|
|
10
|
-
*
|
|
7
|
+
* Banner to inject into ESM bundle for CJS compatibility.
|
|
8
|
+
* Creates a `require` function using Node's createRequire for packages
|
|
9
|
+
* that internally use CommonJS require() for Node builtins.
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const result = execSync('npx tsdown --version', {
|
|
15
|
-
encoding: 'utf-8',
|
|
16
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
17
|
-
});
|
|
18
|
-
// Output format: "tsdown/0.12.8 darwin-arm64 node-v22.21.1"
|
|
19
|
-
const match = result.match(/tsdown\/(\d+\.\d+\.\d+)/);
|
|
20
|
-
if (match) {
|
|
21
|
-
const version = match[1]!;
|
|
22
|
-
const [major, minor] = version.split('.').map(Number) as [number, number];
|
|
23
|
-
const [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(
|
|
24
|
-
Number,
|
|
25
|
-
) as [number, number];
|
|
26
|
-
|
|
27
|
-
if (major < minMajor || (major === minMajor && minor < minMinor)) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\n` +
|
|
30
|
-
' npm install -D tsdown@latest\n' +
|
|
31
|
-
' # or\n' +
|
|
32
|
-
' pnpm add -D tsdown@latest',
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if (error instanceof Error && error.message.includes('too old')) {
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
throw new Error(
|
|
41
|
-
'tsdown is required for bundling. Please install it:\n' +
|
|
42
|
-
' npm install -D tsdown@latest\n' +
|
|
43
|
-
' # or\n' +
|
|
44
|
-
' pnpm add -D tsdown@latest',
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
11
|
+
const ESM_CJS_COMPAT_BANNER =
|
|
12
|
+
'import { createRequire } from "module"; const require = createRequire(import.meta.url);';
|
|
48
13
|
|
|
49
14
|
export interface BundleOptions {
|
|
50
15
|
/** Entry point file (e.g., .gkm/server/server.ts) */
|
|
@@ -97,11 +62,13 @@ async function collectRequiredEnvVars(
|
|
|
97
62
|
}
|
|
98
63
|
|
|
99
64
|
/**
|
|
100
|
-
* Bundle the server application using
|
|
65
|
+
* Bundle the server application using esbuild.
|
|
66
|
+
* Creates a fully standalone bundle with all dependencies included.
|
|
101
67
|
*
|
|
102
68
|
* @param options - Bundle configuration options
|
|
103
69
|
* @returns Bundle result with output path and optional master key
|
|
104
70
|
*/
|
|
71
|
+
|
|
105
72
|
/** Default env var values for docker compose services */
|
|
106
73
|
const DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>> = {
|
|
107
74
|
postgres: {
|
|
@@ -129,27 +96,23 @@ export async function bundleServer(
|
|
|
129
96
|
dockerServices,
|
|
130
97
|
} = options;
|
|
131
98
|
|
|
132
|
-
// Check tsdown version first
|
|
133
|
-
checkTsdownVersion();
|
|
134
|
-
|
|
135
99
|
// Ensure output directory exists
|
|
136
100
|
await mkdir(outputDir, { recursive: true });
|
|
137
101
|
|
|
138
|
-
|
|
102
|
+
const mjsOutput = join(outputDir, 'server.mjs');
|
|
103
|
+
|
|
104
|
+
// Build command-line arguments for esbuild
|
|
139
105
|
const args = [
|
|
140
106
|
'npx',
|
|
141
|
-
'
|
|
107
|
+
'esbuild',
|
|
142
108
|
entryPoint,
|
|
143
|
-
'--
|
|
144
|
-
'--
|
|
145
|
-
|
|
146
|
-
'--format',
|
|
147
|
-
|
|
148
|
-
'--
|
|
149
|
-
|
|
150
|
-
'--target',
|
|
151
|
-
'node22',
|
|
152
|
-
'--clean',
|
|
109
|
+
'--bundle',
|
|
110
|
+
'--platform=node',
|
|
111
|
+
'--target=node22',
|
|
112
|
+
'--format=esm',
|
|
113
|
+
`--outfile=${mjsOutput}`,
|
|
114
|
+
'--packages=bundle', // Bundle all dependencies for standalone output
|
|
115
|
+
`--banner:js=${ESM_CJS_COMPAT_BANNER}`, // CJS compatibility for packages like pino
|
|
153
116
|
];
|
|
154
117
|
|
|
155
118
|
if (minify) {
|
|
@@ -160,14 +123,11 @@ export async function bundleServer(
|
|
|
160
123
|
args.push('--sourcemap');
|
|
161
124
|
}
|
|
162
125
|
|
|
163
|
-
// Add external packages
|
|
126
|
+
// Add external packages (user-specified)
|
|
164
127
|
for (const ext of external) {
|
|
165
|
-
args.push(
|
|
128
|
+
args.push(`--external:${ext}`);
|
|
166
129
|
}
|
|
167
130
|
|
|
168
|
-
// Always exclude node: builtins
|
|
169
|
-
args.push('--external', 'node:*');
|
|
170
|
-
|
|
171
131
|
// Handle secrets injection if stage is provided
|
|
172
132
|
let masterKey: string | undefined;
|
|
173
133
|
|
|
@@ -252,21 +212,17 @@ export async function bundleServer(
|
|
|
252
212
|
const encrypted = encryptSecrets(embeddable);
|
|
253
213
|
masterKey = encrypted.masterKey;
|
|
254
214
|
|
|
255
|
-
// Add define options for build-time injection using
|
|
215
|
+
// Add define options for build-time injection using esbuild's --define:KEY=VALUE format
|
|
256
216
|
const defines = generateDefineOptions(encrypted);
|
|
257
217
|
for (const [key, value] of Object.entries(defines)) {
|
|
258
|
-
args.push(`--
|
|
218
|
+
args.push(`--define:${key}=${JSON.stringify(value)}`);
|
|
259
219
|
}
|
|
260
220
|
|
|
261
221
|
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
262
222
|
}
|
|
263
223
|
|
|
264
|
-
const mjsOutput = join(outputDir, 'server.mjs');
|
|
265
|
-
|
|
266
224
|
try {
|
|
267
|
-
// Run
|
|
268
|
-
// Use spawnSync with args array to avoid shell escaping issues with --define values
|
|
269
|
-
// args is always populated with ['npx', 'tsdown', ...] so cmd is never undefined
|
|
225
|
+
// Run esbuild with command-line arguments
|
|
270
226
|
const [cmd, ...cmdArgs] = args as [string, ...string[]];
|
|
271
227
|
const result = spawnSync(cmd, cmdArgs, {
|
|
272
228
|
cwd: process.cwd(),
|
|
@@ -278,15 +234,7 @@ export async function bundleServer(
|
|
|
278
234
|
throw result.error;
|
|
279
235
|
}
|
|
280
236
|
if (result.status !== 0) {
|
|
281
|
-
throw new Error(`
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Rename output to .mjs for explicit ESM
|
|
285
|
-
// tsdown outputs as server.js for ESM format
|
|
286
|
-
const jsOutput = join(outputDir, 'server.js');
|
|
287
|
-
|
|
288
|
-
if (existsSync(jsOutput)) {
|
|
289
|
-
await rename(jsOutput, mjsOutput);
|
|
237
|
+
throw new Error(`esbuild exited with code ${result.status}`);
|
|
290
238
|
}
|
|
291
239
|
|
|
292
240
|
// Add shebang to the bundled file
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import type { NormalizedAppConfig } from '../../workspace/types';
|
|
3
|
+
import {
|
|
4
|
+
generatePublicUrlBuildArgs,
|
|
5
|
+
getPublicUrlArgNames,
|
|
6
|
+
isMainFrontendApp,
|
|
7
|
+
resolveHost,
|
|
8
|
+
} from '../domain';
|
|
9
|
+
|
|
10
|
+
describe('resolveHost', () => {
|
|
11
|
+
const dokployConfig = {
|
|
12
|
+
endpoint: 'https://dokploy.example.com',
|
|
13
|
+
projectId: 'test-project',
|
|
14
|
+
domains: {
|
|
15
|
+
development: 'dev.myapp.com',
|
|
16
|
+
staging: 'staging.myapp.com',
|
|
17
|
+
production: 'myapp.com',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const createApp = (
|
|
22
|
+
overrides: Partial<NormalizedAppConfig> = {},
|
|
23
|
+
): NormalizedAppConfig => ({
|
|
24
|
+
type: 'backend',
|
|
25
|
+
path: 'apps/api',
|
|
26
|
+
port: 3000,
|
|
27
|
+
dependencies: [],
|
|
28
|
+
resolvedDeployTarget: 'dokploy',
|
|
29
|
+
...overrides,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should return explicit app domain override (string)', () => {
|
|
33
|
+
const app = createApp({ domain: 'api.custom.com' });
|
|
34
|
+
const host = resolveHost('api', app, 'production', dokployConfig, false);
|
|
35
|
+
expect(host).toBe('api.custom.com');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return stage-specific domain override', () => {
|
|
39
|
+
const app = createApp({
|
|
40
|
+
domain: {
|
|
41
|
+
production: 'login.myapp.com',
|
|
42
|
+
staging: 'login.staging.myapp.com',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
const host = resolveHost('auth', app, 'production', dokployConfig, false);
|
|
46
|
+
expect(host).toBe('login.myapp.com');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should fallback to base domain pattern when no stage match in override', () => {
|
|
50
|
+
const app = createApp({
|
|
51
|
+
domain: { production: 'custom.myapp.com' },
|
|
52
|
+
});
|
|
53
|
+
const host = resolveHost('api', app, 'development', dokployConfig, false);
|
|
54
|
+
expect(host).toBe('api.dev.myapp.com');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should return base domain for main frontend app', () => {
|
|
58
|
+
const app = createApp({ type: 'frontend' });
|
|
59
|
+
const host = resolveHost('web', app, 'production', dokployConfig, true);
|
|
60
|
+
expect(host).toBe('myapp.com');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return prefixed domain for non-main apps', () => {
|
|
64
|
+
const app = createApp();
|
|
65
|
+
const host = resolveHost('api', app, 'production', dokployConfig, false);
|
|
66
|
+
expect(host).toBe('api.myapp.com');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should use correct base domain for each stage', () => {
|
|
70
|
+
const app = createApp();
|
|
71
|
+
|
|
72
|
+
expect(resolveHost('api', app, 'development', dokployConfig, false)).toBe(
|
|
73
|
+
'api.dev.myapp.com',
|
|
74
|
+
);
|
|
75
|
+
expect(resolveHost('api', app, 'staging', dokployConfig, false)).toBe(
|
|
76
|
+
'api.staging.myapp.com',
|
|
77
|
+
);
|
|
78
|
+
expect(resolveHost('api', app, 'production', dokployConfig, false)).toBe(
|
|
79
|
+
'api.myapp.com',
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should throw error when no domain configured for stage', () => {
|
|
84
|
+
const app = createApp();
|
|
85
|
+
expect(() =>
|
|
86
|
+
resolveHost('api', app, 'unknown-stage', dokployConfig, false),
|
|
87
|
+
).toThrow('No domain configured for stage "unknown-stage"');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should throw error when dokployConfig has no domains', () => {
|
|
91
|
+
const app = createApp();
|
|
92
|
+
const configWithoutDomains = {
|
|
93
|
+
endpoint: 'https://dokploy.example.com',
|
|
94
|
+
projectId: 'test-project',
|
|
95
|
+
};
|
|
96
|
+
expect(() =>
|
|
97
|
+
resolveHost('api', app, 'production', configWithoutDomains, false),
|
|
98
|
+
).toThrow('No domain configured for stage "production"');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('isMainFrontendApp', () => {
|
|
103
|
+
const createApp = (
|
|
104
|
+
type: 'backend' | 'frontend',
|
|
105
|
+
): NormalizedAppConfig => ({
|
|
106
|
+
type,
|
|
107
|
+
path: 'apps/test',
|
|
108
|
+
port: 3000,
|
|
109
|
+
dependencies: [],
|
|
110
|
+
resolvedDeployTarget: 'dokploy',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should return false for backend apps', () => {
|
|
114
|
+
const apps = {
|
|
115
|
+
api: createApp('backend'),
|
|
116
|
+
web: createApp('frontend'),
|
|
117
|
+
};
|
|
118
|
+
expect(isMainFrontendApp('api', apps.api, apps)).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return true for app named "web" if it is frontend', () => {
|
|
122
|
+
const apps = {
|
|
123
|
+
api: createApp('backend'),
|
|
124
|
+
web: createApp('frontend'),
|
|
125
|
+
admin: createApp('frontend'),
|
|
126
|
+
};
|
|
127
|
+
expect(isMainFrontendApp('web', apps.web, apps)).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should return true for first frontend app when no "web" app', () => {
|
|
131
|
+
const apps = {
|
|
132
|
+
api: createApp('backend'),
|
|
133
|
+
dashboard: createApp('frontend'),
|
|
134
|
+
admin: createApp('frontend'),
|
|
135
|
+
};
|
|
136
|
+
expect(isMainFrontendApp('dashboard', apps.dashboard, apps)).toBe(true);
|
|
137
|
+
expect(isMainFrontendApp('admin', apps.admin, apps)).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should return false for non-first frontend when no "web" app', () => {
|
|
141
|
+
const apps = {
|
|
142
|
+
api: createApp('backend'),
|
|
143
|
+
dashboard: createApp('frontend'),
|
|
144
|
+
admin: createApp('frontend'),
|
|
145
|
+
};
|
|
146
|
+
expect(isMainFrontendApp('admin', apps.admin, apps)).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('generatePublicUrlBuildArgs', () => {
|
|
151
|
+
const createApp = (dependencies: string[]): NormalizedAppConfig => ({
|
|
152
|
+
type: 'frontend',
|
|
153
|
+
path: 'apps/web',
|
|
154
|
+
port: 3001,
|
|
155
|
+
dependencies,
|
|
156
|
+
resolvedDeployTarget: 'dokploy',
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should generate build args for dependencies', () => {
|
|
160
|
+
const app = createApp(['api', 'auth']);
|
|
161
|
+
const deployedUrls = {
|
|
162
|
+
api: 'https://api.myapp.com',
|
|
163
|
+
auth: 'https://auth.myapp.com',
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const buildArgs = generatePublicUrlBuildArgs(app, deployedUrls);
|
|
167
|
+
|
|
168
|
+
expect(buildArgs).toEqual([
|
|
169
|
+
'NEXT_PUBLIC_API_URL=https://api.myapp.com',
|
|
170
|
+
'NEXT_PUBLIC_AUTH_URL=https://auth.myapp.com',
|
|
171
|
+
]);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should skip missing dependencies', () => {
|
|
175
|
+
const app = createApp(['api', 'auth', 'missing']);
|
|
176
|
+
const deployedUrls = {
|
|
177
|
+
api: 'https://api.myapp.com',
|
|
178
|
+
// auth and missing are not deployed yet
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const buildArgs = generatePublicUrlBuildArgs(app, deployedUrls);
|
|
182
|
+
|
|
183
|
+
expect(buildArgs).toEqual(['NEXT_PUBLIC_API_URL=https://api.myapp.com']);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should return empty array when no dependencies', () => {
|
|
187
|
+
const app = createApp([]);
|
|
188
|
+
const deployedUrls = { api: 'https://api.myapp.com' };
|
|
189
|
+
|
|
190
|
+
const buildArgs = generatePublicUrlBuildArgs(app, deployedUrls);
|
|
191
|
+
|
|
192
|
+
expect(buildArgs).toEqual([]);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should handle uppercase conversion correctly', () => {
|
|
196
|
+
const app = createApp(['my-api', 'auth-service']);
|
|
197
|
+
const deployedUrls = {
|
|
198
|
+
'my-api': 'https://my-api.myapp.com',
|
|
199
|
+
'auth-service': 'https://auth-service.myapp.com',
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const buildArgs = generatePublicUrlBuildArgs(app, deployedUrls);
|
|
203
|
+
|
|
204
|
+
expect(buildArgs).toEqual([
|
|
205
|
+
'NEXT_PUBLIC_MY-API_URL=https://my-api.myapp.com',
|
|
206
|
+
'NEXT_PUBLIC_AUTH-SERVICE_URL=https://auth-service.myapp.com',
|
|
207
|
+
]);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('getPublicUrlArgNames', () => {
|
|
212
|
+
const createApp = (dependencies: string[]): NormalizedAppConfig => ({
|
|
213
|
+
type: 'frontend',
|
|
214
|
+
path: 'apps/web',
|
|
215
|
+
port: 3001,
|
|
216
|
+
dependencies,
|
|
217
|
+
resolvedDeployTarget: 'dokploy',
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should return arg names for dependencies', () => {
|
|
221
|
+
const app = createApp(['api', 'auth']);
|
|
222
|
+
const argNames = getPublicUrlArgNames(app);
|
|
223
|
+
expect(argNames).toEqual(['NEXT_PUBLIC_API_URL', 'NEXT_PUBLIC_AUTH_URL']);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should return empty array when no dependencies', () => {
|
|
227
|
+
const app = createApp([]);
|
|
228
|
+
const argNames = getPublicUrlArgNames(app);
|
|
229
|
+
expect(argNames).toEqual([]);
|
|
230
|
+
});
|
|
231
|
+
});
|