@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.
Files changed (81) hide show
  1. package/dist/{bundler-CyHg1v_T.cjs → bundler-BB-kETMd.cjs} +20 -49
  2. package/dist/bundler-BB-kETMd.cjs.map +1 -0
  3. package/dist/{bundler-DQIuE3Kn.mjs → bundler-DGry2vaR.mjs} +22 -51
  4. package/dist/bundler-DGry2vaR.mjs.map +1 -0
  5. package/dist/{config-BC5n1a2D.mjs → config-C0b0jdmU.mjs} +2 -2
  6. package/dist/{config-BC5n1a2D.mjs.map → config-C0b0jdmU.mjs.map} +1 -1
  7. package/dist/{config-BAE9LFC1.cjs → config-xVZsRjN7.cjs} +2 -2
  8. package/dist/{config-BAE9LFC1.cjs.map → config-xVZsRjN7.cjs.map} +1 -1
  9. package/dist/config.cjs +2 -2
  10. package/dist/config.d.cts +1 -1
  11. package/dist/config.d.mts +2 -2
  12. package/dist/config.mjs +2 -2
  13. package/dist/dokploy-api-Bdmk5ImW.cjs +3 -0
  14. package/dist/{dokploy-api-C5czOZoc.cjs → dokploy-api-BdxOMH_V.cjs} +43 -1
  15. package/dist/{dokploy-api-C5czOZoc.cjs.map → dokploy-api-BdxOMH_V.cjs.map} +1 -1
  16. package/dist/{dokploy-api-B9qR2Yn1.mjs → dokploy-api-DWsqNjwP.mjs} +43 -1
  17. package/dist/{dokploy-api-B9qR2Yn1.mjs.map → dokploy-api-DWsqNjwP.mjs.map} +1 -1
  18. package/dist/dokploy-api-tZSZaHd9.mjs +3 -0
  19. package/dist/{encryption-JtMsiGNp.mjs → encryption-BC4MAODn.mjs} +1 -1
  20. package/dist/{encryption-JtMsiGNp.mjs.map → encryption-BC4MAODn.mjs.map} +1 -1
  21. package/dist/encryption-Biq0EZ4m.cjs +4 -0
  22. package/dist/encryption-CQXBZGkt.mjs +3 -0
  23. package/dist/{encryption-BAz0xQ1Q.cjs → encryption-DaCB_NmS.cjs} +13 -3
  24. package/dist/{encryption-BAz0xQ1Q.cjs.map → encryption-DaCB_NmS.cjs.map} +1 -1
  25. package/dist/{index-C7TkoYmt.d.mts → index-CXa3odEw.d.mts} +68 -7
  26. package/dist/index-CXa3odEw.d.mts.map +1 -0
  27. package/dist/{index-CpchsC9w.d.cts → index-E8Nu2Rxl.d.cts} +67 -6
  28. package/dist/index-E8Nu2Rxl.d.cts.map +1 -0
  29. package/dist/index.cjs +698 -127
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.mjs +677 -106
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/{openapi-CjYeF-Tg.mjs → openapi-D3pA6FfZ.mjs} +2 -2
  34. package/dist/{openapi-CjYeF-Tg.mjs.map → openapi-D3pA6FfZ.mjs.map} +1 -1
  35. package/dist/{openapi-a-e3Y8WA.cjs → openapi-DhcCtKzM.cjs} +2 -2
  36. package/dist/{openapi-a-e3Y8WA.cjs.map → openapi-DhcCtKzM.cjs.map} +1 -1
  37. package/dist/{openapi-react-query-DvNpdDpM.cjs → openapi-react-query-C_MxpBgF.cjs} +1 -1
  38. package/dist/{openapi-react-query-DvNpdDpM.cjs.map → openapi-react-query-C_MxpBgF.cjs.map} +1 -1
  39. package/dist/{openapi-react-query-5rSortLH.mjs → openapi-react-query-ZoP9DPbY.mjs} +1 -1
  40. package/dist/{openapi-react-query-5rSortLH.mjs.map → openapi-react-query-ZoP9DPbY.mjs.map} +1 -1
  41. package/dist/openapi-react-query.cjs +1 -1
  42. package/dist/openapi-react-query.mjs +1 -1
  43. package/dist/openapi.cjs +3 -3
  44. package/dist/openapi.d.mts +1 -1
  45. package/dist/openapi.mjs +3 -3
  46. package/dist/{types-K2uQJ-FO.d.mts → types-BtGL-8QS.d.mts} +1 -1
  47. package/dist/{types-K2uQJ-FO.d.mts.map → types-BtGL-8QS.d.mts.map} +1 -1
  48. package/dist/workspace/index.cjs +1 -1
  49. package/dist/workspace/index.d.cts +2 -2
  50. package/dist/workspace/index.d.mts +3 -3
  51. package/dist/workspace/index.mjs +1 -1
  52. package/dist/{workspace-My0A4IRO.cjs → workspace-BDAhr6Kb.cjs} +33 -4
  53. package/dist/{workspace-My0A4IRO.cjs.map → workspace-BDAhr6Kb.cjs.map} +1 -1
  54. package/dist/{workspace-DFJ3sWfY.mjs → workspace-D_6ZCaR_.mjs} +33 -4
  55. package/dist/{workspace-DFJ3sWfY.mjs.map → workspace-D_6ZCaR_.mjs.map} +1 -1
  56. package/package.json +5 -5
  57. package/src/build/bundler.ts +27 -79
  58. package/src/deploy/__tests__/domain.spec.ts +231 -0
  59. package/src/deploy/__tests__/secrets.spec.ts +300 -0
  60. package/src/deploy/__tests__/sniffer.spec.ts +221 -0
  61. package/src/deploy/docker.ts +40 -11
  62. package/src/deploy/dokploy-api.ts +99 -0
  63. package/src/deploy/domain.ts +125 -0
  64. package/src/deploy/index.ts +366 -148
  65. package/src/deploy/secrets.ts +182 -0
  66. package/src/deploy/sniffer.ts +180 -0
  67. package/src/dev/index.ts +11 -0
  68. package/src/docker/index.ts +24 -5
  69. package/src/docker/templates.ts +187 -1
  70. package/src/init/templates/api.ts +4 -4
  71. package/src/init/versions.ts +2 -2
  72. package/src/workspace/index.ts +2 -0
  73. package/src/workspace/schema.ts +32 -6
  74. package/src/workspace/types.ts +64 -2
  75. package/tsconfig.tsbuildinfo +1 -1
  76. package/dist/bundler-CyHg1v_T.cjs.map +0 -1
  77. package/dist/bundler-DQIuE3Kn.mjs.map +0 -1
  78. package/dist/dokploy-api-B0w17y4_.mjs +0 -3
  79. package/dist/dokploy-api-BnGeUqN4.cjs +0 -3
  80. package/dist/index-C7TkoYmt.d.mts.map +0 -1
  81. package/dist/index-CpchsC9w.d.cts.map +0 -1
