@karmaniverous/get-dotenv 6.1.0 → 6.1.1
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/README.md +18 -14
- package/dist/cli.mjs +645 -350
- package/dist/getdotenv.cli.mjs +645 -350
- package/dist/index.mjs +645 -350
- package/dist/plugins-aws.d.ts +4 -3
- package/dist/plugins-aws.mjs +319 -170
- package/dist/plugins-batch.d.ts +2 -1
- package/dist/plugins-batch.mjs +76 -41
- package/dist/plugins-cmd.d.ts +2 -1
- package/dist/plugins-cmd.mjs +29 -15
- package/dist/plugins-init.d.ts +2 -1
- package/dist/plugins-init.mjs +158 -118
- package/dist/plugins.d.ts +7 -2
- package/dist/plugins.mjs +645 -350
- package/dist/templates/cli/plugins/hello/defaultAction.ts +27 -0
- package/dist/templates/cli/plugins/hello/index.ts +26 -0
- package/dist/templates/cli/plugins/hello/options.ts +31 -0
- package/dist/templates/cli/plugins/hello/strangerAction.ts +20 -0
- package/dist/templates/cli/plugins/hello/types.ts +13 -0
- package/dist/templates/defaultAction.ts +27 -0
- package/dist/templates/hello/defaultAction.ts +27 -0
- package/dist/templates/hello/index.ts +26 -0
- package/dist/templates/hello/options.ts +31 -0
- package/dist/templates/hello/strangerAction.ts +20 -0
- package/dist/templates/hello/types.ts +13 -0
- package/dist/templates/index.ts +23 -22
- package/dist/templates/options.ts +31 -0
- package/dist/templates/plugins/hello/defaultAction.ts +27 -0
- package/dist/templates/plugins/hello/index.ts +26 -0
- package/dist/templates/plugins/hello/options.ts +31 -0
- package/dist/templates/plugins/hello/strangerAction.ts +20 -0
- package/dist/templates/plugins/hello/types.ts +13 -0
- package/dist/templates/strangerAction.ts +20 -0
- package/dist/templates/types.ts +13 -0
- package/package.json +2 -2
- package/templates/cli/plugins/hello/defaultAction.ts +27 -0
- package/templates/cli/plugins/hello/index.ts +26 -0
- package/templates/cli/plugins/hello/options.ts +31 -0
- package/templates/cli/plugins/hello/strangerAction.ts +20 -0
- package/templates/cli/plugins/hello/types.ts +13 -0
- package/dist/templates/cli/plugins/hello.ts +0 -42
- package/dist/templates/hello.ts +0 -42
- package/dist/templates/plugins/hello.ts +0 -42
- package/templates/cli/plugins/hello.ts +0 -42
package/dist/plugins-aws.d.ts
CHANGED
|
@@ -292,7 +292,7 @@ interface PluginWithInstanceHelpers<TOptions extends GetDotenvOptions = GetDoten
|
|
|
292
292
|
/**
|
|
293
293
|
* Zod schema for AWS plugin configuration.
|
|
294
294
|
*/
|
|
295
|
-
declare const
|
|
295
|
+
declare const awsPluginConfigSchema: z.ZodObject<{
|
|
296
296
|
profile: z.ZodOptional<z.ZodString>;
|
|
297
297
|
region: z.ZodOptional<z.ZodString>;
|
|
298
298
|
defaultRegion: z.ZodOptional<z.ZodString>;
|
|
@@ -308,7 +308,7 @@ declare const AwsPluginConfigSchema: z.ZodObject<{
|
|
|
308
308
|
/**
|
|
309
309
|
* AWS plugin configuration object.
|
|
310
310
|
*/
|
|
311
|
-
type AwsPluginConfig = z.infer<typeof
|
|
311
|
+
type AwsPluginConfig = z.infer<typeof awsPluginConfigSchema>;
|
|
312
312
|
/**
|
|
313
313
|
* Arguments for resolving AWS context (profile/region/credentials).
|
|
314
314
|
*
|
|
@@ -338,6 +338,7 @@ declare const awsPlugin: () => PluginWithInstanceHelpers<GetDotenvOptions, {
|
|
|
338
338
|
strategy?: "cli-export" | "none" | undefined;
|
|
339
339
|
loginOnDemand?: boolean | undefined;
|
|
340
340
|
}, [], {}, {}>;
|
|
341
|
+
type AwsPlugin = ReturnType<typeof awsPlugin>;
|
|
341
342
|
|
|
342
343
|
export { awsPlugin };
|
|
343
|
-
export type { ResolveAwsContextOptions };
|
|
344
|
+
export type { AwsPlugin, ResolveAwsContextOptions };
|
package/dist/plugins-aws.mjs
CHANGED
|
@@ -2436,18 +2436,49 @@ const buildSpawnEnv = (base, overlay) => {
|
|
|
2436
2436
|
function applyAwsContext(out, ctx, setProcessEnv = true) {
|
|
2437
2437
|
const { profile, region, credentials } = out;
|
|
2438
2438
|
if (setProcessEnv) {
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2439
|
+
// Ensure AWS credential sources are mutually exclusive.
|
|
2440
|
+
// The AWS SDK warns (and may change precedence in future) when both
|
|
2441
|
+
// AWS_PROFILE and AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY are set.
|
|
2442
|
+
const clear = (keys) => {
|
|
2443
|
+
for (const k of keys) {
|
|
2444
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
2445
|
+
delete process.env[k];
|
|
2443
2446
|
}
|
|
2444
|
-
}
|
|
2447
|
+
};
|
|
2448
|
+
const clearProfileVars = () => {
|
|
2449
|
+
clear(['AWS_PROFILE', 'AWS_DEFAULT_PROFILE', 'AWS_SDK_LOAD_CONFIG']);
|
|
2450
|
+
};
|
|
2451
|
+
const clearStaticCreds = () => {
|
|
2452
|
+
clear([
|
|
2453
|
+
'AWS_ACCESS_KEY_ID',
|
|
2454
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
2455
|
+
'AWS_SESSION_TOKEN',
|
|
2456
|
+
]);
|
|
2457
|
+
};
|
|
2458
|
+
// Mode A: exported/static credentials (clear profile vars)
|
|
2445
2459
|
if (credentials) {
|
|
2460
|
+
clearProfileVars();
|
|
2446
2461
|
process.env.AWS_ACCESS_KEY_ID = credentials.accessKeyId;
|
|
2447
2462
|
process.env.AWS_SECRET_ACCESS_KEY = credentials.secretAccessKey;
|
|
2448
2463
|
if (credentials.sessionToken !== undefined) {
|
|
2449
2464
|
process.env.AWS_SESSION_TOKEN = credentials.sessionToken;
|
|
2450
2465
|
}
|
|
2466
|
+
else {
|
|
2467
|
+
delete process.env.AWS_SESSION_TOKEN;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
else if (profile) {
|
|
2471
|
+
// Mode B: profile-based (SSO) credentials (clear static creds)
|
|
2472
|
+
clearStaticCreds();
|
|
2473
|
+
process.env.AWS_PROFILE = profile;
|
|
2474
|
+
process.env.AWS_DEFAULT_PROFILE = profile;
|
|
2475
|
+
process.env.AWS_SDK_LOAD_CONFIG = '1';
|
|
2476
|
+
}
|
|
2477
|
+
if (region) {
|
|
2478
|
+
process.env.AWS_REGION = region;
|
|
2479
|
+
if (!process.env.AWS_DEFAULT_REGION) {
|
|
2480
|
+
process.env.AWS_DEFAULT_REGION = region;
|
|
2481
|
+
}
|
|
2451
2482
|
}
|
|
2452
2483
|
}
|
|
2453
2484
|
// Always publish minimal, non-sensitive metadata
|
|
@@ -2458,7 +2489,7 @@ function applyAwsContext(out, ctx, setProcessEnv = true) {
|
|
|
2458
2489
|
};
|
|
2459
2490
|
}
|
|
2460
2491
|
|
|
2461
|
-
const
|
|
2492
|
+
const AWS_CLI_TIMEOUT_MS = 15_000;
|
|
2462
2493
|
const trim = (s) => (typeof s === 'string' ? s.trim() : '');
|
|
2463
2494
|
const unquote = (s) => s.length >= 2 &&
|
|
2464
2495
|
((s.startsWith('"') && s.endsWith('"')) ||
|
|
@@ -2493,6 +2524,7 @@ const parseExportCredentialsJson = (txt) => {
|
|
|
2493
2524
|
/**
|
|
2494
2525
|
* Parse AWS credentials from environment-export output (shell-agnostic).
|
|
2495
2526
|
* Supports POSIX `export KEY=VAL` and PowerShell `$Env:KEY=VAL`.
|
|
2527
|
+
* Also supports AWS CLI `windows-cmd` (`set KEY=VAL`) and `env-no-export` (`KEY=VAL`).
|
|
2496
2528
|
*
|
|
2497
2529
|
* @param txt - Raw stdout text from the AWS CLI.
|
|
2498
2530
|
* @returns Parsed credentials, or `undefined` when the input is not recognized.
|
|
@@ -2506,12 +2538,17 @@ const parseExportCredentialsEnv = (txt) => {
|
|
|
2506
2538
|
const line = raw.trim();
|
|
2507
2539
|
if (!line)
|
|
2508
2540
|
continue;
|
|
2509
|
-
// POSIX: export AWS_ACCESS_KEY_ID=...,
|
|
2541
|
+
// POSIX: export AWS_ACCESS_KEY_ID=..., ...
|
|
2510
2542
|
let m = /^export\s+([A-Z0-9_]+)\s*=\s*(.+)$/.exec(line);
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
m = /^\$Env:([A-Z0-9_]+)\s*=\s*(.+)
|
|
2514
|
-
|
|
2543
|
+
// PowerShell: $Env:AWS_ACCESS_KEY_ID="...", etc.
|
|
2544
|
+
if (!m)
|
|
2545
|
+
m = /^\$Env:([A-Z0-9_]+)\s*=\s*(.+)$/i.exec(line);
|
|
2546
|
+
// Windows cmd: set AWS_ACCESS_KEY_ID=..., etc.
|
|
2547
|
+
if (!m)
|
|
2548
|
+
m = /^(?:set)\s+([A-Z0-9_]+)\s*=\s*(.+)$/i.exec(line);
|
|
2549
|
+
// env-no-export: AWS_ACCESS_KEY_ID=..., etc.
|
|
2550
|
+
if (!m)
|
|
2551
|
+
m = /^([A-Z0-9_]+)\s*=\s*(.+)$/.exec(line);
|
|
2515
2552
|
if (!m)
|
|
2516
2553
|
continue;
|
|
2517
2554
|
const k = m[1];
|
|
@@ -2536,7 +2573,7 @@ const parseExportCredentialsEnv = (txt) => {
|
|
|
2536
2573
|
};
|
|
2537
2574
|
return undefined;
|
|
2538
2575
|
};
|
|
2539
|
-
const getAwsConfigure = async (key, profile, timeoutMs =
|
|
2576
|
+
const getAwsConfigure = async (key, profile, timeoutMs = AWS_CLI_TIMEOUT_MS) => {
|
|
2540
2577
|
const r = await runCommandResult(['aws', 'configure', 'get', key, '--profile', profile], false, {
|
|
2541
2578
|
env: process.env,
|
|
2542
2579
|
timeoutMs,
|
|
@@ -2551,30 +2588,43 @@ const getAwsConfigure = async (key, profile, timeoutMs = DEFAULT_TIMEOUT_MS) =>
|
|
|
2551
2588
|
}
|
|
2552
2589
|
return undefined;
|
|
2553
2590
|
};
|
|
2554
|
-
const exportCredentials = async (profile, timeoutMs =
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2591
|
+
const exportCredentials = async (profile, timeoutMs = AWS_CLI_TIMEOUT_MS) => {
|
|
2592
|
+
const tryExport = async (format) => {
|
|
2593
|
+
const argv = [
|
|
2594
|
+
'aws',
|
|
2595
|
+
'configure',
|
|
2596
|
+
'export-credentials',
|
|
2597
|
+
'--profile',
|
|
2598
|
+
profile,
|
|
2599
|
+
...(format ? ['--format', format] : []),
|
|
2600
|
+
];
|
|
2601
|
+
const r = await runCommandResult(argv, false, {
|
|
2602
|
+
env: process.env,
|
|
2603
|
+
timeoutMs,
|
|
2604
|
+
});
|
|
2605
|
+
if (r.exitCode !== 0)
|
|
2606
|
+
return undefined;
|
|
2607
|
+
const out = trim(r.stdout);
|
|
2608
|
+
if (!out)
|
|
2609
|
+
return undefined;
|
|
2610
|
+
// Some formats produce JSON ("process"), some produce shell-ish env lines.
|
|
2611
|
+
return parseExportCredentialsJson(out) ?? parseExportCredentialsEnv(out);
|
|
2612
|
+
};
|
|
2613
|
+
// Prefer the default/JSON "process" format first; then fall back to shell env outputs.
|
|
2614
|
+
// Note: AWS CLI v2 supports: process | env | env-no-export | powershell | windows-cmd
|
|
2615
|
+
const formats = [
|
|
2616
|
+
'process',
|
|
2617
|
+
...(process.platform === 'win32'
|
|
2618
|
+
? ['powershell', 'windows-cmd', 'env', 'env-no-export']
|
|
2619
|
+
: ['env', 'env-no-export']),
|
|
2620
|
+
];
|
|
2621
|
+
for (const f of formats) {
|
|
2622
|
+
const creds = await tryExport(f);
|
|
2574
2623
|
if (creds)
|
|
2575
2624
|
return creds;
|
|
2576
2625
|
}
|
|
2577
|
-
|
|
2626
|
+
// Final fallback: no --format (AWS CLI default output)
|
|
2627
|
+
return tryExport(undefined);
|
|
2578
2628
|
};
|
|
2579
2629
|
/**
|
|
2580
2630
|
* Resolve AWS context (profile, region, credentials) using configuration and environment.
|
|
@@ -2606,31 +2656,27 @@ const resolveAwsContext = async ({ dotenv, cfg, }) => {
|
|
|
2606
2656
|
out.region = region;
|
|
2607
2657
|
return out;
|
|
2608
2658
|
}
|
|
2609
|
-
// Env-first credentials.
|
|
2610
2659
|
let credentials;
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
const envToken = trim(process.env.AWS_SESSION_TOKEN);
|
|
2614
|
-
if (envId && envSecret) {
|
|
2615
|
-
credentials = {
|
|
2616
|
-
accessKeyId: envId,
|
|
2617
|
-
secretAccessKey: envSecret,
|
|
2618
|
-
...(envToken ? { sessionToken: envToken } : {}),
|
|
2619
|
-
};
|
|
2620
|
-
}
|
|
2621
|
-
else if (profile) {
|
|
2660
|
+
// Profile wins over ambient env creds when present (from flags/config/dotenv).
|
|
2661
|
+
if (profile) {
|
|
2622
2662
|
// Try export-credentials
|
|
2623
2663
|
credentials = await exportCredentials(profile);
|
|
2624
2664
|
// On failure, detect SSO and optionally login then retry
|
|
2625
2665
|
if (!credentials) {
|
|
2626
2666
|
const ssoSession = await getAwsConfigure('sso_session', profile);
|
|
2627
|
-
|
|
2667
|
+
// Legacy SSO profiles use sso_start_url/sso_region rather than sso_session.
|
|
2668
|
+
const ssoStartUrl = await getAwsConfigure('sso_start_url', profile);
|
|
2669
|
+
const looksSSO = (typeof ssoSession === 'string' && ssoSession.length > 0) ||
|
|
2670
|
+
(typeof ssoStartUrl === 'string' && ssoStartUrl.length > 0);
|
|
2628
2671
|
if (looksSSO && cfg.loginOnDemand) {
|
|
2629
|
-
//
|
|
2630
|
-
await
|
|
2672
|
+
// Interactive login (no timeout by default), then retry export once.
|
|
2673
|
+
const exit = await runCommand(['aws', 'sso', 'login', '--profile', profile], false, {
|
|
2631
2674
|
env: process.env,
|
|
2632
|
-
|
|
2675
|
+
stdio: 'inherit',
|
|
2633
2676
|
});
|
|
2677
|
+
if (exit !== 0) {
|
|
2678
|
+
throw new Error(`aws sso login failed for profile '${profile}' (exit ${String(exit)})`);
|
|
2679
|
+
}
|
|
2634
2680
|
credentials = await exportCredentials(profile);
|
|
2635
2681
|
}
|
|
2636
2682
|
}
|
|
@@ -2648,6 +2694,19 @@ const resolveAwsContext = async ({ dotenv, cfg, }) => {
|
|
|
2648
2694
|
}
|
|
2649
2695
|
}
|
|
2650
2696
|
}
|
|
2697
|
+
else {
|
|
2698
|
+
// Env-first credentials when no profile is present.
|
|
2699
|
+
const envId = trim(process.env.AWS_ACCESS_KEY_ID);
|
|
2700
|
+
const envSecret = trim(process.env.AWS_SECRET_ACCESS_KEY);
|
|
2701
|
+
const envToken = trim(process.env.AWS_SESSION_TOKEN);
|
|
2702
|
+
if (envId && envSecret) {
|
|
2703
|
+
credentials = {
|
|
2704
|
+
accessKeyId: envId,
|
|
2705
|
+
secretAccessKey: envSecret,
|
|
2706
|
+
...(envToken ? { sessionToken: envToken } : {}),
|
|
2707
|
+
};
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2651
2710
|
// Final region resolution
|
|
2652
2711
|
if (!region && profile)
|
|
2653
2712
|
region = await getAwsConfigure('region', profile);
|
|
@@ -2663,10 +2722,213 @@ const resolveAwsContext = async ({ dotenv, cfg, }) => {
|
|
|
2663
2722
|
return out;
|
|
2664
2723
|
};
|
|
2665
2724
|
|
|
2725
|
+
/**
|
|
2726
|
+
* Create the AWS plugin `afterResolve` hook.
|
|
2727
|
+
*
|
|
2728
|
+
* This runs once per invocation after the host resolves dotenv context.
|
|
2729
|
+
*
|
|
2730
|
+
* @param plugin - The AWS plugin instance.
|
|
2731
|
+
* @returns An `afterResolve` hook function suitable for assigning to `plugin.afterResolve`.
|
|
2732
|
+
*
|
|
2733
|
+
* @internal
|
|
2734
|
+
*/
|
|
2735
|
+
function attachAwsAfterResolveHook(plugin) {
|
|
2736
|
+
return async (cli, ctx) => {
|
|
2737
|
+
const cfg = plugin.readConfig(cli);
|
|
2738
|
+
const out = await resolveAwsContext({
|
|
2739
|
+
dotenv: ctx.dotenv,
|
|
2740
|
+
cfg,
|
|
2741
|
+
});
|
|
2742
|
+
applyAwsContext(out, ctx, true);
|
|
2743
|
+
// Optional: low-noise breadcrumb for diagnostics
|
|
2744
|
+
if (process.env.GETDOTENV_DEBUG) {
|
|
2745
|
+
try {
|
|
2746
|
+
const msg = JSON.stringify({
|
|
2747
|
+
profile: out.profile,
|
|
2748
|
+
region: out.region,
|
|
2749
|
+
hasCreds: Boolean(out.credentials),
|
|
2750
|
+
});
|
|
2751
|
+
process.stderr.write(`[aws] afterResolve ${msg}\n`);
|
|
2752
|
+
}
|
|
2753
|
+
catch {
|
|
2754
|
+
/* ignore */
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
/** @internal */
|
|
2761
|
+
const isRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
2762
|
+
/**
|
|
2763
|
+
* Create an AWS plugin config overlay from Commander-parsed option values.
|
|
2764
|
+
*
|
|
2765
|
+
* This preserves tri-state intent:
|
|
2766
|
+
* - If a flag was not provided, it should not overwrite config-derived defaults.
|
|
2767
|
+
* - If `--no-…` was provided, it must explicitly force the boolean false.
|
|
2768
|
+
*
|
|
2769
|
+
* @param opts - Commander option values for the current invocation.
|
|
2770
|
+
* @returns A partial AWS plugin config object containing only explicit overrides.
|
|
2771
|
+
*
|
|
2772
|
+
* @internal
|
|
2773
|
+
*/
|
|
2774
|
+
function awsConfigOverridesFromCommandOpts(opts) {
|
|
2775
|
+
const o = isRecord(opts) ? opts : {};
|
|
2776
|
+
const overlay = {};
|
|
2777
|
+
// Map boolean toggles (respect explicit --no-*)
|
|
2778
|
+
if (Object.prototype.hasOwnProperty.call(o, 'loginOnDemand')) {
|
|
2779
|
+
overlay.loginOnDemand = Boolean(o.loginOnDemand);
|
|
2780
|
+
}
|
|
2781
|
+
// Strings/enums
|
|
2782
|
+
if (typeof o.profile === 'string')
|
|
2783
|
+
overlay.profile = o.profile;
|
|
2784
|
+
if (typeof o.region === 'string')
|
|
2785
|
+
overlay.region = o.region;
|
|
2786
|
+
if (typeof o.defaultRegion === 'string')
|
|
2787
|
+
overlay.defaultRegion = o.defaultRegion;
|
|
2788
|
+
if (o.strategy === 'cli-export' || o.strategy === 'none') {
|
|
2789
|
+
overlay.strategy = o.strategy;
|
|
2790
|
+
}
|
|
2791
|
+
// Advanced key overrides
|
|
2792
|
+
if (typeof o.profileKey === 'string')
|
|
2793
|
+
overlay.profileKey = o.profileKey;
|
|
2794
|
+
if (typeof o.profileFallbackKey === 'string') {
|
|
2795
|
+
overlay.profileFallbackKey = o.profileFallbackKey;
|
|
2796
|
+
}
|
|
2797
|
+
if (typeof o.regionKey === 'string')
|
|
2798
|
+
overlay.regionKey = o.regionKey;
|
|
2799
|
+
return overlay;
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
/**
|
|
2803
|
+
* Attach the default action for the AWS plugin mount.
|
|
2804
|
+
*
|
|
2805
|
+
* Behavior:
|
|
2806
|
+
* - With args: forwards to AWS CLI (`aws <args...>`) under the established session.
|
|
2807
|
+
* - Without args: session-only establishment (no forward).
|
|
2808
|
+
*
|
|
2809
|
+
* @param cli - The `aws` command mount.
|
|
2810
|
+
* @param plugin - The AWS plugin instance.
|
|
2811
|
+
*
|
|
2812
|
+
* @internal
|
|
2813
|
+
*/
|
|
2814
|
+
function attachAwsDefaultAction(cli, plugin, awsCmd) {
|
|
2815
|
+
awsCmd.action(async (args, opts, thisCommand) => {
|
|
2816
|
+
// Access merged root CLI options (installed by root hooks).
|
|
2817
|
+
const bag = readMergedOptions(thisCommand);
|
|
2818
|
+
const capture = shouldCapture(bag.capture);
|
|
2819
|
+
const underTests = process.env.GETDOTENV_TEST === '1' ||
|
|
2820
|
+
typeof process.env.VITEST_WORKER_ID === 'string';
|
|
2821
|
+
// Build overlay cfg from subcommand flags layered over discovered config.
|
|
2822
|
+
const ctx = cli.getCtx();
|
|
2823
|
+
const cfgBase = plugin.readConfig(cli);
|
|
2824
|
+
const cfg = {
|
|
2825
|
+
...cfgBase,
|
|
2826
|
+
...awsConfigOverridesFromCommandOpts(opts),
|
|
2827
|
+
};
|
|
2828
|
+
// Resolve current context with overrides
|
|
2829
|
+
const out = await resolveAwsContext({
|
|
2830
|
+
dotenv: ctx.dotenv,
|
|
2831
|
+
cfg,
|
|
2832
|
+
});
|
|
2833
|
+
// Publish env/context
|
|
2834
|
+
applyAwsContext(out, ctx, true);
|
|
2835
|
+
// Forward when positional args are present; otherwise session-only.
|
|
2836
|
+
if (args.length > 0) {
|
|
2837
|
+
const argv = ['aws', ...args];
|
|
2838
|
+
const shellSetting = resolveShell(bag.scripts, 'aws', bag.shell);
|
|
2839
|
+
const exit = await runCommand(argv, shellSetting, {
|
|
2840
|
+
env: buildSpawnEnv(process.env, ctx.dotenv),
|
|
2841
|
+
stdio: capture ? 'pipe' : 'inherit',
|
|
2842
|
+
});
|
|
2843
|
+
// Deterministic termination (suppressed under tests)
|
|
2844
|
+
if (!underTests) {
|
|
2845
|
+
process.exit(typeof exit === 'number' ? exit : 0);
|
|
2846
|
+
}
|
|
2847
|
+
return;
|
|
2848
|
+
}
|
|
2849
|
+
// Session only: low-noise breadcrumb under debug
|
|
2850
|
+
if (process.env.GETDOTENV_DEBUG) {
|
|
2851
|
+
try {
|
|
2852
|
+
const msg = JSON.stringify({
|
|
2853
|
+
profile: out.profile,
|
|
2854
|
+
region: out.region,
|
|
2855
|
+
hasCreds: Boolean(out.credentials),
|
|
2856
|
+
});
|
|
2857
|
+
process.stderr.write(`[aws] session established ${msg}\n`);
|
|
2858
|
+
}
|
|
2859
|
+
catch {
|
|
2860
|
+
/* ignore */
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
if (!underTests)
|
|
2864
|
+
process.exit(0);
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
/**
|
|
2869
|
+
* Attach options/arguments for the AWS plugin mount.
|
|
2870
|
+
*
|
|
2871
|
+
* @param cli - The `aws` command mount.
|
|
2872
|
+
* @param plugin - The AWS plugin instance (for dynamic option descriptions).
|
|
2873
|
+
*
|
|
2874
|
+
* @internal
|
|
2875
|
+
*/
|
|
2876
|
+
function attachAwsOptions(cli, plugin) {
|
|
2877
|
+
return (cli
|
|
2878
|
+
// Description is owned by the plugin index (src/plugins/aws/index.ts).
|
|
2879
|
+
.enablePositionalOptions()
|
|
2880
|
+
.passThroughOptions()
|
|
2881
|
+
.allowUnknownOption(true)
|
|
2882
|
+
// Boolean toggles with dynamic help labels (effective defaults)
|
|
2883
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--login-on-demand', (_bag, cfg) => `attempt aws sso login on-demand${cfg.loginOnDemand ? ' (default)' : ''}`))
|
|
2884
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--no-login-on-demand', (_bag, cfg) => `disable sso login on-demand${cfg.loginOnDemand === false ? ' (default)' : ''}`))
|
|
2885
|
+
// Strings / enums
|
|
2886
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--profile <string>', (_bag, cfg) => `AWS profile name${cfg.profile ? ` (default: ${JSON.stringify(cfg.profile)})` : ''}`))
|
|
2887
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--region <string>', (_bag, cfg) => `AWS region${cfg.region ? ` (default: ${JSON.stringify(cfg.region)})` : ''}`))
|
|
2888
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--default-region <string>', (_bag, cfg) => `fallback region${cfg.defaultRegion ? ` (default: ${JSON.stringify(cfg.defaultRegion)})` : ''}`))
|
|
2889
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--strategy <string>', (_bag, cfg) => `credential acquisition strategy: cli-export|none${cfg.strategy ? ` (default: ${JSON.stringify(cfg.strategy)})` : ''}`))
|
|
2890
|
+
// Advanced key overrides
|
|
2891
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--profile-key <string>', (_bag, cfg) => `dotenv/config key for local profile${cfg.profileKey ? ` (default: ${JSON.stringify(cfg.profileKey)})` : ''}`))
|
|
2892
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--profile-fallback-key <string>', (_bag, cfg) => `fallback dotenv/config key for profile${cfg.profileFallbackKey ? ` (default: ${JSON.stringify(cfg.profileFallbackKey)})` : ''}`))
|
|
2893
|
+
.addOption(plugin.createPluginDynamicOption(cli, '--region-key <string>', (_bag, cfg) => `dotenv/config key for region${cfg.regionKey ? ` (default: ${JSON.stringify(cfg.regionKey)})` : ''}`))
|
|
2894
|
+
// Accept any extra operands so Commander does not error when tokens appear after "--".
|
|
2895
|
+
.argument('[args...]'));
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
/**
|
|
2899
|
+
* Attach the AWS plugin `preSubcommand` hook.
|
|
2900
|
+
*
|
|
2901
|
+
* Ensures `aws --profile/--region <child>` applies the AWS session setup before
|
|
2902
|
+
* child subcommand execution.
|
|
2903
|
+
*
|
|
2904
|
+
* @param cli - The `aws` command mount.
|
|
2905
|
+
* @param plugin - The AWS plugin instance.
|
|
2906
|
+
*
|
|
2907
|
+
* @internal
|
|
2908
|
+
*/
|
|
2909
|
+
function attachAwsPreSubcommandHook(cli, plugin) {
|
|
2910
|
+
cli.hook('preSubcommand', async (thisCommand) => {
|
|
2911
|
+
// Avoid side effects for help rendering.
|
|
2912
|
+
if (process.argv.includes('-h') || process.argv.includes('--help'))
|
|
2913
|
+
return;
|
|
2914
|
+
const ctx = cli.getCtx();
|
|
2915
|
+
const cfgBase = plugin.readConfig(cli);
|
|
2916
|
+
const cfg = {
|
|
2917
|
+
...cfgBase,
|
|
2918
|
+
...awsConfigOverridesFromCommandOpts(thisCommand.opts()),
|
|
2919
|
+
};
|
|
2920
|
+
const out = await resolveAwsContext({
|
|
2921
|
+
dotenv: ctx.dotenv,
|
|
2922
|
+
cfg,
|
|
2923
|
+
});
|
|
2924
|
+
applyAwsContext(out, ctx, true);
|
|
2925
|
+
});
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2666
2928
|
/**
|
|
2667
2929
|
* Zod schema for AWS plugin configuration.
|
|
2668
2930
|
*/
|
|
2669
|
-
const
|
|
2931
|
+
const awsPluginConfigSchema = z.object({
|
|
2670
2932
|
profile: z.string().optional(),
|
|
2671
2933
|
region: z.string().optional(),
|
|
2672
2934
|
defaultRegion: z.string().optional(),
|
|
@@ -2690,129 +2952,16 @@ const AwsPluginConfigSchema = z.object({
|
|
|
2690
2952
|
const awsPlugin = () => {
|
|
2691
2953
|
const plugin = definePlugin({
|
|
2692
2954
|
ns: 'aws',
|
|
2693
|
-
configSchema:
|
|
2694
|
-
setup
|
|
2695
|
-
|
|
2696
|
-
cli
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
.passThroughOptions()
|
|
2700
|
-
.allowUnknownOption(true)
|
|
2701
|
-
// Boolean toggles with dynamic help labels (effective defaults)
|
|
2702
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--login-on-demand', (_bag, cfg) => `attempt aws sso login on-demand${cfg.loginOnDemand ? ' (default)' : ''}`))
|
|
2703
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--no-login-on-demand', (_bag, cfg) => `disable sso login on-demand${cfg.loginOnDemand === false ? ' (default)' : ''}`))
|
|
2704
|
-
// Strings / enums
|
|
2705
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--profile <string>', (_bag, cfg) => `AWS profile name${cfg.profile ? ` (default: ${JSON.stringify(cfg.profile)})` : ''}`))
|
|
2706
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--region <string>', (_bag, cfg) => `AWS region${cfg.region ? ` (default: ${JSON.stringify(cfg.region)})` : ''}`))
|
|
2707
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--default-region <string>', (_bag, cfg) => `fallback region${cfg.defaultRegion ? ` (default: ${JSON.stringify(cfg.defaultRegion)})` : ''}`))
|
|
2708
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--strategy <string>', (_bag, cfg) => `credential acquisition strategy: cli-export|none${cfg.strategy ? ` (default: ${JSON.stringify(cfg.strategy)})` : ''}`))
|
|
2709
|
-
// Advanced key overrides
|
|
2710
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--profile-key <string>', (_bag, cfg) => `dotenv/config key for local profile${cfg.profileKey ? ` (default: ${JSON.stringify(cfg.profileKey)})` : ''}`))
|
|
2711
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--profile-fallback-key <string>', (_bag, cfg) => `fallback dotenv/config key for profile${cfg.profileFallbackKey ? ` (default: ${JSON.stringify(cfg.profileFallbackKey)})` : ''}`))
|
|
2712
|
-
.addOption(plugin.createPluginDynamicOption(cli, '--region-key <string>', (_bag, cfg) => `dotenv/config key for region${cfg.regionKey ? ` (default: ${JSON.stringify(cfg.regionKey)})` : ''}`))
|
|
2713
|
-
// Accept any extra operands so Commander does not error when tokens appear after "--".
|
|
2714
|
-
.argument('[args...]')
|
|
2715
|
-
.action(async (args, opts, thisCommand) => {
|
|
2716
|
-
const pluginInst = plugin;
|
|
2717
|
-
// Access merged root CLI options (installed by passOptions())
|
|
2718
|
-
const bag = readMergedOptions(thisCommand);
|
|
2719
|
-
const capture = shouldCapture(bag.capture);
|
|
2720
|
-
const underTests = process.env.GETDOTENV_TEST === '1' ||
|
|
2721
|
-
typeof process.env.VITEST_WORKER_ID === 'string';
|
|
2722
|
-
// Build overlay cfg from subcommand flags layered over discovered config.
|
|
2723
|
-
const ctx = cli.getCtx();
|
|
2724
|
-
const cfgBase = pluginInst.readConfig(cli);
|
|
2725
|
-
const o = opts;
|
|
2726
|
-
const overlay = {};
|
|
2727
|
-
// Map boolean toggles (respect explicit --no-*)
|
|
2728
|
-
if (Object.prototype.hasOwnProperty.call(o, 'loginOnDemand'))
|
|
2729
|
-
overlay.loginOnDemand = Boolean(o.loginOnDemand);
|
|
2730
|
-
// Strings/enums
|
|
2731
|
-
if (typeof o.profile === 'string')
|
|
2732
|
-
overlay.profile = o.profile;
|
|
2733
|
-
if (typeof o.region === 'string')
|
|
2734
|
-
overlay.region = o.region;
|
|
2735
|
-
if (typeof o.defaultRegion === 'string')
|
|
2736
|
-
overlay.defaultRegion = o.defaultRegion;
|
|
2737
|
-
if (typeof o.strategy === 'string')
|
|
2738
|
-
overlay.strategy = o.strategy;
|
|
2739
|
-
// Advanced key overrides
|
|
2740
|
-
if (typeof o.profileKey === 'string')
|
|
2741
|
-
overlay.profileKey = o.profileKey;
|
|
2742
|
-
if (typeof o.profileFallbackKey === 'string')
|
|
2743
|
-
overlay.profileFallbackKey = o.profileFallbackKey;
|
|
2744
|
-
if (typeof o.regionKey === 'string')
|
|
2745
|
-
overlay.regionKey = o.regionKey;
|
|
2746
|
-
const cfg = {
|
|
2747
|
-
...cfgBase,
|
|
2748
|
-
...overlay,
|
|
2749
|
-
};
|
|
2750
|
-
// Resolve current context with overrides
|
|
2751
|
-
const out = await resolveAwsContext({
|
|
2752
|
-
dotenv: ctx.dotenv,
|
|
2753
|
-
cfg,
|
|
2754
|
-
});
|
|
2755
|
-
// Publish env/context
|
|
2756
|
-
applyAwsContext(out, ctx, true);
|
|
2757
|
-
// Forward when positional args are present; otherwise session-only.
|
|
2758
|
-
if (Array.isArray(args) && args.length > 0) {
|
|
2759
|
-
const argv = ['aws', ...args];
|
|
2760
|
-
const shellSetting = resolveShell(bag.scripts, 'aws', bag.shell);
|
|
2761
|
-
const exit = await runCommand(argv, shellSetting, {
|
|
2762
|
-
env: buildSpawnEnv(process.env, ctx.dotenv),
|
|
2763
|
-
stdio: capture ? 'pipe' : 'inherit',
|
|
2764
|
-
});
|
|
2765
|
-
// Deterministic termination (suppressed under tests)
|
|
2766
|
-
if (!underTests) {
|
|
2767
|
-
process.exit(typeof exit === 'number' ? exit : 0);
|
|
2768
|
-
}
|
|
2769
|
-
return;
|
|
2770
|
-
}
|
|
2771
|
-
else {
|
|
2772
|
-
// Session only: low-noise breadcrumb under debug
|
|
2773
|
-
if (process.env.GETDOTENV_DEBUG) {
|
|
2774
|
-
try {
|
|
2775
|
-
const msg = JSON.stringify({
|
|
2776
|
-
profile: out.profile,
|
|
2777
|
-
region: out.region,
|
|
2778
|
-
hasCreds: Boolean(out.credentials),
|
|
2779
|
-
});
|
|
2780
|
-
process.stderr.write(`[aws] session established ${msg}\n`);
|
|
2781
|
-
}
|
|
2782
|
-
catch {
|
|
2783
|
-
/* ignore */
|
|
2784
|
-
}
|
|
2785
|
-
}
|
|
2786
|
-
if (!underTests)
|
|
2787
|
-
process.exit(0);
|
|
2788
|
-
return;
|
|
2789
|
-
}
|
|
2790
|
-
});
|
|
2955
|
+
configSchema: awsPluginConfigSchema,
|
|
2956
|
+
setup(cli) {
|
|
2957
|
+
cli.description('Establish an AWS session and optionally forward to the AWS CLI');
|
|
2958
|
+
const awsCmd = attachAwsOptions(cli, plugin);
|
|
2959
|
+
attachAwsPreSubcommandHook(cli, plugin);
|
|
2960
|
+
attachAwsDefaultAction(cli, plugin, awsCmd);
|
|
2791
2961
|
return undefined;
|
|
2792
2962
|
},
|
|
2793
|
-
afterResolve: async (_cli, ctx) => {
|
|
2794
|
-
const cfg = plugin.readConfig(_cli);
|
|
2795
|
-
const out = await resolveAwsContext({
|
|
2796
|
-
dotenv: ctx.dotenv,
|
|
2797
|
-
cfg,
|
|
2798
|
-
});
|
|
2799
|
-
applyAwsContext(out, ctx, true);
|
|
2800
|
-
// Optional: low-noise breadcrumb for diagnostics
|
|
2801
|
-
if (process.env.GETDOTENV_DEBUG) {
|
|
2802
|
-
try {
|
|
2803
|
-
const msg = JSON.stringify({
|
|
2804
|
-
profile: out.profile,
|
|
2805
|
-
region: out.region,
|
|
2806
|
-
hasCreds: Boolean(out.credentials),
|
|
2807
|
-
});
|
|
2808
|
-
process.stderr.write(`[aws] afterResolve ${msg}\n`);
|
|
2809
|
-
}
|
|
2810
|
-
catch {
|
|
2811
|
-
/* ignore */
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
},
|
|
2815
2963
|
});
|
|
2964
|
+
plugin.afterResolve = attachAwsAfterResolveHook(plugin);
|
|
2816
2965
|
return plugin;
|
|
2817
2966
|
};
|
|
2818
2967
|
|
package/dist/plugins-batch.d.ts
CHANGED
|
@@ -426,6 +426,7 @@ declare const batchPlugin: (opts?: BatchPluginOptions) => PluginWithInstanceHelp
|
|
|
426
426
|
globs?: string | undefined;
|
|
427
427
|
pkgCwd?: boolean | undefined;
|
|
428
428
|
}, [], {}, {}>;
|
|
429
|
+
type BatchPlugin = ReturnType<typeof batchPlugin>;
|
|
429
430
|
|
|
430
431
|
export { batchPlugin };
|
|
431
|
-
export type { BatchCmdSubcommandOptions, BatchGlobPathsOptions, BatchParentInvokerFlags, ExecShellCommandBatchOptions };
|
|
432
|
+
export type { BatchCmdSubcommandOptions, BatchGlobPathsOptions, BatchParentInvokerFlags, BatchPlugin, ExecShellCommandBatchOptions };
|