@geekmidas/cli 0.9.0 → 0.12.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 (146) hide show
  1. package/README.md +525 -0
  2. package/dist/bundler-DRXCw_YR.mjs +70 -0
  3. package/dist/bundler-DRXCw_YR.mjs.map +1 -0
  4. package/dist/bundler-WsEvH_b2.cjs +71 -0
  5. package/dist/bundler-WsEvH_b2.cjs.map +1 -0
  6. package/dist/{config-CFls09Ey.cjs → config-AmInkU7k.cjs} +10 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-Bq72aj8e.mjs → config-DYULeEv8.mjs} +6 -4
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +2 -1
  12. package/dist/config.d.cts.map +1 -0
  13. package/dist/config.d.mts +2 -1
  14. package/dist/config.d.mts.map +1 -0
  15. package/dist/config.mjs +1 -1
  16. package/dist/encryption-C8H-38Yy.mjs +42 -0
  17. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  18. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  19. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  20. package/dist/index.cjs +2125 -184
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.mjs +2143 -197
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{openapi--vOy9mo4.mjs → openapi-BfFlOBCG.mjs} +812 -49
  25. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  26. package/dist/{openapi-CHhTPief.cjs → openapi-Bt_1FDpT.cjs} +805 -42
  27. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  28. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  29. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  30. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  31. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  32. package/dist/openapi-react-query.cjs +1 -1
  33. package/dist/openapi-react-query.d.cts.map +1 -0
  34. package/dist/openapi-react-query.d.mts.map +1 -0
  35. package/dist/openapi-react-query.mjs +1 -1
  36. package/dist/openapi.cjs +2 -2
  37. package/dist/openapi.d.cts +1 -1
  38. package/dist/openapi.d.cts.map +1 -0
  39. package/dist/openapi.d.mts +1 -1
  40. package/dist/openapi.d.mts.map +1 -0
  41. package/dist/openapi.mjs +2 -2
  42. package/dist/storage-BUYQJgz7.cjs +4 -0
  43. package/dist/storage-BXoJvmv2.cjs +149 -0
  44. package/dist/storage-BXoJvmv2.cjs.map +1 -0
  45. package/dist/storage-C9PU_30f.mjs +101 -0
  46. package/dist/storage-C9PU_30f.mjs.map +1 -0
  47. package/dist/storage-DLJAYxzJ.mjs +3 -0
  48. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  49. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  50. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  51. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  52. package/examples/cron-example.ts +27 -27
  53. package/examples/env.ts +27 -27
  54. package/examples/function-example.ts +31 -31
  55. package/examples/gkm.config.json +20 -20
  56. package/examples/gkm.config.ts +8 -8
  57. package/examples/gkm.minimal.config.json +5 -5
  58. package/examples/gkm.production.config.json +25 -25
  59. package/examples/logger.ts +2 -2
  60. package/package.json +6 -6
  61. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  62. package/src/__tests__/config.spec.ts +55 -55
  63. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  64. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  65. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  66. package/src/__tests__/openapi.spec.ts +428 -428
  67. package/src/__tests__/test-helpers.ts +77 -76
  68. package/src/auth/__tests__/credentials.spec.ts +204 -0
  69. package/src/auth/__tests__/index.spec.ts +168 -0
  70. package/src/auth/credentials.ts +187 -0
  71. package/src/auth/index.ts +226 -0
  72. package/src/build/__tests__/index-new.spec.ts +474 -474
  73. package/src/build/__tests__/manifests.spec.ts +333 -333
  74. package/src/build/bundler.ts +141 -0
  75. package/src/build/endpoint-analyzer.ts +236 -0
  76. package/src/build/handler-templates.ts +1253 -0
  77. package/src/build/index.ts +250 -179
  78. package/src/build/manifests.ts +52 -52
  79. package/src/build/providerResolver.ts +145 -145
  80. package/src/build/types.ts +64 -43
  81. package/src/config.ts +39 -37
  82. package/src/deploy/__tests__/docker.spec.ts +111 -0
  83. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  84. package/src/deploy/__tests__/init.spec.ts +662 -0
  85. package/src/deploy/docker.ts +128 -0
  86. package/src/deploy/dokploy.ts +204 -0
  87. package/src/deploy/index.ts +136 -0
  88. package/src/deploy/init.ts +484 -0
  89. package/src/deploy/types.ts +48 -0
  90. package/src/dev/__tests__/index.spec.ts +266 -266
  91. package/src/dev/index.ts +647 -593
  92. package/src/docker/__tests__/compose.spec.ts +531 -0
  93. package/src/docker/__tests__/templates.spec.ts +280 -0
  94. package/src/docker/compose.ts +273 -0
  95. package/src/docker/index.ts +230 -0
  96. package/src/docker/templates.ts +446 -0
  97. package/src/generators/CronGenerator.ts +72 -72
  98. package/src/generators/EndpointGenerator.ts +699 -398
  99. package/src/generators/FunctionGenerator.ts +84 -84
  100. package/src/generators/Generator.ts +72 -72
  101. package/src/generators/OpenApiTsGenerator.ts +589 -589
  102. package/src/generators/SubscriberGenerator.ts +124 -124
  103. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  104. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  105. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  106. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  107. package/src/generators/index.ts +4 -4
  108. package/src/index.ts +628 -206
  109. package/src/init/__tests__/generators.spec.ts +334 -334
  110. package/src/init/__tests__/init.spec.ts +332 -332
  111. package/src/init/__tests__/utils.spec.ts +89 -89
  112. package/src/init/generators/config.ts +175 -175
  113. package/src/init/generators/docker.ts +41 -41
  114. package/src/init/generators/env.ts +72 -72
  115. package/src/init/generators/index.ts +1 -1
  116. package/src/init/generators/models.ts +64 -64
  117. package/src/init/generators/monorepo.ts +161 -161
  118. package/src/init/generators/package.ts +71 -71
  119. package/src/init/generators/source.ts +6 -6
  120. package/src/init/index.ts +203 -208
  121. package/src/init/templates/api.ts +115 -115
  122. package/src/init/templates/index.ts +75 -75
  123. package/src/init/templates/minimal.ts +98 -98
  124. package/src/init/templates/serverless.ts +89 -89
  125. package/src/init/templates/worker.ts +98 -98
  126. package/src/init/utils.ts +54 -56
  127. package/src/openapi-react-query.ts +194 -194
  128. package/src/openapi.ts +63 -63
  129. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  130. package/src/secrets/__tests__/generator.spec.ts +319 -0
  131. package/src/secrets/__tests__/index.spec.ts +91 -0
  132. package/src/secrets/__tests__/storage.spec.ts +403 -0
  133. package/src/secrets/encryption.ts +91 -0
  134. package/src/secrets/generator.ts +164 -0
  135. package/src/secrets/index.ts +383 -0
  136. package/src/secrets/storage.ts +134 -0
  137. package/src/secrets/types.ts +53 -0
  138. package/src/types.ts +295 -176
  139. package/tsconfig.json +9 -0
  140. package/tsdown.config.ts +11 -8
  141. package/dist/config-Bq72aj8e.mjs.map +0 -1
  142. package/dist/config-CFls09Ey.cjs.map +0 -1
  143. package/dist/openapi--vOy9mo4.mjs.map +0 -1
  144. package/dist/openapi-CHhTPief.cjs.map +0 -1
  145. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  146. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