@@ -458,6 +458,68 @@ export class DokployApi {
458
458
  ): Promise<void> {
459
459
  await this.post('redis.update', { redisId, ...updates });
460
460
  }
461
+
462
+ // ============================================
463
+ // Domain endpoints
464
+ // ============================================
465
+
466
+ /**
467
+ * Create a new domain for an application
468
+ */
469
+ async createDomain(options: DokployDomainCreate): Promise<DokployDomain> {
470
+ return this.post<DokployDomain>(
471
+ 'domain.create',
472
+ options as unknown as Record<string, unknown>,
473
+ );
474
+ }
475
+
476
+ /**
477
+ * Update an existing domain
478
+ */
479
+ async updateDomain(
480
+ domainId: string,
481
+ updates: Partial<DokployDomainCreate>,
482
+ ): Promise<void> {
483
+ await this.post('domain.update', { domainId, ...updates });
484
+ }
485
+
486
+ /**
487
+ * Delete a domain
488
+ */
489
+ async deleteDomain(domainId: string): Promise<void> {
490
+ await this.post('domain.delete', { domainId });
491
+ }
492
+
493
+ /**
494
+ * Get a domain by ID
495
+ */
496
+ async getDomain(domainId: string): Promise<DokployDomain> {
497
+ return this.get<DokployDomain>(`domain.one?domainId=${domainId}`);
498
+ }
499
+
500
+ /**
501
+ * Get all domains for an application
502
+ */
503
+ async getDomainsByApplicationId(
504
+ applicationId: string,
505
+ ): Promise<DokployDomain[]> {
506
+ return this.get<DokployDomain[]>(
507
+ `domain.byApplicationId?applicationId=${applicationId}`,
508
+ );
509
+ }
510
+
511
+ /**
512
+ * Auto-generate a domain name for an application
513
+ */
514
+ async generateDomain(
515
+ appName: string,
516
+ serverId?: string,
517
+ ): Promise<{ domain: string }> {
518
+ return this.post<{ domain: string }>('domain.generateDomain', {
519
+ appName,
520
+ serverId,
521
+ });
522
+ }
461
523
  }
