@geekmidas/cli 0.47.0 → 0.49.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/{dokploy-api-CMWlWq7-.mjs → dokploy-api-94KzmTVf.mjs} +7 -7
- package/dist/dokploy-api-94KzmTVf.mjs.map +1 -0
- package/dist/dokploy-api-CItuaWTq.mjs +3 -0
- package/dist/dokploy-api-DBNE8MDt.cjs +3 -0
- package/dist/{dokploy-api-BnX2OxyF.cjs → dokploy-api-YD8WCQfW.cjs} +7 -7
- package/dist/dokploy-api-YD8WCQfW.cjs.map +1 -0
- package/dist/index.cjs +2390 -1890
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2387 -1887
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/src/build/__tests__/handler-templates.spec.ts +947 -0
- package/src/deploy/__tests__/__fixtures__/entry-apps/async-entry.ts +24 -0
- package/src/deploy/__tests__/__fixtures__/entry-apps/nested-config-entry.ts +24 -0
- package/src/deploy/__tests__/__fixtures__/entry-apps/no-env-entry.ts +12 -0
- package/src/deploy/__tests__/__fixtures__/entry-apps/simple-entry.ts +14 -0
- package/src/deploy/__tests__/__fixtures__/entry-apps/throwing-entry.ts +16 -0
- package/src/deploy/__tests__/__fixtures__/env-parsers/non-function-export.ts +10 -0
- package/src/deploy/__tests__/__fixtures__/env-parsers/parseable-env-parser.ts +18 -0
- package/src/deploy/__tests__/__fixtures__/env-parsers/throwing-env-parser.ts +18 -0
- package/src/deploy/__tests__/__fixtures__/env-parsers/valid-env-parser.ts +16 -0
- package/src/deploy/__tests__/dns-verification.spec.ts +229 -0
- package/src/deploy/__tests__/dokploy-api.spec.ts +2 -3
- package/src/deploy/__tests__/domain.spec.ts +7 -3
- package/src/deploy/__tests__/env-resolver.spec.ts +469 -0
- package/src/deploy/__tests__/index.spec.ts +12 -12
- package/src/deploy/__tests__/secrets.spec.ts +4 -1
- package/src/deploy/__tests__/sniffer.spec.ts +326 -1
- package/src/deploy/__tests__/state.spec.ts +844 -0
- package/src/deploy/dns/hostinger-api.ts +9 -6
- package/src/deploy/dns/index.ts +115 -4
- package/src/deploy/docker.ts +1 -2
- package/src/deploy/dokploy-api.ts +20 -11
- package/src/deploy/domain.ts +5 -4
- package/src/deploy/env-resolver.ts +278 -0
- package/src/deploy/index.ts +534 -124
- package/src/deploy/secrets.ts +7 -2
- package/src/deploy/sniffer-envkit-patch.ts +43 -0
- package/src/deploy/sniffer-hooks.ts +52 -0
- package/src/deploy/sniffer-loader.ts +23 -0
- package/src/deploy/sniffer-worker.ts +74 -0
- package/src/deploy/sniffer.ts +136 -14
- package/src/deploy/state.ts +162 -1
- package/src/docker/templates.ts +10 -14
- package/src/init/versions.ts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/dokploy-api-4a6h35VY.cjs +0 -3
- package/dist/dokploy-api-BnX2OxyF.cjs.map +0 -1
- package/dist/dokploy-api-CMWlWq7-.mjs.map +0 -1
- package/dist/dokploy-api-DQvi9iZa.mjs +0 -3
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
1
3
|
import { describe, expect, it } from 'vitest';
|
|
2
4
|
import type { NormalizedAppConfig } from '../../workspace/types';
|
|
3
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
_sniffEntryFile,
|
|
7
|
+
_sniffEnvParser,
|
|
8
|
+
sniffAllApps,
|
|
9
|
+
sniffAppEnvironment,
|
|
10
|
+
} from '../sniffer';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
const fixturesPath = resolve(__dirname, '__fixtures__/entry-apps');
|
|
15
|
+
const envParserFixturesPath = resolve(__dirname, '__fixtures__/env-parsers');
|
|
4
16
|
|
|
5
17
|
describe('sniffAppEnvironment', () => {
|
|
6
18
|
const workspacePath = '/test/workspace';
|
|
@@ -219,3 +231,316 @@ describe('fire-and-forget handling', () => {
|
|
|
219
231
|
expect(Array.isArray(result.requiredEnvVars)).toBe(true);
|
|
220
232
|
});
|
|
221
233
|
});
|
|
234
|
+
|
|
235
|
+
describe('entry app sniffing via subprocess', () => {
|
|
236
|
+
// These tests verify the subprocess-based sniffing for entry apps.
|
|
237
|
+
// Each test uses fixture files that import @geekmidas/envkit.
|
|
238
|
+
|
|
239
|
+
it('should sniff environment variables from simple entry app', async () => {
|
|
240
|
+
const result = await _sniffEntryFile(
|
|
241
|
+
'./simple-entry.ts',
|
|
242
|
+
fixturesPath,
|
|
243
|
+
fixturesPath,
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
expect(result.envVars).toContain('PORT');
|
|
247
|
+
expect(result.envVars).toContain('DATABASE_URL');
|
|
248
|
+
expect(result.envVars).toContain('REDIS_URL');
|
|
249
|
+
expect(result.envVars).toHaveLength(3);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should sniff environment variables from nested config entry app', async () => {
|
|
253
|
+
const result = await _sniffEntryFile(
|
|
254
|
+
'./nested-config-entry.ts',
|
|
255
|
+
fixturesPath,
|
|
256
|
+
fixturesPath,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
// Should capture all nested env vars
|
|
260
|
+
expect(result.envVars).toContain('PORT');
|
|
261
|
+
expect(result.envVars).toContain('HOST');
|
|
262
|
+
expect(result.envVars).toContain('DATABASE_URL');
|
|
263
|
+
expect(result.envVars).toContain('DB_POOL_SIZE');
|
|
264
|
+
expect(result.envVars).toContain('BETTER_AUTH_SECRET');
|
|
265
|
+
expect(result.envVars).toContain('BETTER_AUTH_URL');
|
|
266
|
+
expect(result.envVars).toContain('BETTER_AUTH_TRUSTED_ORIGINS');
|
|
267
|
+
expect(result.envVars).toHaveLength(7);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should capture env vars even when entry throws', async () => {
|
|
271
|
+
const result = await _sniffEntryFile(
|
|
272
|
+
'./throwing-entry.ts',
|
|
273
|
+
fixturesPath,
|
|
274
|
+
fixturesPath,
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// Should still capture env vars accessed before the throw
|
|
278
|
+
expect(result.envVars).toContain('PORT');
|
|
279
|
+
expect(result.envVars).toContain('API_KEY');
|
|
280
|
+
expect(result.envVars).toHaveLength(2);
|
|
281
|
+
|
|
282
|
+
// Should report the error
|
|
283
|
+
expect(result.error).toBeDefined();
|
|
284
|
+
expect(result.error?.message).toContain('Initialization failed');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should return empty when entry has no env vars', async () => {
|
|
288
|
+
const result = await _sniffEntryFile(
|
|
289
|
+
'./no-env-entry.ts',
|
|
290
|
+
fixturesPath,
|
|
291
|
+
fixturesPath,
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(result.envVars).toEqual([]);
|
|
295
|
+
expect(result.error).toBeUndefined();
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should handle async entry apps with fire-and-forget promises', async () => {
|
|
299
|
+
const result = await _sniffEntryFile(
|
|
300
|
+
'./async-entry.ts',
|
|
301
|
+
fixturesPath,
|
|
302
|
+
fixturesPath,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
expect(result.envVars).toContain('PORT');
|
|
306
|
+
expect(result.envVars).toContain('DATABASE_URL');
|
|
307
|
+
expect(result.envVars).toHaveLength(2);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should return error for non-existent entry file', async () => {
|
|
311
|
+
const result = await _sniffEntryFile(
|
|
312
|
+
'./non-existent.ts',
|
|
313
|
+
fixturesPath,
|
|
314
|
+
fixturesPath,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
expect(result.envVars).toEqual([]);
|
|
318
|
+
expect(result.error).toBeDefined();
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
describe('sniffAppEnvironment with entry apps', () => {
|
|
323
|
+
// Integration tests for sniffAppEnvironment with entry-based apps
|
|
324
|
+
|
|
325
|
+
it('should use subprocess sniffing for entry apps without requiredEnv', async () => {
|
|
326
|
+
const app: NormalizedAppConfig = {
|
|
327
|
+
type: 'backend',
|
|
328
|
+
path: fixturesPath,
|
|
329
|
+
port: 3000,
|
|
330
|
+
dependencies: [],
|
|
331
|
+
resolvedDeployTarget: 'dokploy',
|
|
332
|
+
entry: './simple-entry.ts',
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const result = await sniffAppEnvironment(app, 'api', fixturesPath);
|
|
336
|
+
|
|
337
|
+
expect(result.appName).toBe('api');
|
|
338
|
+
expect(result.requiredEnvVars).toContain('PORT');
|
|
339
|
+
expect(result.requiredEnvVars).toContain('DATABASE_URL');
|
|
340
|
+
expect(result.requiredEnvVars).toContain('REDIS_URL');
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('should prefer requiredEnv over sniffing for entry apps', async () => {
|
|
344
|
+
const app: NormalizedAppConfig = {
|
|
345
|
+
type: 'backend',
|
|
346
|
+
path: fixturesPath,
|
|
347
|
+
port: 3000,
|
|
348
|
+
dependencies: [],
|
|
349
|
+
resolvedDeployTarget: 'dokploy',
|
|
350
|
+
entry: './simple-entry.ts',
|
|
351
|
+
requiredEnv: ['CUSTOM_VAR', 'ANOTHER_VAR'], // Should use this instead of sniffing
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const result = await sniffAppEnvironment(app, 'api', fixturesPath);
|
|
355
|
+
|
|
356
|
+
expect(result.requiredEnvVars).toEqual(['CUSTOM_VAR', 'ANOTHER_VAR']);
|
|
357
|
+
// Should NOT contain the sniffed vars since requiredEnv takes precedence
|
|
358
|
+
expect(result.requiredEnvVars).not.toContain('PORT');
|
|
359
|
+
expect(result.requiredEnvVars).not.toContain('DATABASE_URL');
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('should handle entry app that throws and still return captured env vars', async () => {
|
|
363
|
+
const app: NormalizedAppConfig = {
|
|
364
|
+
type: 'backend',
|
|
365
|
+
path: fixturesPath,
|
|
366
|
+
port: 3000,
|
|
367
|
+
dependencies: [],
|
|
368
|
+
resolvedDeployTarget: 'dokploy',
|
|
369
|
+
entry: './throwing-entry.ts',
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const result = await sniffAppEnvironment(app, 'api', fixturesPath, {
|
|
373
|
+
logWarnings: false,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
expect(result.appName).toBe('api');
|
|
377
|
+
expect(result.requiredEnvVars).toContain('PORT');
|
|
378
|
+
expect(result.requiredEnvVars).toContain('API_KEY');
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
describe('envParser sniffing via _sniffEnvParser', () => {
|
|
383
|
+
// These tests verify the envParser sniffing functionality.
|
|
384
|
+
// Each test uses fixture files that export envParser functions.
|
|
385
|
+
|
|
386
|
+
it('should sniff environment variables from valid envParser', async () => {
|
|
387
|
+
const result = await _sniffEnvParser(
|
|
388
|
+
'./valid-env-parser.ts#envParser',
|
|
389
|
+
envParserFixturesPath,
|
|
390
|
+
envParserFixturesPath,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
expect(result.envVars).toContain('PORT');
|
|
394
|
+
expect(result.envVars).toContain('DATABASE_URL');
|
|
395
|
+
expect(result.envVars).toContain('DB_POOL_SIZE');
|
|
396
|
+
expect(result.envVars).toHaveLength(3);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('should sniff environment variables from default export', async () => {
|
|
400
|
+
// Test with default export (no # specifier)
|
|
401
|
+
const result = await _sniffEnvParser(
|
|
402
|
+
'./valid-env-parser.ts',
|
|
403
|
+
envParserFixturesPath,
|
|
404
|
+
envParserFixturesPath,
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
expect(result.envVars).toContain('PORT');
|
|
408
|
+
expect(result.envVars).toContain('DATABASE_URL');
|
|
409
|
+
expect(result.envVars).toContain('DB_POOL_SIZE');
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
it('should return empty when export is not a function', async () => {
|
|
413
|
+
const result = await _sniffEnvParser(
|
|
414
|
+
'./non-function-export.ts#envParser',
|
|
415
|
+
envParserFixturesPath,
|
|
416
|
+
envParserFixturesPath,
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
expect(result.envVars).toEqual([]);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('should handle non-function default export', async () => {
|
|
423
|
+
const result = await _sniffEnvParser(
|
|
424
|
+
'./non-function-export.ts', // Uses default export which is not a function
|
|
425
|
+
envParserFixturesPath,
|
|
426
|
+
envParserFixturesPath,
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
expect(result.envVars).toEqual([]);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('should return empty when module path is empty', async () => {
|
|
433
|
+
const result = await _sniffEnvParser(
|
|
434
|
+
'#envParser', // Empty module path
|
|
435
|
+
envParserFixturesPath,
|
|
436
|
+
envParserFixturesPath,
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
expect(result.envVars).toEqual([]);
|
|
440
|
+
expect(result.unhandledRejections).toEqual([]);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('should capture env vars from throwing envParser', async () => {
|
|
444
|
+
const result = await _sniffEnvParser(
|
|
445
|
+
'./throwing-env-parser.ts#envParser',
|
|
446
|
+
envParserFixturesPath,
|
|
447
|
+
envParserFixturesPath,
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
// Should still capture env vars accessed before the throw
|
|
451
|
+
expect(result.envVars).toContain('PORT');
|
|
452
|
+
expect(result.envVars).toContain('API_KEY');
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('should return empty when module does not exist', async () => {
|
|
456
|
+
const result = await _sniffEnvParser(
|
|
457
|
+
'./non-existent.ts#envParser',
|
|
458
|
+
envParserFixturesPath,
|
|
459
|
+
envParserFixturesPath,
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
expect(result.envVars).toEqual([]);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it('should call parse() on returned config and capture env vars', async () => {
|
|
466
|
+
// This tests the path where envParser returns a config with parse() method
|
|
467
|
+
const result = await _sniffEnvParser(
|
|
468
|
+
'./parseable-env-parser.ts#envParser',
|
|
469
|
+
envParserFixturesPath,
|
|
470
|
+
envParserFixturesPath,
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
// Should capture env vars even though parse() fails due to missing values
|
|
474
|
+
expect(result.envVars).toContain('PORT');
|
|
475
|
+
expect(result.envVars).toContain('DATABASE_URL');
|
|
476
|
+
expect(result.envVars).toContain('API_KEY');
|
|
477
|
+
expect(result.envVars).toHaveLength(3);
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
describe('sniffAppEnvironment with envParser apps', () => {
|
|
482
|
+
it('should use envParser sniffing for apps with envParser config', async () => {
|
|
483
|
+
const app: NormalizedAppConfig = {
|
|
484
|
+
type: 'backend',
|
|
485
|
+
path: envParserFixturesPath,
|
|
486
|
+
port: 3000,
|
|
487
|
+
dependencies: [],
|
|
488
|
+
resolvedDeployTarget: 'dokploy',
|
|
489
|
+
envParser: './valid-env-parser.ts#envParser',
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const result = await sniffAppEnvironment(
|
|
493
|
+
app,
|
|
494
|
+
'api',
|
|
495
|
+
envParserFixturesPath,
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
expect(result.appName).toBe('api');
|
|
499
|
+
expect(result.requiredEnvVars).toContain('PORT');
|
|
500
|
+
expect(result.requiredEnvVars).toContain('DATABASE_URL');
|
|
501
|
+
expect(result.requiredEnvVars).toContain('DB_POOL_SIZE');
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should prefer requiredEnv over envParser sniffing', async () => {
|
|
505
|
+
const app: NormalizedAppConfig = {
|
|
506
|
+
type: 'backend',
|
|
507
|
+
path: envParserFixturesPath,
|
|
508
|
+
port: 3000,
|
|
509
|
+
dependencies: [],
|
|
510
|
+
resolvedDeployTarget: 'dokploy',
|
|
511
|
+
envParser: './valid-env-parser.ts#envParser',
|
|
512
|
+
requiredEnv: ['CUSTOM_VAR'], // Should use this instead
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const result = await sniffAppEnvironment(
|
|
516
|
+
app,
|
|
517
|
+
'api',
|
|
518
|
+
envParserFixturesPath,
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
expect(result.requiredEnvVars).toEqual(['CUSTOM_VAR']);
|
|
522
|
+
// Should NOT contain the sniffed vars
|
|
523
|
+
expect(result.requiredEnvVars).not.toContain('PORT');
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('should handle envParser that exports non-function gracefully', async () => {
|
|
527
|
+
const app: NormalizedAppConfig = {
|
|
528
|
+
type: 'backend',
|
|
529
|
+
path: envParserFixturesPath,
|
|
530
|
+
port: 3000,
|
|
531
|
+
dependencies: [],
|
|
532
|
+
resolvedDeployTarget: 'dokploy',
|
|
533
|
+
envParser: './non-function-export.ts#envParser',
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
const result = await sniffAppEnvironment(
|
|
537
|
+
app,
|
|
538
|
+
'api',
|
|
539
|
+
envParserFixturesPath,
|
|
540
|
+
{ logWarnings: false },
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
expect(result.appName).toBe('api');
|
|
544
|
+
expect(result.requiredEnvVars).toEqual([]);
|
|
545
|
+
});
|
|
546
|
+
});
|