@geekmidas/cli 0.10.0 → 0.13.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-B1qy9b-j.cjs +112 -0
  3. package/dist/bundler-B1qy9b-j.cjs.map +1 -0
  4. package/dist/bundler-DskIqW2t.mjs +111 -0
  5. package/dist/bundler-DskIqW2t.mjs.map +1 -0
  6. package/dist/{config-C9aXOHBe.cjs → config-AmInkU7k.cjs} +8 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-BrkUalUh.mjs → config-DYULeEv8.mjs} +3 -3
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +1 -1
  12. package/dist/config.d.mts +1 -1
  13. package/dist/config.mjs +1 -1
  14. package/dist/encryption-C8H-38Yy.mjs +42 -0
  15. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  16. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  17. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  18. package/dist/index.cjs +2123 -179
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +2141 -192
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{openapi-CZLI4QTr.mjs → openapi-BfFlOBCG.mjs} +801 -38
  23. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  24. package/dist/{openapi-BeHLKcwP.cjs → openapi-Bt_1FDpT.cjs} +794 -31
  25. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  26. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  27. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  28. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  29. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  30. package/dist/openapi-react-query.cjs +1 -1
  31. package/dist/openapi-react-query.d.cts.map +1 -1
  32. package/dist/openapi-react-query.d.mts.map +1 -1
  33. package/dist/openapi-react-query.mjs +1 -1
  34. package/dist/openapi.cjs +2 -2
  35. package/dist/openapi.d.cts +1 -1
  36. package/dist/openapi.d.cts.map +1 -1
  37. package/dist/openapi.d.mts +1 -1
  38. package/dist/openapi.d.mts.map +1 -1
  39. package/dist/openapi.mjs +2 -2
  40. package/dist/storage-BOOpAF8N.cjs +5 -0
  41. package/dist/storage-Bj1E26lU.cjs +187 -0
  42. package/dist/storage-Bj1E26lU.cjs.map +1 -0
  43. package/dist/storage-kSxTjkNb.mjs +133 -0
  44. package/dist/storage-kSxTjkNb.mjs.map +1 -0
  45. package/dist/storage-tgZSUnKl.mjs +3 -0
  46. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  47. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  48. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  49. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  50. package/examples/cron-example.ts +27 -27
  51. package/examples/env.ts +27 -27
  52. package/examples/function-example.ts +31 -31
  53. package/examples/gkm.config.json +20 -20
  54. package/examples/gkm.config.ts +8 -8
  55. package/examples/gkm.minimal.config.json +5 -5
  56. package/examples/gkm.production.config.json +25 -25
  57. package/examples/logger.ts +2 -2
  58. package/package.json +6 -6
  59. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  60. package/src/__tests__/config.spec.ts +55 -55
  61. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  62. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  63. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  64. package/src/__tests__/openapi.spec.ts +428 -428
  65. package/src/__tests__/test-helpers.ts +76 -76
  66. package/src/auth/__tests__/credentials.spec.ts +204 -0
  67. package/src/auth/__tests__/index.spec.ts +168 -0
  68. package/src/auth/credentials.ts +187 -0
  69. package/src/auth/index.ts +226 -0
  70. package/src/build/__tests__/bundler.spec.ts +444 -0
  71. package/src/build/__tests__/index-new.spec.ts +474 -474
  72. package/src/build/__tests__/manifests.spec.ts +333 -333
  73. package/src/build/bundler.ts +210 -0
  74. package/src/build/endpoint-analyzer.ts +236 -0
  75. package/src/build/handler-templates.ts +1253 -0
  76. package/src/build/index.ts +260 -179
  77. package/src/build/manifests.ts +52 -52
  78. package/src/build/providerResolver.ts +145 -145
  79. package/src/build/types.ts +64 -43
  80. package/src/config.ts +39 -39
  81. package/src/deploy/__tests__/docker.spec.ts +111 -0
  82. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  83. package/src/deploy/__tests__/init.spec.ts +662 -0
  84. package/src/deploy/docker.ts +128 -0
  85. package/src/deploy/dokploy.ts +204 -0
  86. package/src/deploy/index.ts +136 -0
  87. package/src/deploy/init.ts +484 -0
  88. package/src/deploy/types.ts +48 -0
  89. package/src/dev/__tests__/index.spec.ts +266 -266
  90. package/src/dev/index.ts +647 -601
  91. package/src/docker/__tests__/compose.spec.ts +531 -0
  92. package/src/docker/__tests__/templates.spec.ts +280 -0
  93. package/src/docker/compose.ts +273 -0
  94. package/src/docker/index.ts +230 -0
  95. package/src/docker/templates.ts +446 -0
  96. package/src/generators/CronGenerator.ts +72 -72
  97. package/src/generators/EndpointGenerator.ts +699 -398
  98. package/src/generators/FunctionGenerator.ts +84 -84
  99. package/src/generators/Generator.ts +72 -72
  100. package/src/generators/OpenApiTsGenerator.ts +577 -577
  101. package/src/generators/SubscriberGenerator.ts +124 -124
  102. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  103. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  104. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  105. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  106. package/src/generators/index.ts +4 -4
  107. package/src/index.ts +623 -201
  108. package/src/init/__tests__/generators.spec.ts +334 -334
  109. package/src/init/__tests__/init.spec.ts +332 -332
  110. package/src/init/__tests__/utils.spec.ts +89 -89
  111. package/src/init/generators/config.ts +175 -175
  112. package/src/init/generators/docker.ts +41 -41
  113. package/src/init/generators/env.ts +72 -72
  114. package/src/init/generators/index.ts +1 -1
  115. package/src/init/generators/models.ts +64 -64
  116. package/src/init/generators/monorepo.ts +161 -161
  117. package/src/init/generators/package.ts +71 -71
  118. package/src/init/generators/source.ts +6 -6
  119. package/src/init/index.ts +203 -208
  120. package/src/init/templates/api.ts +115 -115
  121. package/src/init/templates/index.ts +75 -75
  122. package/src/init/templates/minimal.ts +98 -98
  123. package/src/init/templates/serverless.ts +89 -89
  124. package/src/init/templates/worker.ts +98 -98
  125. package/src/init/utils.ts +54 -56
  126. package/src/openapi-react-query.ts +194 -194
  127. package/src/openapi.ts +63 -63
  128. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  129. package/src/secrets/__tests__/generator.spec.ts +319 -0
  130. package/src/secrets/__tests__/index.spec.ts +91 -0
  131. package/src/secrets/__tests__/storage.spec.ts +611 -0
  132. package/src/secrets/encryption.ts +91 -0
  133. package/src/secrets/generator.ts +164 -0
  134. package/src/secrets/index.ts +383 -0
  135. package/src/secrets/storage.ts +192 -0
  136. package/src/secrets/types.ts +53 -0
  137. package/src/types.ts +295 -176
  138. package/tsdown.config.ts +11 -8
  139. package/dist/config-BrkUalUh.mjs.map +0 -1
  140. package/dist/config-C9aXOHBe.cjs.map +0 -1
  141. package/dist/openapi-BeHLKcwP.cjs.map +0 -1
  142. package/dist/openapi-CZLI4QTr.mjs.map +0 -1
  143. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  144. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
  145. package/dist/types-DXgiA1sF.d.mts.map +0 -1
  146. package/dist/types-b-vwGpqc.d.cts.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';