462
524
 
463
525
  // ============================================
@@ -552,6 +614,43 @@ export interface DokployRedisUpdate {
552
614
  description: string;
553
615
  }
554
616
 
617
+ export type DokployCertificateType = 'letsencrypt' | 'none' | 'custom';
618
+ export type DokployDomainType = 'application' | 'compose' | 'preview';
619
+
620
+ export interface DokployDomainCreate {
621
+ /** Domain hostname (e.g., 'api.example.com') */
622
+ host: string;
623
+ /** URL path (optional, e.g., '/api') */
624
+ path?: string | null;
625
+ /** Container port to route to (1-65535) */
626
+ port?: number | null;
627
+ /** Enable HTTPS */
628
+ https?: boolean;
629
+ /** Associated application ID */
630
+ applicationId?: string | null;
631
+ /** Certificate type for HTTPS */
632
+ certificateType?: DokployCertificateType;
633
+ /** Custom certificate resolver name */
634
+ customCertResolver?: string | null;
635
+ /** Docker Compose service ID */
636
+ composeId?: string | null;
637
+ /** Service name for compose */
638
+ serviceName?: string | null;
639
+ /** Domain type */
640
+ domainType?: DokployDomainType | null;
641
+ /** Preview deployment ID */
642
+ previewDeploymentId?: string | null;
643
+ /** Internal routing path */
644
+ internalPath?: string | null;
645
+ /** Strip path from forwarded requests */
646
+ stripPath?: boolean;
647
+ }
648
+
649
+ export interface DokployDomain extends DokployDomainCreate {
650
+ domainId: string;
651
+ createdAt?: string;
652
+ }
653
+
555
654
  /**
556
655
  * Create a Dokploy API client from stored credentials or environment
557
656
  */
