@geekmidas/cli 0.12.0 → 0.14.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/bundler-BjholBlA.cjs +131 -0
- package/dist/bundler-BjholBlA.cjs.map +1 -0
- package/dist/bundler-DWctKN1z.mjs +130 -0
- package/dist/bundler-DWctKN1z.mjs.map +1 -0
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/dokploy-api-B7KxOQr3.cjs +3 -0
- package/dist/dokploy-api-C7F9VykY.cjs +317 -0
- package/dist/dokploy-api-C7F9VykY.cjs.map +1 -0
- package/dist/dokploy-api-CaETb2L6.mjs +305 -0
- package/dist/dokploy-api-CaETb2L6.mjs.map +1 -0
- package/dist/dokploy-api-DHvfmWbi.mjs +3 -0
- package/dist/{encryption-Dyf_r1h-.cjs → encryption-D7Efcdi9.cjs} +1 -1
- package/dist/{encryption-Dyf_r1h-.cjs.map → encryption-D7Efcdi9.cjs.map} +1 -1
- package/dist/{encryption-C8H-38Yy.mjs → encryption-h4Nb6W-M.mjs} +1 -1
- package/dist/{encryption-C8H-38Yy.mjs.map → encryption-h4Nb6W-M.mjs.map} +1 -1
- package/dist/index.cjs +1520 -1136
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1520 -1136
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-Bt_1FDpT.cjs → openapi-C89hhkZC.cjs} +3 -3
- package/dist/{openapi-Bt_1FDpT.cjs.map → openapi-C89hhkZC.cjs.map} +1 -1
- package/dist/{openapi-BfFlOBCG.mjs → openapi-CZVcfxk-.mjs} +3 -3
- package/dist/{openapi-BfFlOBCG.mjs.map → openapi-CZVcfxk-.mjs.map} +1 -1
- package/dist/{openapi-react-query-B6XTeGqS.mjs → openapi-react-query-CM2_qlW9.mjs} +1 -1
- package/dist/{openapi-react-query-B6XTeGqS.mjs.map → openapi-react-query-CM2_qlW9.mjs.map} +1 -1
- package/dist/{openapi-react-query-B-sNWHFU.cjs → openapi-react-query-iKjfLzff.cjs} +1 -1
- package/dist/{openapi-react-query-B-sNWHFU.cjs.map → openapi-react-query-iKjfLzff.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/{storage-C9PU_30f.mjs → storage-BaOP55oq.mjs} +48 -2
- package/dist/storage-BaOP55oq.mjs.map +1 -0
- package/dist/{storage-BXoJvmv2.cjs → storage-Bn3K9Ccu.cjs} +59 -1
- package/dist/storage-Bn3K9Ccu.cjs.map +1 -0
- package/dist/storage-UfyTn7Zm.cjs +7 -0
- package/dist/storage-nkGIjeXt.mjs +3 -0
- package/dist/{types-BR0M2v_c.d.mts → types-BgaMXsUa.d.cts} +3 -1
- package/dist/{types-BR0M2v_c.d.mts.map → types-BgaMXsUa.d.cts.map} +1 -1
- package/dist/{types-BhkZc-vm.d.cts → types-iFk5ms7y.d.mts} +3 -1
- package/dist/{types-BhkZc-vm.d.cts.map → types-iFk5ms7y.d.mts.map} +1 -1
- package/package.json +4 -4
- package/src/auth/__tests__/credentials.spec.ts +127 -0
- package/src/auth/__tests__/index.spec.ts +69 -0
- package/src/auth/credentials.ts +33 -0
- package/src/auth/index.ts +57 -50
- package/src/build/__tests__/bundler.spec.ts +444 -0
- package/src/build/__tests__/endpoint-analyzer.spec.ts +623 -0
- package/src/build/__tests__/handler-templates.spec.ts +272 -0
- package/src/build/bundler.ts +126 -8
- package/src/build/index.ts +31 -0
- package/src/build/types.ts +6 -0
- package/src/deploy/__tests__/dokploy-api.spec.ts +698 -0
- package/src/deploy/__tests__/dokploy.spec.ts +196 -6
- package/src/deploy/__tests__/index.spec.ts +339 -0
- package/src/deploy/__tests__/init.spec.ts +147 -16
- package/src/deploy/docker.ts +32 -3
- package/src/deploy/dokploy-api.ts +581 -0
- package/src/deploy/dokploy.ts +66 -93
- package/src/deploy/index.ts +587 -32
- package/src/deploy/init.ts +192 -249
- package/src/deploy/types.ts +19 -1
- package/src/dev/__tests__/index.spec.ts +95 -0
- package/src/docker/__tests__/templates.spec.ts +144 -0
- package/src/docker/index.ts +96 -6
- package/src/docker/templates.ts +114 -27
- package/src/generators/EndpointGenerator.ts +2 -2
- package/src/index.ts +34 -13
- package/src/secrets/__tests__/storage.spec.ts +208 -0
- package/src/secrets/storage.ts +73 -0
- package/src/types.ts +2 -0
- package/dist/bundler-DRXCw_YR.mjs +0 -70
- package/dist/bundler-DRXCw_YR.mjs.map +0 -1
- package/dist/bundler-WsEvH_b2.cjs +0 -71
- package/dist/bundler-WsEvH_b2.cjs.map +0 -1
- package/dist/storage-BUYQJgz7.cjs +0 -4
- package/dist/storage-BXoJvmv2.cjs.map +0 -1
- package/dist/storage-C9PU_30f.mjs.map +0 -1
- package/dist/storage-DLJAYxzJ.mjs +0 -3
package/src/index.ts
CHANGED
|
@@ -47,7 +47,8 @@ program
|
|
|
47
47
|
process.chdir(globalOptions.cwd);
|
|
48
48
|
}
|
|
49
49
|
await initCommand(name, options);
|
|
50
|
-
} catch (
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
51
52
|
process.exit(1);
|
|
52
53
|
}
|
|
53
54
|
});
|
|
@@ -120,7 +121,10 @@ program
|
|
|
120
121
|
stage: options.stage,
|
|
121
122
|
});
|
|
122
123
|
}
|
|
123
|
-
} catch (
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(
|
|
126
|
+
error instanceof Error ? error.message : 'Command failed',
|
|
127
|
+
);
|
|
124
128
|
process.exit(1);
|
|
125
129
|
}
|
|
126
130
|
},
|
|
@@ -147,7 +151,8 @@ program
|
|
|
147
151
|
portExplicit: !!options.port,
|
|
148
152
|
enableOpenApi: options.enableOpenapi ?? true,
|
|
149
153
|
});
|
|
150
|
-
} catch (
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
151
156
|
process.exit(1);
|
|
152
157
|
}
|
|
153
158
|
});
|
|
@@ -195,7 +200,8 @@ program
|
|
|
195
200
|
process.chdir(globalOptions.cwd);
|
|
196
201
|
}
|
|
197
202
|
await openapiCommand({});
|
|
198
|
-
} catch (
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
199
205
|
process.exit(1);
|
|
200
206
|
}
|
|
201
207
|
});
|
|
@@ -218,7 +224,10 @@ program
|
|
|
218
224
|
process.chdir(globalOptions.cwd);
|
|
219
225
|
}
|
|
220
226
|
await generateReactQueryCommand(options);
|
|
221
|
-
} catch (
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error(
|
|
229
|
+
error instanceof Error ? error.message : 'Command failed',
|
|
230
|
+
);
|
|
222
231
|
process.exit(1);
|
|
223
232
|
}
|
|
224
233
|
},
|
|
@@ -241,7 +250,8 @@ program
|
|
|
241
250
|
process.chdir(globalOptions.cwd);
|
|
242
251
|
}
|
|
243
252
|
await dockerCommand(options);
|
|
244
|
-
} catch (
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
245
255
|
process.exit(1);
|
|
246
256
|
}
|
|
247
257
|
});
|
|
@@ -299,7 +309,10 @@ program
|
|
|
299
309
|
const registry = options.registry;
|
|
300
310
|
const _imageRef = registry ? `${registry}/api:${tag}` : `api:${tag}`;
|
|
301
311
|
}
|
|
302
|
-
} catch (
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error(
|
|
314
|
+
error instanceof Error ? error.message : 'Command failed',
|
|
315
|
+
);
|
|
303
316
|
process.exit(1);
|
|
304
317
|
}
|
|
305
318
|
},
|
|
@@ -318,7 +331,8 @@ program
|
|
|
318
331
|
process.chdir(globalOptions.cwd);
|
|
319
332
|
}
|
|
320
333
|
await secretsInitCommand(options);
|
|
321
|
-
} catch (
|
|
334
|
+
} catch (error) {
|
|
335
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
322
336
|
process.exit(1);
|
|
323
337
|
}
|
|
324
338
|
});
|
|
@@ -341,7 +355,10 @@ program
|
|
|
341
355
|
process.chdir(globalOptions.cwd);
|
|
342
356
|
}
|
|
343
357
|
await secretsSetCommand(key, value, options);
|
|
344
|
-
} catch (
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error(
|
|
360
|
+
error instanceof Error ? error.message : 'Command failed',
|
|
361
|
+
);
|
|
345
362
|
process.exit(1);
|
|
346
363
|
}
|
|
347
364
|
},
|
|
@@ -359,7 +376,8 @@ program
|
|
|
359
376
|
process.chdir(globalOptions.cwd);
|
|
360
377
|
}
|
|
361
378
|
await secretsShowCommand(options);
|
|
362
|
-
} catch (
|
|
379
|
+
} catch (error) {
|
|
380
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
363
381
|
process.exit(1);
|
|
364
382
|
}
|
|
365
383
|
});
|
|
@@ -379,7 +397,8 @@ program
|
|
|
379
397
|
process.chdir(globalOptions.cwd);
|
|
380
398
|
}
|
|
381
399
|
await secretsRotateCommand(options);
|
|
382
|
-
} catch (
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
383
402
|
process.exit(1);
|
|
384
403
|
}
|
|
385
404
|
});
|
|
@@ -397,7 +416,8 @@ program
|
|
|
397
416
|
process.chdir(globalOptions.cwd);
|
|
398
417
|
}
|
|
399
418
|
await secretsImportCommand(file, options);
|
|
400
|
-
} catch (
|
|
419
|
+
} catch (error) {
|
|
420
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
401
421
|
process.exit(1);
|
|
402
422
|
}
|
|
403
423
|
});
|
|
@@ -447,7 +467,8 @@ program
|
|
|
447
467
|
skipPush: options.skipPush,
|
|
448
468
|
skipBuild: options.skipBuild,
|
|
449
469
|
});
|
|
450
|
-
} catch (
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.error(error instanceof Error ? error.message : 'Deploy failed');
|
|
451
472
|
process.exit(1);
|
|
452
473
|
}
|
|
453
474
|
},
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
secretsExist,
|
|
12
12
|
setCustomSecret,
|
|
13
13
|
toEmbeddableSecrets,
|
|
14
|
+
validateEnvironmentVariables,
|
|
14
15
|
writeStageSecrets,
|
|
15
16
|
} from '../storage';
|
|
16
17
|
import type { StageSecrets } from '../types';
|
|
@@ -401,3 +402,210 @@ describe('maskPassword', () => {
|
|
|
401
402
|
expect(masked).toBe('1234***89');
|
|
402
403
|
});
|
|
403
404
|
});
|
|
405
|
+
|
|
406
|
+
describe('validateEnvironmentVariables', () => {
|
|
407
|
+
const baseSecrets: StageSecrets = {
|
|
408
|
+
stage: 'production',
|
|
409
|
+
createdAt: new Date().toISOString(),
|
|
410
|
+
updatedAt: new Date().toISOString(),
|
|
411
|
+
services: {},
|
|
412
|
+
urls: {},
|
|
413
|
+
custom: {},
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
it('should return valid when no variables are required', () => {
|
|
417
|
+
const result = validateEnvironmentVariables([], baseSecrets);
|
|
418
|
+
|
|
419
|
+
expect(result.valid).toBe(true);
|
|
420
|
+
expect(result.missing).toEqual([]);
|
|
421
|
+
expect(result.provided).toEqual([]);
|
|
422
|
+
expect(result.required).toEqual([]);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('should return valid when all required variables are present', () => {
|
|
426
|
+
const secrets: StageSecrets = {
|
|
427
|
+
...baseSecrets,
|
|
428
|
+
urls: {
|
|
429
|
+
DATABASE_URL: 'postgresql://...',
|
|
430
|
+
},
|
|
431
|
+
custom: {
|
|
432
|
+
API_KEY: 'sk_test_123',
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const result = validateEnvironmentVariables(
|
|
437
|
+
['DATABASE_URL', 'API_KEY'],
|
|
438
|
+
secrets,
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
expect(result.valid).toBe(true);
|
|
442
|
+
expect(result.missing).toEqual([]);
|
|
443
|
+
expect(result.provided).toEqual(['API_KEY', 'DATABASE_URL']);
|
|
444
|
+
expect(result.required).toEqual(['API_KEY', 'DATABASE_URL']);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('should return invalid when some variables are missing', () => {
|
|
448
|
+
const secrets: StageSecrets = {
|
|
449
|
+
...baseSecrets,
|
|
450
|
+
urls: {
|
|
451
|
+
DATABASE_URL: 'postgresql://...',
|
|
452
|
+
},
|
|
453
|
+
custom: {},
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const result = validateEnvironmentVariables(
|
|
457
|
+
['DATABASE_URL', 'API_KEY', 'JWT_SECRET'],
|
|
458
|
+
secrets,
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
expect(result.valid).toBe(false);
|
|
462
|
+
expect(result.missing).toEqual(['API_KEY', 'JWT_SECRET']);
|
|
463
|
+
expect(result.provided).toEqual(['DATABASE_URL']);
|
|
464
|
+
expect(result.required).toEqual(['API_KEY', 'DATABASE_URL', 'JWT_SECRET']);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('should return invalid when all variables are missing', () => {
|
|
468
|
+
const result = validateEnvironmentVariables(
|
|
469
|
+
['API_KEY', 'JWT_SECRET'],
|
|
470
|
+
baseSecrets,
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
expect(result.valid).toBe(false);
|
|
474
|
+
expect(result.missing).toEqual(['API_KEY', 'JWT_SECRET']);
|
|
475
|
+
expect(result.provided).toEqual([]);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should recognize service credentials as provided', () => {
|
|
479
|
+
const secrets: StageSecrets = {
|
|
480
|
+
...baseSecrets,
|
|
481
|
+
services: {
|
|
482
|
+
postgres: {
|
|
483
|
+
host: 'postgres',
|
|
484
|
+
port: 5432,
|
|
485
|
+
username: 'app',
|
|
486
|
+
password: 'secret',
|
|
487
|
+
database: 'app',
|
|
488
|
+
},
|
|
489
|
+
redis: {
|
|
490
|
+
host: 'redis',
|
|
491
|
+
port: 6379,
|
|
492
|
+
username: 'default',
|
|
493
|
+
password: 'redis-pass',
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
urls: {},
|
|
497
|
+
custom: {},
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
const result = validateEnvironmentVariables(
|
|
501
|
+
['POSTGRES_PASSWORD', 'REDIS_HOST', 'POSTGRES_DB'],
|
|
502
|
+
secrets,
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
expect(result.valid).toBe(true);
|
|
506
|
+
expect(result.missing).toEqual([]);
|
|
507
|
+
expect(result.provided).toEqual([
|
|
508
|
+
'POSTGRES_DB',
|
|
509
|
+
'POSTGRES_PASSWORD',
|
|
510
|
+
'REDIS_HOST',
|
|
511
|
+
]);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('should sort missing and provided arrays alphabetically', () => {
|
|
515
|
+
const secrets: StageSecrets = {
|
|
516
|
+
...baseSecrets,
|
|
517
|
+
custom: {
|
|
518
|
+
ZEBRA: 'value',
|
|
519
|
+
ALPHA: 'value',
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
const result = validateEnvironmentVariables(
|
|
524
|
+
['ZEBRA', 'ALPHA', 'YELLOW', 'BETA'],
|
|
525
|
+
secrets,
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
expect(result.missing).toEqual(['BETA', 'YELLOW']);
|
|
529
|
+
expect(result.provided).toEqual(['ALPHA', 'ZEBRA']);
|
|
530
|
+
expect(result.required).toEqual(['ALPHA', 'BETA', 'YELLOW', 'ZEBRA']);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it('should handle duplicate required variables', () => {
|
|
534
|
+
const secrets: StageSecrets = {
|
|
535
|
+
...baseSecrets,
|
|
536
|
+
custom: {
|
|
537
|
+
API_KEY: 'value',
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
const result = validateEnvironmentVariables(
|
|
542
|
+
['API_KEY', 'API_KEY', 'MISSING'],
|
|
543
|
+
secrets,
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
expect(result.valid).toBe(false);
|
|
547
|
+
expect(result.missing).toEqual(['MISSING']);
|
|
548
|
+
// Note: duplicates in input are preserved in required list
|
|
549
|
+
expect(result.required).toEqual(['API_KEY', 'API_KEY', 'MISSING']);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should work with complex service configurations', () => {
|
|
553
|
+
const secrets: StageSecrets = {
|
|
554
|
+
...baseSecrets,
|
|
555
|
+
services: {
|
|
556
|
+
postgres: {
|
|
557
|
+
host: 'postgres',
|
|
558
|
+
port: 5432,
|
|
559
|
+
username: 'app',
|
|
560
|
+
password: 'pg-secret',
|
|
561
|
+
database: 'mydb',
|
|
562
|
+
},
|
|
563
|
+
redis: {
|
|
564
|
+
host: 'redis',
|
|
565
|
+
port: 6379,
|
|
566
|
+
username: 'default',
|
|
567
|
+
password: 'redis-secret',
|
|
568
|
+
},
|
|
569
|
+
rabbitmq: {
|
|
570
|
+
host: 'rabbitmq',
|
|
571
|
+
port: 5672,
|
|
572
|
+
username: 'guest',
|
|
573
|
+
password: 'guest',
|
|
574
|
+
vhost: '/',
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
urls: {
|
|
578
|
+
DATABASE_URL: 'postgresql://...',
|
|
579
|
+
REDIS_URL: 'redis://...',
|
|
580
|
+
RABBITMQ_URL: 'amqp://...',
|
|
581
|
+
},
|
|
582
|
+
custom: {
|
|
583
|
+
JWT_SECRET: 'jwt-secret-value',
|
|
584
|
+
},
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
const result = validateEnvironmentVariables(
|
|
588
|
+
[
|
|
589
|
+
'DATABASE_URL',
|
|
590
|
+
'REDIS_URL',
|
|
591
|
+
'RABBITMQ_URL',
|
|
592
|
+
'JWT_SECRET',
|
|
593
|
+
'POSTGRES_PASSWORD',
|
|
594
|
+
'REDIS_PASSWORD',
|
|
595
|
+
'RABBITMQ_USER',
|
|
596
|
+
'MISSING_VAR',
|
|
597
|
+
],
|
|
598
|
+
secrets,
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
expect(result.valid).toBe(false);
|
|
602
|
+
expect(result.missing).toEqual(['MISSING_VAR']);
|
|
603
|
+
expect(result.provided).toContain('DATABASE_URL');
|
|
604
|
+
expect(result.provided).toContain('REDIS_URL');
|
|
605
|
+
expect(result.provided).toContain('RABBITMQ_URL');
|
|
606
|
+
expect(result.provided).toContain('JWT_SECRET');
|
|
607
|
+
expect(result.provided).toContain('POSTGRES_PASSWORD');
|
|
608
|
+
expect(result.provided).toContain('REDIS_PASSWORD');
|
|
609
|
+
expect(result.provided).toContain('RABBITMQ_USER');
|
|
610
|
+
});
|
|
611
|
+
});
|
package/src/secrets/storage.ts
CHANGED
|
@@ -27,6 +27,21 @@ export function secretsExist(stage: string, cwd = process.cwd()): boolean {
|
|
|
27
27
|
return existsSync(getSecretsPath(stage, cwd));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Initialize an empty StageSecrets object for a stage.
|
|
32
|
+
*/
|
|
33
|
+
export function initStageSecrets(stage: string): StageSecrets {
|
|
34
|
+
const now = new Date().toISOString();
|
|
35
|
+
return {
|
|
36
|
+
stage,
|
|
37
|
+
createdAt: now,
|
|
38
|
+
updatedAt: now,
|
|
39
|
+
services: {},
|
|
40
|
+
urls: {},
|
|
41
|
+
custom: {},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
/**
|
|
31
46
|
* Read secrets for a stage.
|
|
32
47
|
* @returns StageSecrets or null if not found
|
|
@@ -132,3 +147,61 @@ export function maskPassword(password: string): string {
|
|
|
132
147
|
}
|
|
133
148
|
return `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;
|
|
134
149
|
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Result of environment variable validation.
|
|
153
|
+
*/
|
|
154
|
+
export interface EnvValidationResult {
|
|
155
|
+
/** Whether all required environment variables are present */
|
|
156
|
+
valid: boolean;
|
|
157
|
+
/** List of missing environment variable names */
|
|
158
|
+
missing: string[];
|
|
159
|
+
/** List of environment variables that are provided */
|
|
160
|
+
provided: string[];
|
|
161
|
+
/** List of environment variables that were required */
|
|
162
|
+
required: string[];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Validate that all required environment variables are present in secrets.
|
|
167
|
+
*
|
|
168
|
+
* @param requiredVars - Array of environment variable names required by the application
|
|
169
|
+
* @param secrets - Stage secrets to validate against
|
|
170
|
+
* @returns Validation result with missing and provided variables
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
|
|
175
|
+
* const secrets = await readStageSecrets('production');
|
|
176
|
+
* const result = validateEnvironmentVariables(required, secrets);
|
|
177
|
+
*
|
|
178
|
+
* if (!result.valid) {
|
|
179
|
+
* console.error(`Missing environment variables: ${result.missing.join(', ')}`);
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export function validateEnvironmentVariables(
|
|
184
|
+
requiredVars: string[],
|
|
185
|
+
secrets: StageSecrets,
|
|
186
|
+
): EnvValidationResult {
|
|
187
|
+
const embeddable = toEmbeddableSecrets(secrets);
|
|
188
|
+
const availableVars = new Set(Object.keys(embeddable));
|
|
189
|
+
|
|
190
|
+
const missing: string[] = [];
|
|
191
|
+
const provided: string[] = [];
|
|
192
|
+
|
|
193
|
+
for (const varName of requiredVars) {
|
|
194
|
+
if (availableVars.has(varName)) {
|
|
195
|
+
provided.push(varName);
|
|
196
|
+
} else {
|
|
197
|
+
missing.push(varName);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
valid: missing.length === 0,
|
|
203
|
+
missing: missing.sort(),
|
|
204
|
+
provided: provided.sort(),
|
|
205
|
+
required: [...requiredVars].sort(),
|
|
206
|
+
};
|
|
207
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -181,6 +181,8 @@ export interface DokployProviderConfig {
|
|
|
181
181
|
applicationId: string;
|
|
182
182
|
/** Container registry (overrides docker.registry if set) */
|
|
183
183
|
registry?: string;
|
|
184
|
+
/** Registry ID in Dokploy (recommended for private registries) */
|
|
185
|
+
registryId?: string;
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
export interface ProvidersConfig {
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { mkdir, rename, writeFile } from "node:fs/promises";
|
|
4
|
-
import { execSync } from "node:child_process";
|
|
5
|
-
|
|
6
|
-
//#region src/build/bundler.ts
|
|
7
|
-
/**
|
|
8
|
-
* Bundle the server application using tsdown
|
|
9
|
-
*
|
|
10
|
-
* @param options - Bundle configuration options
|
|
11
|
-
* @returns Bundle result with output path and optional master key
|
|
12
|
-
*/
|
|
13
|
-
async function bundleServer(options) {
|
|
14
|
-
const { entryPoint, outputDir, minify, sourcemap, external, stage } = options;
|
|
15
|
-
await mkdir(outputDir, { recursive: true });
|
|
16
|
-
const args = [
|
|
17
|
-
"npx",
|
|
18
|
-
"tsdown",
|
|
19
|
-
entryPoint,
|
|
20
|
-
"--no-config",
|
|
21
|
-
"--out-dir",
|
|
22
|
-
outputDir,
|
|
23
|
-
"--format",
|
|
24
|
-
"esm",
|
|
25
|
-
"--platform",
|
|
26
|
-
"node",
|
|
27
|
-
"--target",
|
|
28
|
-
"node22",
|
|
29
|
-
"--clean"
|
|
30
|
-
];
|
|
31
|
-
if (minify) args.push("--minify");
|
|
32
|
-
if (sourcemap) args.push("--sourcemap");
|
|
33
|
-
for (const ext of external) args.push("--external", ext);
|
|
34
|
-
args.push("--external", "node:*");
|
|
35
|
-
let masterKey;
|
|
36
|
-
if (stage) {
|
|
37
|
-
const { readStageSecrets, toEmbeddableSecrets } = await import("./storage-DLJAYxzJ.mjs");
|
|
38
|
-
const { encryptSecrets, generateDefineOptions } = await import("./encryption-C8H-38Yy.mjs");
|
|
39
|
-
const secrets = await readStageSecrets(stage);
|
|
40
|
-
if (!secrets) throw new Error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
41
|
-
const embeddable = toEmbeddableSecrets(secrets);
|
|
42
|
-
const encrypted = encryptSecrets(embeddable);
|
|
43
|
-
masterKey = encrypted.masterKey;
|
|
44
|
-
const defines = generateDefineOptions(encrypted);
|
|
45
|
-
for (const [key, value] of Object.entries(defines)) args.push("--define", `${key}=${value}`);
|
|
46
|
-
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
47
|
-
}
|
|
48
|
-
const mjsOutput = join(outputDir, "server.mjs");
|
|
49
|
-
try {
|
|
50
|
-
execSync(args.join(" "), {
|
|
51
|
-
cwd: process.cwd(),
|
|
52
|
-
stdio: "inherit"
|
|
53
|
-
});
|
|
54
|
-
const jsOutput = join(outputDir, "server.js");
|
|
55
|
-
if (existsSync(jsOutput)) await rename(jsOutput, mjsOutput);
|
|
56
|
-
const { readFile: readFile$1 } = await import("node:fs/promises");
|
|
57
|
-
const content = await readFile$1(mjsOutput, "utf-8");
|
|
58
|
-
if (!content.startsWith("#!")) await writeFile(mjsOutput, `#!/usr/bin/env node\n${content}`);
|
|
59
|
-
} catch (error) {
|
|
60
|
-
throw new Error(`Failed to bundle server: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
outputPath: mjsOutput,
|
|
64
|
-
masterKey
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
//#endregion
|
|
69
|
-
export { bundleServer };
|
|
70
|
-
//# sourceMappingURL=bundler-DRXCw_YR.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundler-DRXCw_YR.mjs","names":["options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface BundleOptions {\n\t/** Entry point file (e.g., .gkm/server/server.ts) */\n\tentryPoint: string;\n\t/** Output directory for bundled files */\n\toutputDir: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * Bundle the server application using tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst { entryPoint, outputDir, minify, sourcemap, external, stage } = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build command-line arguments for tsdown\n\tconst args = [\n\t\t'npx',\n\t\t'tsdown',\n\t\tentryPoint,\n\t\t'--no-config', // Don't use any config file from workspace\n\t\t'--out-dir',\n\t\toutputDir,\n\t\t'--format',\n\t\t'esm',\n\t\t'--platform',\n\t\t'node',\n\t\t'--target',\n\t\t'node22',\n\t\t'--clean',\n\t];\n\n\tif (minify) {\n\t\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages\n\tfor (const ext of external) {\n\t\targs.push('--external', ext);\n\t}\n\n\t// Always exclude node: builtins\n\targs.push('--external', 'node:*');\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst { readStageSecrets, toEmbeddableSecrets } = await import(\n\t\t\t'../secrets/storage'\n\t\t);\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\tconst secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\tthrow new Error(\n\t\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t\t);\n\t\t}\n\n\t\t// Convert to embeddable format and encrypt\n\t\tconst embeddable = toEmbeddableSecrets(secrets);\n\t\tconst encrypted = encryptSecrets(embeddable);\n\t\tmasterKey = encrypted.masterKey;\n\n\t\t// Add define options for build-time injection\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push('--define', `${key}=${value}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\ttry {\n\t\t// Run tsdown with command-line arguments\n\t\texecSync(args.join(' '), {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t});\n\n\t\t// Rename output to .mjs for explicit ESM\n\t\t// tsdown outputs as server.js for ESM format\n\t\tconst jsOutput = join(outputDir, 'server.js');\n\n\t\tif (existsSync(jsOutput)) {\n\t\t\tawait rename(jsOutput, mjsOutput);\n\t\t}\n\n\t\t// Add shebang to the bundled file\n\t\tconst { readFile } = await import('node:fs/promises');\n\t\tconst content = await readFile(mjsOutput, 'utf-8');\n\t\tif (!content.startsWith('#!')) {\n\t\t\tawait writeFile(mjsOutput, `#!/usr/bin/env node\\n${content}`);\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to bundle server: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n\n\treturn {\n\t\toutputPath: mjsOutput,\n\t\tmasterKey,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;AAiCA,eAAsB,aACrBA,SACwB;CACxB,MAAM,EAAE,YAAY,WAAW,QAAQ,WAAW,UAAU,OAAO,GAAG;AAGtE,OAAM,MAAM,WAAW,EAAE,WAAW,KAAM,EAAC;CAG3C,MAAM,OAAO;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACA;AAED,KAAI,OACH,MAAK,KAAK,WAAW;AAGtB,KAAI,UACH,MAAK,KAAK,cAAc;AAIzB,MAAK,MAAM,OAAO,SACjB,MAAK,KAAK,cAAc,IAAI;AAI7B,MAAK,KAAK,cAAc,SAAS;CAGjC,IAAIC;AAEJ,KAAI,OAAO;EACV,MAAM,EAAE,kBAAkB,qBAAqB,GAAG,MAAM,OACvD;EAED,MAAM,EAAE,gBAAgB,uBAAuB,GAAG,MAAM,OACvD;EAGD,MAAM,UAAU,MAAM,iBAAiB,MAAM;AAE7C,OAAK,QACJ,OAAM,IAAI,OACR,8BAA8B,MAAM,mCAAmC,MAAM;EAKhF,MAAM,aAAa,oBAAoB,QAAQ;EAC/C,MAAM,YAAY,eAAe,WAAW;AAC5C,cAAY,UAAU;EAGtB,MAAM,UAAU,sBAAsB,UAAU;AAChD,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,CACjD,MAAK,KAAK,aAAa,EAAE,IAAI,GAAG,MAAM,EAAE;AAGzC,UAAQ,KAAK,iCAAiC,MAAM,GAAG;CACvD;CAED,MAAM,YAAY,KAAK,WAAW,aAAa;AAE/C,KAAI;AAEH,WAAS,KAAK,KAAK,IAAI,EAAE;GACxB,KAAK,QAAQ,KAAK;GAClB,OAAO;EACP,EAAC;EAIF,MAAM,WAAW,KAAK,WAAW,YAAY;AAE7C,MAAI,WAAW,SAAS,CACvB,OAAM,OAAO,UAAU,UAAU;EAIlC,MAAM,EAAE,sBAAU,GAAG,MAAM,OAAO;EAClC,MAAM,UAAU,MAAM,WAAS,WAAW,QAAQ;AAClD,OAAK,QAAQ,WAAW,KAAK,CAC5B,OAAM,UAAU,YAAY,uBAAuB,QAAQ,EAAE;CAE9D,SAAQ,OAAO;AACf,QAAM,IAAI,OACR,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,gBAAgB;CAEtF;AAED,QAAO;EACN,YAAY;EACZ;CACA;AACD"}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
-
const node_fs = require_chunk.__toESM(require("node:fs"));
|
|
3
|
-
const node_path = require_chunk.__toESM(require("node:path"));
|
|
4
|
-
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
|
|
5
|
-
const node_child_process = require_chunk.__toESM(require("node:child_process"));
|
|
6
|
-
|
|
7
|
-
//#region src/build/bundler.ts
|
|
8
|
-
/**
|
|
9
|
-
* Bundle the server application using tsdown
|
|
10
|
-
*
|
|
11
|
-
* @param options - Bundle configuration options
|
|
12
|
-
* @returns Bundle result with output path and optional master key
|
|
13
|
-
*/
|
|
14
|
-
async function bundleServer(options) {
|
|
15
|
-
const { entryPoint, outputDir, minify, sourcemap, external, stage } = options;
|
|
16
|
-
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
17
|
-
const args = [
|
|
18
|
-
"npx",
|
|
19
|
-
"tsdown",
|
|
20
|
-
entryPoint,
|
|
21
|
-
"--no-config",
|
|
22
|
-
"--out-dir",
|
|
23
|
-
outputDir,
|
|
24
|
-
"--format",
|
|
25
|
-
"esm",
|
|
26
|
-
"--platform",
|
|
27
|
-
"node",
|
|
28
|
-
"--target",
|
|
29
|
-
"node22",
|
|
30
|
-
"--clean"
|
|
31
|
-
];
|
|
32
|
-
if (minify) args.push("--minify");
|
|
33
|
-
if (sourcemap) args.push("--sourcemap");
|
|
34
|
-
for (const ext of external) args.push("--external", ext);
|
|
35
|
-
args.push("--external", "node:*");
|
|
36
|
-
let masterKey;
|
|
37
|
-
if (stage) {
|
|
38
|
-
const { readStageSecrets, toEmbeddableSecrets } = await Promise.resolve().then(() => require("./storage-BUYQJgz7.cjs"));
|
|
39
|
-
const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./encryption-Dyf_r1h-.cjs"));
|
|
40
|
-
const secrets = await readStageSecrets(stage);
|
|
41
|
-
if (!secrets) throw new Error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
42
|
-
const embeddable = toEmbeddableSecrets(secrets);
|
|
43
|
-
const encrypted = encryptSecrets(embeddable);
|
|
44
|
-
masterKey = encrypted.masterKey;
|
|
45
|
-
const defines = generateDefineOptions(encrypted);
|
|
46
|
-
for (const [key, value] of Object.entries(defines)) args.push("--define", `${key}=${value}`);
|
|
47
|
-
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
48
|
-
}
|
|
49
|
-
const mjsOutput = (0, node_path.join)(outputDir, "server.mjs");
|
|
50
|
-
try {
|
|
51
|
-
(0, node_child_process.execSync)(args.join(" "), {
|
|
52
|
-
cwd: process.cwd(),
|
|
53
|
-
stdio: "inherit"
|
|
54
|
-
});
|
|
55
|
-
const jsOutput = (0, node_path.join)(outputDir, "server.js");
|
|
56
|
-
if ((0, node_fs.existsSync)(jsOutput)) await (0, node_fs_promises.rename)(jsOutput, mjsOutput);
|
|
57
|
-
const { readFile } = await import("node:fs/promises");
|
|
58
|
-
const content = await readFile(mjsOutput, "utf-8");
|
|
59
|
-
if (!content.startsWith("#!")) await (0, node_fs_promises.writeFile)(mjsOutput, `#!/usr/bin/env node\n${content}`);
|
|
60
|
-
} catch (error) {
|
|
61
|
-
throw new Error(`Failed to bundle server: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
outputPath: mjsOutput,
|
|
65
|
-
masterKey
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
//#endregion
|
|
70
|
-
exports.bundleServer = bundleServer;
|
|
71
|
-
//# sourceMappingURL=bundler-WsEvH_b2.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundler-WsEvH_b2.cjs","names":["options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface BundleOptions {\n\t/** Entry point file (e.g., .gkm/server/server.ts) */\n\tentryPoint: string;\n\t/** Output directory for bundled files */\n\toutputDir: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * Bundle the server application using tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst { entryPoint, outputDir, minify, sourcemap, external, stage } = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build command-line arguments for tsdown\n\tconst args = [\n\t\t'npx',\n\t\t'tsdown',\n\t\tentryPoint,\n\t\t'--no-config', // Don't use any config file from workspace\n\t\t'--out-dir',\n\t\toutputDir,\n\t\t'--format',\n\t\t'esm',\n\t\t'--platform',\n\t\t'node',\n\t\t'--target',\n\t\t'node22',\n\t\t'--clean',\n\t];\n\n\tif (minify) {\n\t\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages\n\tfor (const ext of external) {\n\t\targs.push('--external', ext);\n\t}\n\n\t// Always exclude node: builtins\n\targs.push('--external', 'node:*');\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst { readStageSecrets, toEmbeddableSecrets } = await import(\n\t\t\t'../secrets/storage'\n\t\t);\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\tconst secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\tthrow new Error(\n\t\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t\t);\n\t\t}\n\n\t\t// Convert to embeddable format and encrypt\n\t\tconst embeddable = toEmbeddableSecrets(secrets);\n\t\tconst encrypted = encryptSecrets(embeddable);\n\t\tmasterKey = encrypted.masterKey;\n\n\t\t// Add define options for build-time injection\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push('--define', `${key}=${value}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\ttry {\n\t\t// Run tsdown with command-line arguments\n\t\texecSync(args.join(' '), {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t});\n\n\t\t// Rename output to .mjs for explicit ESM\n\t\t// tsdown outputs as server.js for ESM format\n\t\tconst jsOutput = join(outputDir, 'server.js');\n\n\t\tif (existsSync(jsOutput)) {\n\t\t\tawait rename(jsOutput, mjsOutput);\n\t\t}\n\n\t\t// Add shebang to the bundled file\n\t\tconst { readFile } = await import('node:fs/promises');\n\t\tconst content = await readFile(mjsOutput, 'utf-8');\n\t\tif (!content.startsWith('#!')) {\n\t\t\tawait writeFile(mjsOutput, `#!/usr/bin/env node\\n${content}`);\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to bundle server: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n\n\treturn {\n\t\toutputPath: mjsOutput,\n\t\tmasterKey,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;AAiCA,eAAsB,aACrBA,SACwB;CACxB,MAAM,EAAE,YAAY,WAAW,QAAQ,WAAW,UAAU,OAAO,GAAG;AAGtE,OAAM,4BAAM,WAAW,EAAE,WAAW,KAAM,EAAC;CAG3C,MAAM,OAAO;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACA;AAED,KAAI,OACH,MAAK,KAAK,WAAW;AAGtB,KAAI,UACH,MAAK,KAAK,cAAc;AAIzB,MAAK,MAAM,OAAO,SACjB,MAAK,KAAK,cAAc,IAAI;AAI7B,MAAK,KAAK,cAAc,SAAS;CAGjC,IAAIC;AAEJ,KAAI,OAAO;EACV,MAAM,EAAE,kBAAkB,qBAAqB,GAAG,2CAAM;EAGxD,MAAM,EAAE,gBAAgB,uBAAuB,GAAG,2CAAM;EAIxD,MAAM,UAAU,MAAM,iBAAiB,MAAM;AAE7C,OAAK,QACJ,OAAM,IAAI,OACR,8BAA8B,MAAM,mCAAmC,MAAM;EAKhF,MAAM,aAAa,oBAAoB,QAAQ;EAC/C,MAAM,YAAY,eAAe,WAAW;AAC5C,cAAY,UAAU;EAGtB,MAAM,UAAU,sBAAsB,UAAU;AAChD,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,CACjD,MAAK,KAAK,aAAa,EAAE,IAAI,GAAG,MAAM,EAAE;AAGzC,UAAQ,KAAK,iCAAiC,MAAM,GAAG;CACvD;CAED,MAAM,YAAY,oBAAK,WAAW,aAAa;AAE/C,KAAI;AAEH,mCAAS,KAAK,KAAK,IAAI,EAAE;GACxB,KAAK,QAAQ,KAAK;GAClB,OAAO;EACP,EAAC;EAIF,MAAM,WAAW,oBAAK,WAAW,YAAY;AAE7C,MAAI,wBAAW,SAAS,CACvB,OAAM,6BAAO,UAAU,UAAU;EAIlC,MAAM,EAAE,UAAU,GAAG,MAAM,OAAO;EAClC,MAAM,UAAU,MAAM,SAAS,WAAW,QAAQ;AAClD,OAAK,QAAQ,WAAW,KAAK,CAC5B,OAAM,gCAAU,YAAY,uBAAuB,QAAQ,EAAE;CAE9D,SAAQ,OAAO;AACf,QAAM,IAAI,OACR,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,gBAAgB;CAEtF;AAED,QAAO;EACN,YAAY;EACZ;CACA;AACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage-BXoJvmv2.cjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: string"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Read secrets for a stage.\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\treturn JSON.parse(content) as StageSecrets;\n}\n\n/**\n * Write secrets for a stage.\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Write with pretty formatting\n\tawait writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc;;;;AAKpB,SAAgB,cAAc,MAAM,QAAQ,KAAK,EAAU;AAC1D,QAAO,oBAAK,KAAK,YAAY;AAC7B;;;;AAKD,SAAgB,eAAeA,OAAe,MAAM,QAAQ,KAAK,EAAU;AAC1E,QAAO,oBAAK,cAAc,IAAI,GAAG,EAAE,MAAM,OAAO;AAChD;;;;AAKD,SAAgB,aAAaA,OAAe,MAAM,QAAQ,KAAK,EAAW;AACzE,QAAO,wBAAW,eAAe,OAAO,IAAI,CAAC;AAC7C;;;;;AAMD,eAAsB,iBACrBA,OACA,MAAM,QAAQ,KAAK,EACY;CAC/B,MAAM,OAAO,eAAe,OAAO,IAAI;AAEvC,MAAK,wBAAW,KAAK,CACpB,QAAO;CAGR,MAAM,UAAU,MAAM,+BAAS,MAAM,QAAQ;AAC7C,QAAO,KAAK,MAAM,QAAQ;AAC1B;;;;AAKD,eAAsB,kBACrBC,SACA,MAAM,QAAQ,KAAK,EACH;CAChB,MAAM,MAAM,cAAc,IAAI;CAC9B,MAAM,OAAO,eAAe,QAAQ,OAAO,IAAI;AAG/C,OAAM,4BAAM,KAAK,EAAE,WAAW,KAAM,EAAC;AAGrC,OAAM,gCAAU,MAAM,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE;;;;;AAMD,SAAgB,oBAAoBA,SAA0C;AAC7E,QAAO;EACN,GAAG,QAAQ;EACX,GAAG,QAAQ;EAEX,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,aAAa,QAAQ,SAAS,SAAS,YAAY;GACnD,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;EACrD;EACD,GAAI,QAAQ,SAAS,SAAS;GAC7B,gBAAgB,QAAQ,SAAS,MAAM;GACvC,YAAY,QAAQ,SAAS,MAAM;GACnC,YAAY,OAAO,QAAQ,SAAS,MAAM,KAAK;EAC/C;EACD,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;GACrD,gBAAgB,QAAQ,SAAS,SAAS,SAAS;EACnD;CACD;AACD;;;;AAKD,eAAsB,gBACrBD,OACAE,KACAC,OACA,MAAM,QAAQ,KAAK,EACK;CACxB,MAAM,UAAU,MAAM,iBAAiB,OAAO,IAAI;AAElD,MAAK,QACJ,OAAM,IAAI,OACR,+BAA+B,MAAM,mCAAmC,MAAM;CAIjF,MAAMC,UAAwB;EAC7B,GAAG;EACH,WAAW,qBAAI,QAAO,aAAa;EACnC,QAAQ;GACP,GAAG,QAAQ;IACV,MAAM;EACP;CACD;AAED,OAAM,kBAAkB,SAAS,IAAI;AACrC,QAAO;AACP;;;;AAKD,SAAgB,aAAaC,UAA0B;AACtD,KAAI,SAAS,UAAU,EACtB,QAAO;AAER,SAAQ,EAAE,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE,SAAS,MAAM,GAAG,CAAC;AACtF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage-C9PU_30f.mjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: string"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Read secrets for a stage.\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\treturn JSON.parse(content) as StageSecrets;\n}\n\n/**\n * Write secrets for a stage.\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Write with pretty formatting\n\tawait writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n"],"mappings":";;;;;;AAMA,MAAM,cAAc;;;;AAKpB,SAAgB,cAAc,MAAM,QAAQ,KAAK,EAAU;AAC1D,QAAO,KAAK,KAAK,YAAY;AAC7B;;;;AAKD,SAAgB,eAAeA,OAAe,MAAM,QAAQ,KAAK,EAAU;AAC1E,QAAO,KAAK,cAAc,IAAI,GAAG,EAAE,MAAM,OAAO;AAChD;;;;AAKD,SAAgB,aAAaA,OAAe,MAAM,QAAQ,KAAK,EAAW;AACzE,QAAO,WAAW,eAAe,OAAO,IAAI,CAAC;AAC7C;;;;;AAMD,eAAsB,iBACrBA,OACA,MAAM,QAAQ,KAAK,EACY;CAC/B,MAAM,OAAO,eAAe,OAAO,IAAI;AAEvC,MAAK,WAAW,KAAK,CACpB,QAAO;CAGR,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;AAC7C,QAAO,KAAK,MAAM,QAAQ;AAC1B;;;;AAKD,eAAsB,kBACrBC,SACA,MAAM,QAAQ,KAAK,EACH;CAChB,MAAM,MAAM,cAAc,IAAI;CAC9B,MAAM,OAAO,eAAe,QAAQ,OAAO,IAAI;AAG/C,OAAM,MAAM,KAAK,EAAE,WAAW,KAAM,EAAC;AAGrC,OAAM,UAAU,MAAM,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE;;;;;AAMD,SAAgB,oBAAoBA,SAA0C;AAC7E,QAAO;EACN,GAAG,QAAQ;EACX,GAAG,QAAQ;EAEX,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,aAAa,QAAQ,SAAS,SAAS,YAAY;GACnD,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;EACrD;EACD,GAAI,QAAQ,SAAS,SAAS;GAC7B,gBAAgB,QAAQ,SAAS,MAAM;GACvC,YAAY,QAAQ,SAAS,MAAM;GACnC,YAAY,OAAO,QAAQ,SAAS,MAAM,KAAK;EAC/C;EACD,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;GACrD,gBAAgB,QAAQ,SAAS,SAAS,SAAS;EACnD;CACD;AACD;;;;AAKD,eAAsB,gBACrBD,OACAE,KACAC,OACA,MAAM,QAAQ,KAAK,EACK;CACxB,MAAM,UAAU,MAAM,iBAAiB,OAAO,IAAI;AAElD,MAAK,QACJ,OAAM,IAAI,OACR,+BAA+B,MAAM,mCAAmC,MAAM;CAIjF,MAAMC,UAAwB;EAC7B,GAAG;EACH,WAAW,qBAAI,QAAO,aAAa;EACnC,QAAQ;GACP,GAAG,QAAQ;IACV,MAAM;EACP;CACD;AAED,OAAM,kBAAkB,SAAS,IAAI;AACrC,QAAO;AACP;;;;AAKD,SAAgB,aAAaC,UAA0B;AACtD,KAAI,SAAS,UAAU,EACtB,QAAO;AAER,SAAQ,EAAE,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE,SAAS,MAAM,GAAG,CAAC;AACtF"}
|