@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.
Files changed (50) hide show
  1. package/dist/{dokploy-api-CMWlWq7-.mjs → dokploy-api-94KzmTVf.mjs} +7 -7
  2. package/dist/dokploy-api-94KzmTVf.mjs.map +1 -0
  3. package/dist/dokploy-api-CItuaWTq.mjs +3 -0
  4. package/dist/dokploy-api-DBNE8MDt.cjs +3 -0
  5. package/dist/{dokploy-api-BnX2OxyF.cjs → dokploy-api-YD8WCQfW.cjs} +7 -7
  6. package/dist/dokploy-api-YD8WCQfW.cjs.map +1 -0
  7. package/dist/index.cjs +2390 -1890
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.mjs +2387 -1887
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +8 -6
  12. package/src/build/__tests__/handler-templates.spec.ts +947 -0
  13. package/src/deploy/__tests__/__fixtures__/entry-apps/async-entry.ts +24 -0
  14. package/src/deploy/__tests__/__fixtures__/entry-apps/nested-config-entry.ts +24 -0
  15. package/src/deploy/__tests__/__fixtures__/entry-apps/no-env-entry.ts +12 -0
  16. package/src/deploy/__tests__/__fixtures__/entry-apps/simple-entry.ts +14 -0
  17. package/src/deploy/__tests__/__fixtures__/entry-apps/throwing-entry.ts +16 -0
  18. package/src/deploy/__tests__/__fixtures__/env-parsers/non-function-export.ts +10 -0
  19. package/src/deploy/__tests__/__fixtures__/env-parsers/parseable-env-parser.ts +18 -0
  20. package/src/deploy/__tests__/__fixtures__/env-parsers/throwing-env-parser.ts +18 -0
  21. package/src/deploy/__tests__/__fixtures__/env-parsers/valid-env-parser.ts +16 -0
  22. package/src/deploy/__tests__/dns-verification.spec.ts +229 -0
  23. package/src/deploy/__tests__/dokploy-api.spec.ts +2 -3
  24. package/src/deploy/__tests__/domain.spec.ts +7 -3
  25. package/src/deploy/__tests__/env-resolver.spec.ts +469 -0
  26. package/src/deploy/__tests__/index.spec.ts +12 -12
  27. package/src/deploy/__tests__/secrets.spec.ts +4 -1
  28. package/src/deploy/__tests__/sniffer.spec.ts +326 -1
  29. package/src/deploy/__tests__/state.spec.ts +844 -0
  30. package/src/deploy/dns/hostinger-api.ts +9 -6
  31. package/src/deploy/dns/index.ts +115 -4
  32. package/src/deploy/docker.ts +1 -2
  33. package/src/deploy/dokploy-api.ts +20 -11
  34. package/src/deploy/domain.ts +5 -4
  35. package/src/deploy/env-resolver.ts +278 -0
  36. package/src/deploy/index.ts +534 -124
  37. package/src/deploy/secrets.ts +7 -2
  38. package/src/deploy/sniffer-envkit-patch.ts +43 -0
  39. package/src/deploy/sniffer-hooks.ts +52 -0
  40. package/src/deploy/sniffer-loader.ts +23 -0
  41. package/src/deploy/sniffer-worker.ts +74 -0
  42. package/src/deploy/sniffer.ts +136 -14
  43. package/src/deploy/state.ts +162 -1
  44. package/src/docker/templates.ts +10 -14
  45. package/src/init/versions.ts +3 -3
  46. package/tsconfig.tsbuildinfo +1 -1
  47. package/dist/dokploy-api-4a6h35VY.cjs +0 -3
  48. package/dist/dokploy-api-BnX2OxyF.cjs.map +0 -1
  49. package/dist/dokploy-api-CMWlWq7-.mjs.map +0 -1
  50. 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 { sniffAllApps, sniffAppEnvironment, type SniffResult } from '../sniffer';
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
+ });