@@ -0,0 +1,125 @@
1
+ import type { DokployWorkspaceConfig, NormalizedAppConfig } from '../workspace/types.js';
2
+
3
+ /**
4
+ * Resolve the hostname for an app based on stage configuration.
5
+ *
6
+ * Domain resolution priority:
7
+ * 1. Explicit app.domain override (string or stage-specific)
8
+ * 2. Default pattern based on app type:
9
+ * - Main frontend app gets base domain (e.g., 'myapp.com')
10
+ * - Other apps get prefixed domain (e.g., 'api.myapp.com')
11
+ *
12
+ * @param appName - The name of the app
13
+ * @param app - The normalized app configuration
14
+ * @param stage - The deployment stage (e.g., 'production', 'development')
15
+ * @param dokployConfig - Dokploy workspace configuration with domain mappings
16
+ * @param isMainFrontend - Whether this is the main frontend app
17
+ * @returns The resolved hostname for the app
18
+ * @throws Error if no domain configuration is found for the stage
19
+ */
20
+ export function resolveHost(
21
+ appName: string,
22
+ app: NormalizedAppConfig,
23
+ stage: string,
24
+ dokployConfig: DokployWorkspaceConfig | undefined,
25
+ isMainFrontend: boolean,
26
+ ): string {
27
+ // 1. Check for explicit app domain override
28
+ if (app.domain) {
29
+ if (typeof app.domain === 'string') {
30
+ return app.domain;
31
+ }
32
+ if (app.domain[stage]) {
33
+ return app.domain[stage]!;
34
+ }
35
+ }
36
+
37
+ // 2. Get base domain for this stage
38
+ const baseDomain = dokployConfig?.domains?.[stage];
39
+ if (!baseDomain) {
40
+ throw new Error(
41
+ `No domain configured for stage "${stage}". ` +
42
+ `Add deploy.dokploy.domains.${stage} to gkm.config.ts`,
43
+ );
44
+ }
45
+
46
+ // 3. Main frontend app gets base domain, others get prefix
47
+ if (isMainFrontend) {
48
+ return baseDomain;
49
+ }
50
+
51
+ return `${appName}.${baseDomain}`;
52
+ }
53
+
54
+ /**
55
+ * Determine if an app is the "main" frontend (gets base domain).
56
+ *
57
+ * An app is considered the main frontend if:
58
+ * 1. It's named 'web' and is a frontend type
59
+ * 2. It's the first frontend app in the apps list
60
+ *
61
+ * @param appName - The name of the app to check
62
+ * @param app - The app configuration
63
+ * @param allApps - All apps in the workspace
64
+ * @returns True if this is the main frontend app
65
+ */
66
+ export function isMainFrontendApp(
67
+ appName: string,
68
+ app: NormalizedAppConfig,
69
+ allApps: Record<string, NormalizedAppConfig>,
70
+ ): boolean {
71
+ if (app.type !== 'frontend') {
72
+ return false;
73
+ }
74
+
75
+ // App named 'web' is always main
76
+ if (appName === 'web') {
77
+ return true;
78
+ }
79
+
80
+ // Otherwise, check if this is the first frontend
81
+ for (const [name, a] of Object.entries(allApps)) {
82
+ if (a.type === 'frontend') {
83
+ return name === appName;
84
+ }
85
+ }
86
+
87
+ return false;
88
+ }
89
+
90
+ /**
91
+ * Generate public URL build args for a frontend app based on its dependencies.
92
+ *
93
+ * @param app - The frontend app configuration
94
+ * @param deployedUrls - Map of app name to deployed public URL
95
+ * @returns Array of build args like 'NEXT_PUBLIC_API_URL=https://api.example.com'
96
+ */
97
+ export function generatePublicUrlBuildArgs(
98
+ app: NormalizedAppConfig,
99
+ deployedUrls: Record<string, string>,
100
+ ): string[] {
101
+ const buildArgs: string[] = [];
102
+
103
+ for (const dep of app.dependencies) {
104
+ const publicUrl = deployedUrls[dep];
105
+ if (publicUrl) {
106
+ // Convert app name to UPPER_SNAKE_CASE for env var
107
+ const envVarName = `NEXT_PUBLIC_${dep.toUpperCase()}_URL`;
108
+ buildArgs.push(`${envVarName}=${publicUrl}`);
109
+ }
110
+ }
111
+
112
+ return buildArgs;
113
+ }
114
+
115
+ /**
116
+ * Get public URL arg names from app dependencies.
117
+ *
118
+ * @param app - The frontend app configuration
119
+ * @returns Array of arg names like 'NEXT_PUBLIC_API_URL'
120
+ */
121
+ export function getPublicUrlArgNames(app: NormalizedAppConfig): string[] {
122
+ return app.dependencies.map(
123
+ (dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`,
124
+ );
125
+ }