@@ -0,0 +1,187 @@
1
+ import { existsSync, mkdirSync } from 'node:fs';
2
+ import { readFile, unlink, writeFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+
6
+ /**
7
+ * Stored credentials for various services
8
+ */
9
+ export interface StoredCredentials {
10
+ dokploy?: {
11
+ /** API token */
12
+ token: string;
13
+ /** Dokploy endpoint URL */
14
+ endpoint: string;
15
+ /** When the credentials were stored */
16
+ storedAt: string;
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Options for credential operations
22
+ */
23
+ export interface CredentialOptions {
24
+ /** Root directory for credentials storage (default: user home directory) */
25
+ root?: string;
26
+ }
27
+
28
+ /**
29
+ * Get the path to the credentials directory
30
+ */
31
+ export function getCredentialsDir(options?: CredentialOptions): string {
32
+ const root = options?.root ?? homedir();
33
+ return join(root, '.gkm');
34
+ }
35
+
36
+ /**
37
+ * Get the path to the credentials file
38
+ */
39
+ export function getCredentialsPath(options?: CredentialOptions): string {
40
+ return join(getCredentialsDir(options), 'credentials.json');
41
+ }
42
+
43
+ /**
44
+ * Ensure the credentials directory exists
45
+ */
46
+ function ensureCredentialsDir(options?: CredentialOptions): void {
47
+ const dir = getCredentialsDir(options);
48
+ if (!existsSync(dir)) {
49
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Read stored credentials from disk
55
+ */
56
+ export async function readCredentials(
57
+ options?: CredentialOptions,
58
+ ): Promise<StoredCredentials> {
59
+ const path = getCredentialsPath(options);
60
+
61
+ if (!existsSync(path)) {
62
+ return {};
63
+ }
64
+
65
+ try {
66
+ const content = await readFile(path, 'utf-8');
67
+ return JSON.parse(content) as StoredCredentials;
68
+ } catch {
69
+ return {};
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Write credentials to disk
75
+ */
76
+ export async function writeCredentials(
77
+ credentials: StoredCredentials,
78
+ options?: CredentialOptions,
79
+ ): Promise<void> {
80
+ ensureCredentialsDir(options);
81
+ const path = getCredentialsPath(options);
82
+
83
+ await writeFile(path, JSON.stringify(credentials, null, 2), {
84
+ mode: 0o600, // Owner read/write only
85
+ });
86
+ }
87
+
88
+ /**
89
+ * Store Dokploy credentials
90
+ */
91
+ export async function storeDokployCredentials(
92
+ token: string,
93
+ endpoint: string,
94
+ options?: CredentialOptions,
95
+ ): Promise<void> {
96
+ const credentials = await readCredentials(options);
97
+
98
+ credentials.dokploy = {
99
+ token,
100
+ endpoint,
101
+ storedAt: new Date().toISOString(),
102
+ };
103
+
104
+ await writeCredentials(credentials, options);
105
+ }
106
+
107
+ /**
108
+ * Get stored Dokploy credentials
109
+ */
110
+ export async function getDokployCredentials(
111
+ options?: CredentialOptions,
112
+ ): Promise<{
113
+ token: string;
114
+ endpoint: string;
115
+ } | null> {
116
+ const credentials = await readCredentials(options);
117
+
118
+ if (!credentials.dokploy) {
119
+ return null;
120
+ }
121
+
122
+ return {
123
+ token: credentials.dokploy.token,
124
+ endpoint: credentials.dokploy.endpoint,
125
+ };
126
+ }
127
+
128
+ /**
129
+ * Remove Dokploy credentials
130
+ */
131
+ export async function removeDokployCredentials(
132
+ options?: CredentialOptions,
133
+ ): Promise<boolean> {
134
+ const credentials = await readCredentials(options);
135
+
136
+ if (!credentials.dokploy) {
137
+ return false;
138
+ }
139
+
140
+ delete credentials.dokploy;
141
+ await writeCredentials(credentials, options);
142
+ return true;
143
+ }
144
+
145
+ /**
146
+ * Remove all stored credentials
147
+ */
148
+ export async function removeAllCredentials(
149
+ options?: CredentialOptions,
150
+ ): Promise<void> {
151
+ const path = getCredentialsPath(options);
152
+
153
+ if (existsSync(path)) {
154
+ await unlink(path);
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Get Dokploy API token, checking stored credentials first, then environment
160
+ */
161
+ export async function getDokployToken(
162
+ options?: CredentialOptions,
163
+ ): Promise<string | null> {
164
+ // First check environment variable (takes precedence)
165
+ const envToken = process.env.DOKPLOY_API_TOKEN;
166
+ if (envToken) {
167
+ return envToken;
168
+ }
169
+
170
+ // Then check stored credentials
171
+ const stored = await getDokployCredentials(options);
172
+ if (stored) {
173
+ return stored.token;
174
+ }
175
+
176
+ return null;
177
+ }
178
+
179
+ /**
180
+ * Get Dokploy endpoint from stored credentials
181
+ */
182
+ export async function getDokployEndpoint(
183
+ options?: CredentialOptions,
184
+ ): Promise<string | null> {
185
+ const stored = await getDokployCredentials(options);
186
+ return stored?.endpoint ?? null;
187
+ }
@@ -0,0 +1,226 @@
1
+ import { stdin as input, stdout as output } from 'node:process';
2
+ import * as readline from 'node:readline/promises';
3
+ import {
4
+ getCredentialsPath,
5
+ getDokployCredentials,
6
+ removeDokployCredentials,
7
+ storeDokployCredentials,
8
+ } from './credentials';
9
+
10
+ const logger = console;
11
+
12
+ export interface LoginOptions {
13
+ /** Service to login to */
14
+ service: 'dokploy';
15
+ /** API token (if not provided, will prompt) */
16
+ token?: string;
17
+ /** Endpoint URL */
18
+ endpoint?: string;
19
+ }
20
+
21
+ export interface LogoutOptions {
22
+ /** Service to logout from */
23
+ service?: 'dokploy' | 'all';
24
+ }
25
+
26
+ /**
27
+ * Validate Dokploy token by making a test API call
28
+ */
29
+ export async function validateDokployToken(
30
+ endpoint: string,
31
+ token: string,
32
+ ): Promise<boolean> {
33
+ try {
34
+ const response = await fetch(`${endpoint}/api/project.all`, {
35
+ method: 'GET',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ Authorization: `Bearer ${token}`,
39
+ },
40
+ });
41
+
42
+ return response.ok;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Prompt for input (handles both TTY and non-TTY)
50
+ */
51
+ async function prompt(message: string, hidden = false): Promise<string> {
52
+ if (!process.stdin.isTTY) {
53
+ throw new Error(
54
+ 'Interactive input required. Please provide --token option.',
55
+ );
56
+ }
57
+
58
+ const rl = readline.createInterface({ input, output });
59
+
60
+ try {
61
+ if (hidden) {
62
+ // For hidden input, we need to handle it differently
63
+ process.stdout.write(message);
64
+
65
+ return new Promise((resolve) => {
66
+ let value = '';
67
+
68
+ const onData = (char: Buffer) => {
69
+ const c = char.toString();
70
+
71
+ if (c === '\n' || c === '\r') {
72
+ process.stdin.removeListener('data', onData);
73
+ process.stdin.setRawMode(false);
74
+ process.stdout.write('\n');
75
+ resolve(value);
76
+ } else if (c === '\u0003') {
77
+ // Ctrl+C
78
+ process.exit(1);
79
+ } else if (c === '\u007F' || c === '\b') {
80
+ // Backspace
81
+ if (value.length > 0) {
82
+ value = value.slice(0, -1);
83
+ }
84
+ } else {
85
+ value += c;
86
+ }
87
+ };
88
+
89
+ process.stdin.setRawMode(true);
90
+ process.stdin.resume();
91
+ process.stdin.on('data', onData);
92
+ });
93
+ } else {
94
+ return await rl.question(message);
95
+ }
96
+ } finally {
97
+ rl.close();
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Login to a service
103
+ */
104
+ export async function loginCommand(options: LoginOptions): Promise<void> {
105
+ const { service, token: providedToken, endpoint: providedEndpoint } = options;
106
+
107
+ if (service === 'dokploy') {
108
+ logger.log('\n🔐 Logging in to Dokploy...\n');
109
+
110
+ // Get endpoint
111
+ let endpoint = providedEndpoint;
112
+ if (!endpoint) {
113
+ endpoint = await prompt(
114
+ 'Dokploy URL (e.g., https://dokploy.example.com): ',
115
+ );
116
+ }
117
+
118
+ // Normalize endpoint (remove trailing slash)
119
+ endpoint = endpoint.replace(/\/$/, '');
120
+
121
+ // Validate endpoint format
122
+ try {
123
+ new URL(endpoint);
124
+ } catch {
125
+ logger.error('Invalid URL format');
126
+ process.exit(1);
127
+ }
128
+
129
+ // Get token
130
+ let token = providedToken;
131
+ if (!token) {
132
+ logger.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
133
+ token = await prompt('API Token: ', true);
134
+ }
135
+
136
+ if (!token) {
137
+ logger.error('Token is required');
138
+ process.exit(1);
139
+ }
140
+
141
+ // Validate token
142
+ logger.log('\nValidating credentials...');
143
+ const isValid = await validateDokployToken(endpoint, token);
144
+
145
+ if (!isValid) {
146
+ logger.error(
147
+ '\n✗ Invalid credentials. Please check your token and try again.',
148
+ );
149
+ process.exit(1);
150
+ }
151
+
152
+ // Store credentials
153
+ await storeDokployCredentials(token, endpoint);
154
+
155
+ logger.log('\n✓ Successfully logged in to Dokploy!');
156
+ logger.log(` Endpoint: ${endpoint}`);
157
+ logger.log(` Credentials stored in: ${getCredentialsPath()}`);
158
+ logger.log(
159
+ '\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.',
160
+ );
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Logout from a service
166
+ */
167
+ export async function logoutCommand(options: LogoutOptions): Promise<void> {
168
+ const { service = 'dokploy' } = options;
169
+
170
+ if (service === 'all') {
171
+ const dokployRemoved = await removeDokployCredentials();
172
+
173
+ if (dokployRemoved) {
174
+ logger.log('\n✓ Logged out from all services');
175
+ } else {
176
+ logger.log('\nNo stored credentials found');
177
+ }
178
+ return;
179
+ }
180
+
181
+ if (service === 'dokploy') {
182
+ const removed = await removeDokployCredentials();
183
+
184
+ if (removed) {
185
+ logger.log('\n✓ Logged out from Dokploy');
186
+ } else {
187
+ logger.log('\nNo Dokploy credentials found');
188
+ }
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Show current login status
194
+ */
195
+ export async function whoamiCommand(): Promise<void> {
196
+ logger.log('\n📋 Current credentials:\n');
197
+
198
+ const dokploy = await getDokployCredentials();
199
+
200
+ if (dokploy) {
201
+ logger.log(' Dokploy:');
202
+ logger.log(` Endpoint: ${dokploy.endpoint}`);
203
+ logger.log(` Token: ${maskToken(dokploy.token)}`);
204
+ } else {
205
+ logger.log(' Dokploy: Not logged in');
206
+ }
207
+
208
+ logger.log(`\n Credentials file: ${getCredentialsPath()}`);
209
+ }
210
+
211
+ /**
212
+ * Mask a token for display
213
+ */
214
+ export function maskToken(token: string): string {
215
+ if (token.length <= 8) {
216
+ return '****';
217
+ }
218
+ return `${token.slice(0, 4)}...${token.slice(-4)}`;
219
+ }
220
+
221
+ // Re-export credentials utilities for use in other modules
222
+ export {
223
+ getDokployCredentials,
224
+ getDokployEndpoint,
225
+ getDokployToken,
226
+ } from './credentials';