@karmaniverous/aws-secrets-manager-tools 0.1.1 → 0.2.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 CHANGED
@@ -1,102 +1,102 @@
1
- # AWS Secrets Manager Tools
2
-
3
- [![npm version](https://img.shields.io/npm/v/@karmaniverous/aws-secrets-manager-tools.svg)](https://www.npmjs.com/package/@karmaniverous/aws-secrets-manager-tools) ![Node Current](https://img.shields.io/node/v/@karmaniverous/aws-secrets-manager-tools) [![docs](https://img.shields.io/badge/docs-website-blue)](https://docs.karmanivero.us/aws-secrets-manager-tools) [![changelog](https://img.shields.io/badge/changelog-latest-blue.svg)](./CHANGELOG.md) [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](./LICENSE)
4
-
5
- Tools and a get-dotenv plugin for working with AWS Secrets Manager “env-map” secrets (JSON object maps of environment variables).
6
-
7
- This package provides:
8
-
9
- - A tools-style wrapper that owns AWS client setup (including optional AWS X-Ray capture):
10
- - `AwsSecretsManagerTools`
11
- - A get-dotenv plugin intended to be mounted under `aws`:
12
- - `secretsPlugin()` → `aws secrets pull|push|delete`
13
- - A CLI embedding get-dotenv with the secrets plugin:
14
- - `aws-secrets-manager-tools`
15
-
16
- ## Documentation
17
-
18
- - Learn the programmatic API: [AwsSecretsManagerTools guide](guides/aws-secrets-manager-tools.md)
19
- - Learn the CLI and plugin behavior: [aws secrets plugin guide](guides/secrets-plugin.md)
20
- - Browse the generated API reference: [TypeDoc site](https://docs.karmanivero.us/aws-secrets-manager-tools)
21
-
22
- ## Install
23
-
24
- ```bash
25
- npm i @karmaniverous/aws-secrets-manager-tools
26
- ```
27
-
28
- This package is ESM-only (Node >= 20).
29
-
30
- ## Quick start (programmatic)
31
-
32
- ```ts
33
- import { AwsSecretsManagerTools } from '@karmaniverous/aws-secrets-manager-tools';
34
-
35
- const tools = await AwsSecretsManagerTools.init({
36
- clientConfig: { region: 'us-east-1', logger: console },
37
- xray: 'auto',
38
- });
39
-
40
- const current = await tools.readEnvSecret({ secretId: 'my-app/dev' });
41
- await tools.upsertEnvSecret({ secretId: 'my-app/dev', value: current });
42
- ```
43
-
44
- When you need AWS functionality not wrapped by this package, use the fully configured AWS SDK v3 client at `tools.client` (see the [programmatic guide](guides/aws-secrets-manager-tools.md) for examples).
45
-
46
- ## Quick start (CLI)
47
-
48
- ```bash
49
- aws-secrets-manager-tools --env dev aws secrets pull --secret-name '$STACK_NAME'
50
- aws-secrets-manager-tools --env dev aws secrets push --secret-name '$STACK_NAME'
51
- aws-secrets-manager-tools --env dev aws secrets delete --secret-name '$STACK_NAME'
52
- ```
53
-
54
- Notes:
55
-
56
- - `--env` is a root-level (get-dotenv) option and must appear before the command path.
57
- - Secret name expansion is evaluated at action time against `{ ...process.env, ...ctx.dotenv }` (ctx wins).
58
-
59
- ## Env-map secret format
60
-
61
- Secrets are stored as a JSON object map of environment variables in `SecretString`:
62
-
63
- ```json
64
- { "KEY": "value", "OPTIONAL": null }
65
- ```
66
-
67
- Notes:
68
-
69
- - Values must be strings or `null`.
70
- - `null` is treated as `undefined` when decoding.
71
-
72
- ## AWS X-Ray capture (optional)
73
-
74
- X-Ray support is guarded:
75
-
76
- - Default behavior is `xray: 'auto'`: capture is enabled only when `AWS_XRAY_DAEMON_ADDRESS` is set.
77
- - To enable capture, install the optional peer dependency:
78
- - `aws-xray-sdk`
79
- - In `auto` mode, if `AWS_XRAY_DAEMON_ADDRESS` is set but `aws-xray-sdk` is not installed, initialization throws.
80
-
81
- ## Config defaults (getdotenv.config.\*)
82
-
83
- If you embed the plugin in your own get-dotenv host (or use the shipped CLI), you can provide safe defaults in config under `plugins['aws/secrets']`:
84
-
85
- ```jsonc
86
- {
87
- "plugins": {
88
- "aws/secrets": {
89
- "secretName": "$STACK_NAME",
90
- "templateExtension": "template",
91
- "push": { "from": ["file:env:private"] },
92
- "pull": { "to": "env:private" },
93
- },
94
- },
95
- }
96
- ```
97
-
98
- See the [secrets plugin guide](guides/secrets-plugin.md) for `--from` / `--to` selector details and all supported config keys.
99
-
100
- ---
101
-
102
- Built for you with ❤️ on Bali! Find more great tools & templates on [my GitHub Profile](https://github.com/karmaniverous).
1
+ # AWS Secrets Manager Tools
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@karmaniverous/aws-secrets-manager-tools.svg)](https://www.npmjs.com/package/@karmaniverous/aws-secrets-manager-tools) ![Node Current](https://img.shields.io/node/v/@karmaniverous/aws-secrets-manager-tools) [![docs](https://img.shields.io/badge/docs-website-blue)](https://docs.karmanivero.us/aws-secrets-manager-tools) [![changelog](https://img.shields.io/badge/changelog-latest-blue.svg)](./CHANGELOG.md) [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](./LICENSE)
4
+
5
+ Tools and a get-dotenv plugin for working with AWS Secrets Manager “env-map” secrets (JSON object maps of environment variables).
6
+
7
+ This package provides:
8
+
9
+ - A tools-style wrapper that owns AWS client setup (including optional AWS X-Ray capture):
10
+ - `AwsSecretsManagerTools`
11
+ - A get-dotenv plugin intended to be mounted under `aws`:
12
+ - `secretsPlugin()` → `aws secrets pull|push|delete`
13
+ - A CLI embedding get-dotenv with the secrets plugin:
14
+ - `aws-secrets-manager-tools`
15
+
16
+ ## Documentation
17
+
18
+ - Learn the programmatic API: [AwsSecretsManagerTools guide](guides/aws-secrets-manager-tools.md)
19
+ - Learn the CLI and plugin behavior: [aws secrets plugin guide](guides/secrets-plugin.md)
20
+ - Browse the generated API reference: [TypeDoc site](https://docs.karmanivero.us/aws-secrets-manager-tools)
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ npm i @karmaniverous/aws-secrets-manager-tools
26
+ ```
27
+
28
+ This package is ESM-only (Node >= 20).
29
+
30
+ ## Quick start (programmatic)
31
+
32
+ ```ts
33
+ import { AwsSecretsManagerTools } from '@karmaniverous/aws-secrets-manager-tools';
34
+
35
+ const tools = new AwsSecretsManagerTools({
36
+ clientConfig: { region: 'us-east-1', logger: console },
37
+ xray: 'auto',
38
+ });
39
+
40
+ const current = await tools.readEnvSecret({ secretId: 'my-app/dev' });
41
+ await tools.upsertEnvSecret({ secretId: 'my-app/dev', value: current });
42
+ ```
43
+
44
+ When you need AWS functionality not wrapped by this package, use the fully configured AWS SDK v3 client at `tools.client` (see the [programmatic guide](guides/aws-secrets-manager-tools.md) for examples).
45
+
46
+ ## Quick start (CLI)
47
+
48
+ ```bash
49
+ aws-secrets-manager-tools --env dev aws secrets pull --secret-name '$STACK_NAME'
50
+ aws-secrets-manager-tools --env dev aws secrets push --secret-name '$STACK_NAME'
51
+ aws-secrets-manager-tools --env dev aws secrets delete --secret-name '$STACK_NAME'
52
+ ```
53
+
54
+ Notes:
55
+
56
+ - `--env` is a root-level (get-dotenv) option and must appear before the command path.
57
+ - Secret name expansion is evaluated at action time against `{ ...process.env, ...ctx.dotenv }` (ctx wins).
58
+
59
+ ## Env-map secret format
60
+
61
+ Secrets are stored as a JSON object map of environment variables in `SecretString`:
62
+
63
+ ```json
64
+ { "KEY": "value", "OPTIONAL": null }
65
+ ```
66
+
67
+ Notes:
68
+
69
+ - Values must be strings or `null`.
70
+ - `null` is treated as `undefined` when decoding.
71
+
72
+ ## AWS X-Ray capture (optional)
73
+
74
+ X-Ray support is guarded:
75
+
76
+ - Default behavior is `xray: 'auto'`: capture is enabled only when `AWS_XRAY_DAEMON_ADDRESS` is set.
77
+ - To enable capture, install the optional peer dependency:
78
+ - `aws-xray-sdk`
79
+ - In `auto` mode, if `AWS_XRAY_DAEMON_ADDRESS` is set but `aws-xray-sdk` is not installed, construction throws.
80
+
81
+ ## Config defaults (getdotenv.config.\*)
82
+
83
+ If you embed the plugin in your own get-dotenv host (or use the shipped CLI), you can provide safe defaults in config under `plugins['aws/secrets']`:
84
+
85
+ ```jsonc
86
+ {
87
+ "plugins": {
88
+ "aws/secrets": {
89
+ "secretName": "$STACK_NAME",
90
+ "templateExtension": "template",
91
+ "push": { "from": ["file:env:private"] },
92
+ "pull": { "to": "env:private" },
93
+ },
94
+ },
95
+ }
96
+ ```
97
+
98
+ See the [secrets plugin guide](guides/secrets-plugin.md) for `--from` / `--to` selector details and all supported config keys.
99
+
100
+ ---
101
+
102
+ Built for you with ❤️ on Bali! Find more great tools & templates on [my GitHub Profile](https://github.com/karmaniverous).
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createCli } from '@karmaniverous/get-dotenv/cli';
3
- import { cmdPlugin, batchPlugin, awsPlugin, initPlugin } from '@karmaniverous/get-dotenv/plugins';
4
- import { readMergedOptions, z, definePlugin } from '@karmaniverous/get-dotenv/cliHost';
3
+ import { getAwsRegion, cmdPlugin, batchPlugin, awsPlugin, initPlugin } from '@karmaniverous/get-dotenv/plugins';
4
+ import { readMergedOptions, z, describeConfigKeyListDefaults, describeDefault, definePlugin } from '@karmaniverous/get-dotenv/cliHost';
5
+ import { assertLogger, silentLogger, buildSpawnEnv, dotenvExpand, toNumber, getDotenvCliOptions2Options, applyIncludeExclude, editDotenvFile, requireString, assertByteLimit } from '@karmaniverous/get-dotenv';
5
6
  import { SecretsManagerClient, GetSecretValueCommand, PutSecretValueCommand, CreateSecretCommand, DeleteSecretCommand } from '@aws-sdk/client-secrets-manager';
6
- import { dotenvExpand, getDotenvCliOptions2Options, editDotenvFile } from '@karmaniverous/get-dotenv';
7
- import { omit, pick } from 'radash';
8
- import { Buffer } from 'node:buffer';
7
+ import { shouldEnableXray, captureAwsSdkV3Client } from '@karmaniverous/aws-xray-tools';
8
+ import { getAwsRegion as getAwsRegion$1 } from '@karmaniverous/get-dotenv/plugins/aws';
9
9
 
10
10
  /**
11
11
  * Requirements addressed:
@@ -21,74 +21,22 @@ const getAwsErrorCode = (err) => {
21
21
  const isAwsErrorCode = (err, code) => getAwsErrorCode(err) === code;
22
22
  const isResourceNotFoundError = (err) => isAwsErrorCode(err, 'ResourceNotFoundException');
23
23
 
24
- /**
25
- * Requirements addressed:
26
- * - Optional AWS X-Ray capture support.
27
- * - Default behavior “auto”: only attempt capture when AWS_XRAY_DAEMON_ADDRESS
28
- * is set.
29
- * - Avoid importing/enabling X-Ray when the daemon address is not set (the
30
- * X-Ray SDK will throw otherwise).
31
- */
32
- const shouldEnableXray = (mode, daemonAddress) => {
33
- if (mode === 'off')
34
- return false;
35
- if (mode === 'on')
36
- return true;
37
- return Boolean(daemonAddress);
38
- };
39
- const captureAwsSdkV3Client = async (client, { mode = 'auto', logger = console, daemonAddress = process.env.AWS_XRAY_DAEMON_ADDRESS, } = {}) => {
40
- if (!shouldEnableXray(mode, daemonAddress))
41
- return client;
42
- if (!daemonAddress) {
43
- throw new Error('X-Ray capture requested but AWS_XRAY_DAEMON_ADDRESS is not set.');
44
- }
45
- // Guarded dynamic import: some X-Ray SDK integrations throw when daemon
46
- // configuration is missing, so do not import unless we are capturing.
47
- let mod;
48
- try {
49
- mod = (await import('aws-xray-sdk'));
50
- }
51
- catch {
52
- throw new Error("X-Ray capture is enabled but 'aws-xray-sdk' is not installed. Install it or set xray to 'off'.");
53
- }
54
- const AWSXRay = (mod.default ?? mod);
55
- if (typeof AWSXRay.captureAWSv3Client !== 'function') {
56
- logger.debug('aws-xray-sdk does not expose captureAWSv3Client', AWSXRay);
57
- throw new Error('aws-xray-sdk missing captureAWSv3Client export.');
58
- }
59
- logger.debug('Enabling AWS X-Ray capture for AWS SDK v3 client.');
60
- return AWSXRay.captureAWSv3Client(client);
61
- };
62
-
63
24
  /**
64
25
  * Requirements addressed:
65
26
  * - Provide a public tools-style wrapper `AwsSecretsManagerTools`.
66
27
  * - Package consumers should not need to construct SecretsManagerClient; they
67
- * should use `AwsSecretsManagerTools.init(...)` and optionally import AWS SDK
68
- * Commands for advanced operations.
28
+ * should construct `new AwsSecretsManagerTools(...)` and optionally import
29
+ * AWS SDK Commands for advanced operations.
69
30
  * - Expose the fully configured SDK client via `tools.client`.
70
31
  * - Support optional AWS X-Ray capture:
71
32
  * - Default “auto”: enable only when AWS_XRAY_DAEMON_ADDRESS is set.
72
33
  * - In “auto”, if the daemon address is set but aws-xray-sdk is missing,
73
34
  * throw with a clear message.
74
- * - Enforce a minimal logger contract (debug/info/warn/error); do not attempt
75
- * to polyfill or proxy unknown loggers.
35
+ * - Enforce the get-dotenv minimal Logger contract (debug/info/warn/error);
36
+ * validate and throw (no polyfills or proxies).
76
37
  * - Secret values are JSON object maps of env vars.
77
38
  */
78
- const assertLogger = (candidate) => {
79
- if (!candidate || typeof candidate !== 'object') {
80
- throw new Error('logger must be an object with debug, info, warn, and error methods');
81
- }
82
- const logger = candidate;
83
- if (typeof logger.debug !== 'function' ||
84
- typeof logger.info !== 'function' ||
85
- typeof logger.warn !== 'function' ||
86
- typeof logger.error !== 'function') {
87
- throw new Error('logger must implement debug, info, warn, and error methods; wrap/proxy your logger if needed');
88
- }
89
- return logger;
90
- };
91
- const parseEnvSecretMap = (secretString) => {
39
+ const parseProcessEnv = (secretString) => {
92
40
  let parsed;
93
41
  try {
94
42
  parsed = JSON.parse(secretString);
@@ -118,7 +66,7 @@ const toSecretString = (value) => JSON.stringify(value);
118
66
  * Tools-style AWS Secrets Manager wrapper for env-map secrets.
119
67
  *
120
68
  * The secret payload is always a JSON object map of environment variables:
121
- * `Record<string, string | undefined>`.
69
+ * `ProcessEnv`.
122
70
  *
123
71
  * Consumers should typically use the convenience methods on this class, and
124
72
  * use {@link AwsSecretsManagerTools.client} as an escape hatch when they need
@@ -141,17 +89,8 @@ class AwsSecretsManagerTools {
141
89
  logger;
142
90
  /** Materialized X-Ray state (mode + enabled + daemonAddress when relevant). */
143
91
  xray;
144
- constructor({ client, clientConfig, logger, xray, }) {
145
- this.client = client;
146
- this.clientConfig = clientConfig;
147
- this.logger = logger;
148
- this.xray = xray;
149
- }
150
92
  /**
151
- * Initialize an `AwsSecretsManagerTools` instance.
152
- *
153
- * This factory owns all setup (including optional X-Ray capture) so consumers
154
- * do not need to construct a base Secrets Manager client themselves.
93
+ * Construct an `AwsSecretsManagerTools` instance.
155
94
  *
156
95
  * @throws If `clientConfig.logger` is provided but does not implement
157
96
  * `debug`, `info`, `warn`, and `error`.
@@ -159,7 +98,7 @@ class AwsSecretsManagerTools {
159
98
  * with `AWS_XRAY_DAEMON_ADDRESS` set) but `aws-xray-sdk` is not installed.
160
99
  * @throws If X-Ray capture is requested but `AWS_XRAY_DAEMON_ADDRESS` is not set.
161
100
  */
162
- static async init({ clientConfig = {}, xray: xrayMode = 'auto', } = {}) {
101
+ constructor({ clientConfig = {}, xray: xrayMode = 'auto', } = {}) {
163
102
  const logger = assertLogger(clientConfig.logger ?? console);
164
103
  const effectiveClientConfig = {
165
104
  ...clientConfig,
@@ -174,18 +113,16 @@ class AwsSecretsManagerTools {
174
113
  ...(enabled && daemonAddress ? { daemonAddress } : {}),
175
114
  };
176
115
  const effectiveClient = enabled
177
- ? await captureAwsSdkV3Client(base, {
116
+ ? captureAwsSdkV3Client(base, {
178
117
  mode: xrayMode,
179
118
  logger,
180
119
  daemonAddress,
181
120
  })
182
121
  : base;
183
- return new AwsSecretsManagerTools({
184
- client: effectiveClient,
185
- clientConfig: effectiveClientConfig,
186
- logger,
187
- xray: xrayState,
188
- });
122
+ this.client = effectiveClient;
123
+ this.clientConfig = effectiveClientConfig;
124
+ this.logger = logger;
125
+ this.xray = xrayState;
189
126
  }
190
127
  /**
191
128
  * Read a Secrets Manager secret and parse it as an env-map secret.
@@ -208,7 +145,7 @@ class AwsSecretsManagerTools {
208
145
  if (!res.SecretString) {
209
146
  throw new Error('SecretString is missing (binary secrets not supported).');
210
147
  }
211
- return parseEnvSecretMap(res.SecretString);
148
+ return parseProcessEnv(res.SecretString);
212
149
  }
213
150
  /**
214
151
  * Write a new version value for an existing secret.
@@ -315,96 +252,6 @@ class AwsSecretsManagerTools {
315
252
  }
316
253
  }
317
254
 
318
- /**
319
- * Requirements addressed:
320
- * - Secret name expansion expands against `{ ...process.env, ...ctx.dotenv }`.
321
- * - include/exclude ignore unknown keys; use radash (no lodash).
322
- */
323
- const buildExpansionEnv = (ctxDotenv) => ({
324
- ...process.env,
325
- ...ctxDotenv,
326
- });
327
- const expandSecretName = (raw, envRef) => dotenvExpand(raw, envRef) ?? raw;
328
- const applyIncludeExclude = (env, { include, exclude, }) => {
329
- let out = env;
330
- if (exclude?.length)
331
- out = omit(out, exclude);
332
- if (include?.length)
333
- out = pick(out, include);
334
- return out;
335
- };
336
-
337
- /**
338
- * Requirements addressed:
339
- * - Enforce AWS Secrets Manager SecretString size limits (65,536 bytes).
340
- * - Provide safe parsing helpers for CLI-mapped inputs.
341
- * - Render config-derived defaults in dynamic option help text.
342
- * - Access aws plugin ctx state via runtime narrowing (no casts).
343
- */
344
- const silentLogger = {
345
- debug: () => {
346
- // no-op
347
- },
348
- info: () => {
349
- // no-op
350
- },
351
- warn: () => {
352
- // no-op
353
- },
354
- error: () => {
355
- // no-op
356
- },
357
- };
358
- const requireString = (v, msg) => {
359
- if (typeof v !== 'string' || !v)
360
- throw new Error(msg);
361
- return v;
362
- };
363
- const toNumber = (v) => {
364
- if (typeof v === 'undefined')
365
- return;
366
- if (typeof v === 'number')
367
- return v;
368
- if (typeof v === 'string' && v.trim())
369
- return Number(v);
370
- return;
371
- };
372
- const assertBytesWithinSecretsManagerLimit = (value) => {
373
- const s = JSON.stringify(value);
374
- const bytes = Buffer.byteLength(s, 'utf8');
375
- if (bytes > 65_536) {
376
- throw new Error(`SecretString size ${String(bytes)} bytes exceeds 65536 bytes; narrow selection with --from/--include/--exclude.`);
377
- }
378
- };
379
- const describeDefault = (v) => {
380
- if (Array.isArray(v))
381
- return v.length ? v.join(' ') : 'none';
382
- if (typeof v === 'string' && v.trim())
383
- return v;
384
- return 'none';
385
- };
386
- const isRecord = (v) => typeof v === 'object' && v !== null;
387
- const getAwsRegion = (ctx) => {
388
- if (!isRecord(ctx.plugins))
389
- return;
390
- const aws = ctx.plugins['aws'];
391
- if (!isRecord(aws))
392
- return;
393
- const region = aws['region'];
394
- return typeof region === 'string' ? region : undefined;
395
- };
396
- const describeConfigKeyListDefaults = ({ cfgInclude, cfgExclude, }) => {
397
- // Avoid throwing in help rendering: show an explicit invalid marker.
398
- if (cfgInclude?.length && cfgExclude?.length) {
399
- const msg = '(invalid: both set in config)';
400
- return { includeDefault: msg, excludeDefault: msg };
401
- }
402
- return {
403
- includeDefault: describeDefault(cfgExclude?.length ? undefined : cfgInclude),
404
- excludeDefault: describeDefault(cfgInclude?.length ? undefined : cfgExclude),
405
- };
406
- };
407
-
408
255
  /**
409
256
  * Requirements addressed:
410
257
  * - Provide `aws secrets delete`.
@@ -434,14 +281,14 @@ const registerDeleteCommand = ({ cli, plugin, }) => {
434
281
  const logger = console;
435
282
  const ctx = cli.getCtx();
436
283
  const cfg = plugin.readConfig(del);
437
- const envRef = buildExpansionEnv(ctx.dotenv);
284
+ const envRef = buildSpawnEnv(process.env, ctx.dotenv);
438
285
  const secretNameRaw = opts.secretName ?? cfg.secretName ?? '$STACK_NAME';
439
- const secretId = expandSecretName(secretNameRaw, envRef);
286
+ const secretId = dotenvExpand(secretNameRaw, envRef);
440
287
  if (!secretId)
441
288
  throw new Error('secret-name is required.');
442
289
  const recoveryWindowInDays = toNumber(opts.recoveryWindowDays);
443
290
  const region = getAwsRegion(ctx);
444
- const tools = await AwsSecretsManagerTools.init({
291
+ const tools = new AwsSecretsManagerTools({
445
292
  clientConfig: region
446
293
  ? { region, logger: sdkLogger }
447
294
  : { logger: sdkLogger },
@@ -718,13 +565,13 @@ const registerPullCommand = ({ cli, plugin, }) => {
718
565
  const privateToken = rootOpts.privateToken ?? 'local';
719
566
  const toRaw = opts.to ?? cfg.pull?.to ?? 'env:private';
720
567
  const to = parseToSelector(toRaw);
721
- const envRef = buildExpansionEnv(ctx.dotenv);
568
+ const envRef = buildSpawnEnv(process.env, ctx.dotenv);
722
569
  const secretNameRaw = opts.secretName ?? cfg.secretName ?? '$STACK_NAME';
723
- const secretId = expandSecretName(secretNameRaw, envRef);
570
+ const secretId = dotenvExpand(secretNameRaw, envRef);
724
571
  if (!secretId)
725
572
  throw new Error('secret-name is required.');
726
- const region = getAwsRegion(ctx);
727
- const tools = await AwsSecretsManagerTools.init({
573
+ const region = getAwsRegion$1(ctx);
574
+ const tools = new AwsSecretsManagerTools({
728
575
  clientConfig: region
729
576
  ? { region, logger: sdkLogger }
730
577
  : { logger: sdkLogger },
@@ -750,7 +597,7 @@ const registerPullCommand = ({ cli, plugin, }) => {
750
597
  ? await editDotenvFile(secrets, {
751
598
  ...editCommon,
752
599
  scope: 'env',
753
- env: requireString(bag.env ?? bag.defaultEnv, 'env is required (use --env or defaultEnv).'),
600
+ env: requireString(bag.env, 'env is required (use --env or defaultEnv).'),
754
601
  })
755
602
  : await editDotenvFile(secrets, {
756
603
  ...editCommon,
@@ -823,16 +670,16 @@ const registerPushCommand = ({ cli, plugin, }) => {
823
670
  cfgInclude: cfg.push?.include,
824
671
  cfgExclude: cfg.push?.exclude,
825
672
  });
826
- const envRef = buildExpansionEnv(ctx.dotenv);
673
+ const envRef = buildSpawnEnv(process.env, ctx.dotenv);
827
674
  const secretNameRaw = opts.secretName ?? cfg.secretName ?? '$STACK_NAME';
828
- const secretId = expandSecretName(secretNameRaw, envRef);
675
+ const secretId = dotenvExpand(secretNameRaw, envRef);
829
676
  if (!secretId)
830
677
  throw new Error('secret-name is required.');
831
678
  const selected = selectEnvByProvenance(ctx.dotenv, ctx.dotenvProvenance, fromSelectors);
832
679
  const secrets = applyIncludeExclude(selected, { include, exclude });
833
- assertBytesWithinSecretsManagerLimit(secrets);
834
- const region = getAwsRegion(ctx);
835
- const tools = await AwsSecretsManagerTools.init({
680
+ assertByteLimit(secrets, 65_536, (v, l) => `SecretString size ${String(v)} bytes exceeds ${String(l)} bytes; narrow selection with --from/--include/--exclude.`);
681
+ const region = getAwsRegion$1(ctx);
682
+ const tools = new AwsSecretsManagerTools({
836
683
  clientConfig: region
837
684
  ? { region, logger: sdkLogger }
838
685
  : { logger: sdkLogger },
package/dist/index.d.ts CHANGED
@@ -1,59 +1,26 @@
1
1
  import { SecretsManagerClient, SecretsManagerClientConfig } from '@aws-sdk/client-secrets-manager';
2
+ import { XrayState, XrayMode } from '@karmaniverous/aws-xray-tools';
3
+ import { Logger, ProcessEnv } from '@karmaniverous/get-dotenv';
2
4
  import * as _karmaniverous_get_dotenv_cliHost from '@karmaniverous/get-dotenv/cliHost';
3
5
 
4
- /**
5
- * Requirements addressed:
6
- * - Secret values are always a JSON object map of env vars.
7
- */
8
- /**
9
- * Canonical “env secret” shape stored in AWS Secrets Manager.
10
- *
11
- * `undefined` values are not representable in JSON; readers should treat `null`
12
- * values as `undefined` when decoding.
13
- */
14
- type EnvSecretMap = Record<string, string | undefined>;
15
-
16
6
  /**
17
7
  * Requirements addressed:
18
8
  * - Provide a public tools-style wrapper `AwsSecretsManagerTools`.
19
9
  * - Package consumers should not need to construct SecretsManagerClient; they
20
- * should use `AwsSecretsManagerTools.init(...)` and optionally import AWS SDK
21
- * Commands for advanced operations.
10
+ * should construct `new AwsSecretsManagerTools(...)` and optionally import
11
+ * AWS SDK Commands for advanced operations.
22
12
  * - Expose the fully configured SDK client via `tools.client`.
23
13
  * - Support optional AWS X-Ray capture:
24
14
  * - Default “auto”: enable only when AWS_XRAY_DAEMON_ADDRESS is set.
25
15
  * - In “auto”, if the daemon address is set but aws-xray-sdk is missing,
26
16
  * throw with a clear message.
27
- * - Enforce a minimal logger contract (debug/info/warn/error); do not attempt
28
- * to polyfill or proxy unknown loggers.
17
+ * - Enforce the get-dotenv minimal Logger contract (debug/info/warn/error);
18
+ * validate and throw (no polyfills or proxies).
29
19
  * - Secret values are JSON object maps of env vars.
30
20
  */
31
21
 
32
- /**
33
- * Console-like logger contract used by AwsSecretsManagerTools.
34
- *
35
- * If you pass a custom logger via `clientConfig.logger`, it must implement
36
- * these methods (no internal polyfills are applied).
37
- */
38
- type AwsSecretsManagerToolsLogger = Pick<Console, 'debug' | 'error' | 'info' | 'warn'>;
39
- /** X-Ray capture mode for {@link AwsSecretsManagerTools.init}. */
40
- type AwsSecretsManagerToolsXrayMode = 'auto' | 'on' | 'off';
41
- /**
42
- * Materialized X-Ray state for diagnostics and DX.
43
- *
44
- * Note: `enabled` reflects the effective runtime decision after applying the
45
- * configured `mode` and checking daemon configuration.
46
- */
47
- type XrayState = {
48
- /** Capture mode configured for initialization. */
49
- mode: AwsSecretsManagerToolsXrayMode;
50
- /** Whether capture is enabled for the effective client instance. */
51
- enabled: boolean;
52
- /** Daemon address used when capture is enabled (if available). */
53
- daemonAddress?: string;
54
- };
55
- /** Options for {@link AwsSecretsManagerTools.init}. */
56
- type AwsSecretsManagerToolsInitOptions = {
22
+ /** Options for {@link AwsSecretsManagerTools} construction. */
23
+ type AwsSecretsManagerToolsOptions = {
57
24
  /**
58
25
  * AWS SDK v3 Secrets Manager client config.
59
26
  *
@@ -69,13 +36,13 @@ type AwsSecretsManagerToolsInitOptions = {
69
36
  * - `on`: force enable (throws if daemon address is missing).
70
37
  * - `off`: disable.
71
38
  */
72
- xray?: AwsSecretsManagerToolsXrayMode;
39
+ xray?: XrayMode;
73
40
  };
74
41
  /**
75
42
  * Tools-style AWS Secrets Manager wrapper for env-map secrets.
76
43
  *
77
44
  * The secret payload is always a JSON object map of environment variables:
78
- * `Record<string, string | undefined>`.
45
+ * `ProcessEnv`.
79
46
  *
80
47
  * Consumers should typically use the convenience methods on this class, and
81
48
  * use {@link AwsSecretsManagerTools.client} as an escape hatch when they need
@@ -95,15 +62,11 @@ declare class AwsSecretsManagerTools {
95
62
  */
96
63
  readonly clientConfig: SecretsManagerClientConfig;
97
64
  /** The logger used by this wrapper and (when applicable) by the AWS client. */
98
- readonly logger: AwsSecretsManagerToolsLogger;
65
+ readonly logger: Logger;
99
66
  /** Materialized X-Ray state (mode + enabled + daemonAddress when relevant). */
100
67
  readonly xray: XrayState;
101
- private constructor();
102
68
  /**
103
- * Initialize an `AwsSecretsManagerTools` instance.
104
- *
105
- * This factory owns all setup (including optional X-Ray capture) so consumers
106
- * do not need to construct a base Secrets Manager client themselves.
69
+ * Construct an `AwsSecretsManagerTools` instance.
107
70
  *
108
71
  * @throws If `clientConfig.logger` is provided but does not implement
109
72
  * `debug`, `info`, `warn`, and `error`.
@@ -111,7 +74,7 @@ declare class AwsSecretsManagerTools {
111
74
  * with `AWS_XRAY_DAEMON_ADDRESS` set) but `aws-xray-sdk` is not installed.
112
75
  * @throws If X-Ray capture is requested but `AWS_XRAY_DAEMON_ADDRESS` is not set.
113
76
  */
114
- static init({ clientConfig, xray: xrayMode, }?: AwsSecretsManagerToolsInitOptions): Promise<AwsSecretsManagerTools>;
77
+ constructor({ clientConfig, xray: xrayMode, }?: AwsSecretsManagerToolsOptions);
115
78
  /**
116
79
  * Read a Secrets Manager secret and parse it as an env-map secret.
117
80
  *
@@ -124,7 +87,7 @@ declare class AwsSecretsManagerTools {
124
87
  readEnvSecret(opts: {
125
88
  secretId: string;
126
89
  versionId?: string;
127
- }): Promise<EnvSecretMap>;
90
+ }): Promise<ProcessEnv>;
128
91
  /**
129
92
  * Write a new version value for an existing secret.
130
93
  *
@@ -137,7 +100,7 @@ declare class AwsSecretsManagerTools {
137
100
  */
138
101
  updateEnvSecret(opts: {
139
102
  secretId: string;
140
- value: EnvSecretMap;
103
+ value: ProcessEnv;
141
104
  versionId?: string;
142
105
  }): Promise<void>;
143
106
  /**
@@ -152,7 +115,7 @@ declare class AwsSecretsManagerTools {
152
115
  */
153
116
  createEnvSecret(opts: {
154
117
  secretId: string;
155
- value: EnvSecretMap;
118
+ value: ProcessEnv;
156
119
  description?: string;
157
120
  forceOverwriteReplicaSecret?: boolean;
158
121
  versionId?: string;
@@ -168,7 +131,7 @@ declare class AwsSecretsManagerTools {
168
131
  */
169
132
  upsertEnvSecret({ secretId, value, }: {
170
133
  secretId: string;
171
- value: EnvSecretMap;
134
+ value: ProcessEnv;
172
135
  }): Promise<'updated' | 'created'>;
173
136
  /**
174
137
  * Delete a secret.
@@ -209,6 +172,7 @@ declare class AwsSecretsManagerTools {
209
172
  declare const secretsPlugin: () => _karmaniverous_get_dotenv_cliHost.PluginWithInstanceHelpers<Omit<{
210
173
  logger: unknown;
211
174
  defaultEnv?: string | undefined;
175
+ defaultEnvKey?: string | undefined;
212
176
  dotenvToken?: string | undefined;
213
177
  dynamicPath?: string | undefined;
214
178
  dynamic?: Record<string, unknown> | undefined;
@@ -225,7 +189,12 @@ declare const secretsPlugin: () => _karmaniverous_get_dotenv_cliHost.PluginWithI
225
189
  privateToken?: string | undefined;
226
190
  vars?: Record<string, string | undefined> | undefined;
227
191
  }, "dynamic" | "logger"> & {
228
- logger: Record<string, (...args: unknown[]) => void> | Console;
192
+ logger: {
193
+ debug: (...data: any[]) => void;
194
+ info: (...data: any[]) => void;
195
+ warn: (...data: any[]) => void;
196
+ error: (...data: any[]) => void;
197
+ };
229
198
  dynamic?: {
230
199
  [x: string]: string | ((vars: {
231
200
  [x: string]: string | undefined;
@@ -247,4 +216,4 @@ declare const secretsPlugin: () => _karmaniverous_get_dotenv_cliHost.PluginWithI
247
216
  }, [], {}, {}>;
248
217
 
249
218
  export { AwsSecretsManagerTools, secretsPlugin };
250
- export type { AwsSecretsManagerToolsInitOptions, AwsSecretsManagerToolsLogger, AwsSecretsManagerToolsXrayMode, EnvSecretMap, XrayState };
219
+ export type { AwsSecretsManagerToolsOptions };
package/dist/mjs/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { SecretsManagerClient, GetSecretValueCommand, PutSecretValueCommand, CreateSecretCommand, DeleteSecretCommand } from '@aws-sdk/client-secrets-manager';
2
- import { readMergedOptions, z, definePlugin } from '@karmaniverous/get-dotenv/cliHost';
3
- import { dotenvExpand, getDotenvCliOptions2Options, editDotenvFile } from '@karmaniverous/get-dotenv';
4
- import { omit, pick } from 'radash';
5
- import { Buffer } from 'node:buffer';
2
+ import { shouldEnableXray, captureAwsSdkV3Client } from '@karmaniverous/aws-xray-tools';
3
+ import { assertLogger, silentLogger, buildSpawnEnv, dotenvExpand, toNumber, getDotenvCliOptions2Options, applyIncludeExclude, editDotenvFile, requireString, assertByteLimit } from '@karmaniverous/get-dotenv';
4
+ import { readMergedOptions, z, describeConfigKeyListDefaults, describeDefault, definePlugin } from '@karmaniverous/get-dotenv/cliHost';
5
+ import { getAwsRegion } from '@karmaniverous/get-dotenv/plugins';
6
+ import { getAwsRegion as getAwsRegion$1 } from '@karmaniverous/get-dotenv/plugins/aws';
6
7
 
7
8
  /**
8
9
  * Requirements addressed:
@@ -18,74 +19,22 @@ const getAwsErrorCode = (err) => {
18
19
  const isAwsErrorCode = (err, code) => getAwsErrorCode(err) === code;
19
20
  const isResourceNotFoundError = (err) => isAwsErrorCode(err, 'ResourceNotFoundException');
20
21
 
21
- /**
22
- * Requirements addressed:
23
- * - Optional AWS X-Ray capture support.
24
- * - Default behavior “auto”: only attempt capture when AWS_XRAY_DAEMON_ADDRESS
25
- * is set.
26
- * - Avoid importing/enabling X-Ray when the daemon address is not set (the
27
- * X-Ray SDK will throw otherwise).
28
- */
29
- const shouldEnableXray = (mode, daemonAddress) => {
30
- if (mode === 'off')
31
- return false;
32
- if (mode === 'on')
33
- return true;
34
- return Boolean(daemonAddress);
35
- };
36
- const captureAwsSdkV3Client = async (client, { mode = 'auto', logger = console, daemonAddress = process.env.AWS_XRAY_DAEMON_ADDRESS, } = {}) => {
37
- if (!shouldEnableXray(mode, daemonAddress))
38
- return client;
39
- if (!daemonAddress) {
40
- throw new Error('X-Ray capture requested but AWS_XRAY_DAEMON_ADDRESS is not set.');
41
- }
42
- // Guarded dynamic import: some X-Ray SDK integrations throw when daemon
43
- // configuration is missing, so do not import unless we are capturing.
44
- let mod;
45
- try {
46
- mod = (await import('aws-xray-sdk'));
47
- }
48
- catch {
49
- throw new Error("X-Ray capture is enabled but 'aws-xray-sdk' is not installed. Install it or set xray to 'off'.");
50
- }
51
- const AWSXRay = (mod.default ?? mod);
52
- if (typeof AWSXRay.captureAWSv3Client !== 'function') {
53
- logger.debug('aws-xray-sdk does not expose captureAWSv3Client', AWSXRay);
54
- throw new Error('aws-xray-sdk missing captureAWSv3Client export.');
55
- }
56
- logger.debug('Enabling AWS X-Ray capture for AWS SDK v3 client.');
57
- return AWSXRay.captureAWSv3Client(client);
58
- };
59
-
60
22
  /**
61
23
  * Requirements addressed:
62
24
  * - Provide a public tools-style wrapper `AwsSecretsManagerTools`.
63
25
  * - Package consumers should not need to construct SecretsManagerClient; they
64
- * should use `AwsSecretsManagerTools.init(...)` and optionally import AWS SDK
65
- * Commands for advanced operations.
26
+ * should construct `new AwsSecretsManagerTools(...)` and optionally import
27
+ * AWS SDK Commands for advanced operations.
66
28
  * - Expose the fully configured SDK client via `tools.client`.
67
29
  * - Support optional AWS X-Ray capture:
68
30
  * - Default “auto”: enable only when AWS_XRAY_DAEMON_ADDRESS is set.
69
31
  * - In “auto”, if the daemon address is set but aws-xray-sdk is missing,
70
32
  * throw with a clear message.
71
- * - Enforce a minimal logger contract (debug/info/warn/error); do not attempt
72
- * to polyfill or proxy unknown loggers.
33
+ * - Enforce the get-dotenv minimal Logger contract (debug/info/warn/error);
34
+ * validate and throw (no polyfills or proxies).
73
35
  * - Secret values are JSON object maps of env vars.
74
36
  */
75
- const assertLogger = (candidate) => {
76
- if (!candidate || typeof candidate !== 'object') {
77
- throw new Error('logger must be an object with debug, info, warn, and error methods');
78
- }
79
- const logger = candidate;
80
- if (typeof logger.debug !== 'function' ||
81
- typeof logger.info !== 'function' ||
82
- typeof logger.warn !== 'function' ||
83
- typeof logger.error !== 'function') {
84
- throw new Error('logger must implement debug, info, warn, and error methods; wrap/proxy your logger if needed');
85
- }
86
- return logger;
87
- };
88
- const parseEnvSecretMap = (secretString) => {
37
+ const parseProcessEnv = (secretString) => {
89
38
  let parsed;
90
39
  try {
91
40
  parsed = JSON.parse(secretString);
@@ -115,7 +64,7 @@ const toSecretString = (value) => JSON.stringify(value);
115
64
  * Tools-style AWS Secrets Manager wrapper for env-map secrets.
116
65
  *
117
66
  * The secret payload is always a JSON object map of environment variables:
118
- * `Record<string, string | undefined>`.
67
+ * `ProcessEnv`.
119
68
  *
120
69
  * Consumers should typically use the convenience methods on this class, and
121
70
  * use {@link AwsSecretsManagerTools.client} as an escape hatch when they need
@@ -138,17 +87,8 @@ class AwsSecretsManagerTools {
138
87
  logger;
139
88
  /** Materialized X-Ray state (mode + enabled + daemonAddress when relevant). */
140
89
  xray;
141
- constructor({ client, clientConfig, logger, xray, }) {
142
- this.client = client;
143
- this.clientConfig = clientConfig;
144
- this.logger = logger;
145
- this.xray = xray;
146
- }
147
90
  /**
148
- * Initialize an `AwsSecretsManagerTools` instance.
149
- *
150
- * This factory owns all setup (including optional X-Ray capture) so consumers
151
- * do not need to construct a base Secrets Manager client themselves.
91
+ * Construct an `AwsSecretsManagerTools` instance.
152
92
  *
153
93
  * @throws If `clientConfig.logger` is provided but does not implement
154
94
  * `debug`, `info`, `warn`, and `error`.
@@ -156,7 +96,7 @@ class AwsSecretsManagerTools {
156
96
  * with `AWS_XRAY_DAEMON_ADDRESS` set) but `aws-xray-sdk` is not installed.
157
97
  * @throws If X-Ray capture is requested but `AWS_XRAY_DAEMON_ADDRESS` is not set.
158
98
  */
159
- static async init({ clientConfig = {}, xray: xrayMode = 'auto', } = {}) {
99
+ constructor({ clientConfig = {}, xray: xrayMode = 'auto', } = {}) {
160
100
  const logger = assertLogger(clientConfig.logger ?? console);
161
101
  const effectiveClientConfig = {
162
102
  ...clientConfig,
@@ -171,18 +111,16 @@ class AwsSecretsManagerTools {
171
111
  ...(enabled && daemonAddress ? { daemonAddress } : {}),
172
112
  };
173
113
  const effectiveClient = enabled
174
- ? await captureAwsSdkV3Client(base, {
114
+ ? captureAwsSdkV3Client(base, {
175
115
  mode: xrayMode,
176
116
  logger,
177
117
  daemonAddress,
178
118
  })
179
119
  : base;
180
- return new AwsSecretsManagerTools({
181
- client: effectiveClient,
182
- clientConfig: effectiveClientConfig,
183
- logger,
184
- xray: xrayState,
185
- });
120
+ this.client = effectiveClient;
121
+ this.clientConfig = effectiveClientConfig;
122
+ this.logger = logger;
123
+ this.xray = xrayState;
186
124
  }
187
125
  /**
188
126
  * Read a Secrets Manager secret and parse it as an env-map secret.
@@ -205,7 +143,7 @@ class AwsSecretsManagerTools {
205
143
  if (!res.SecretString) {
206
144
  throw new Error('SecretString is missing (binary secrets not supported).');
207
145
  }
208
- return parseEnvSecretMap(res.SecretString);
146
+ return parseProcessEnv(res.SecretString);
209
147
  }
210
148
  /**
211
149
  * Write a new version value for an existing secret.
@@ -312,96 +250,6 @@ class AwsSecretsManagerTools {
312
250
  }
313
251
  }
314
252
 
315
- /**
316
- * Requirements addressed:
317
- * - Secret name expansion expands against `{ ...process.env, ...ctx.dotenv }`.
318
- * - include/exclude ignore unknown keys; use radash (no lodash).
319
- */
320
- const buildExpansionEnv = (ctxDotenv) => ({
321
- ...process.env,
322
- ...ctxDotenv,
323
- });
324
- const expandSecretName = (raw, envRef) => dotenvExpand(raw, envRef) ?? raw;
325
- const applyIncludeExclude = (env, { include, exclude, }) => {
326
- let out = env;
327
- if (exclude?.length)
328
- out = omit(out, exclude);
329
- if (include?.length)
330
- out = pick(out, include);
331
- return out;
332
- };
333
-
334
- /**
335
- * Requirements addressed:
336
- * - Enforce AWS Secrets Manager SecretString size limits (65,536 bytes).
337
- * - Provide safe parsing helpers for CLI-mapped inputs.
338
- * - Render config-derived defaults in dynamic option help text.
339
- * - Access aws plugin ctx state via runtime narrowing (no casts).
340
- */
341
- const silentLogger = {
342
- debug: () => {
343
- // no-op
344
- },
345
- info: () => {
346
- // no-op
347
- },
348
- warn: () => {
349
- // no-op
350
- },
351
- error: () => {
352
- // no-op
353
- },
354
- };
355
- const requireString = (v, msg) => {
356
- if (typeof v !== 'string' || !v)
357
- throw new Error(msg);
358
- return v;
359
- };
360
- const toNumber = (v) => {
361
- if (typeof v === 'undefined')
362
- return;
363
- if (typeof v === 'number')
364
- return v;
365
- if (typeof v === 'string' && v.trim())
366
- return Number(v);
367
- return;
368
- };
369
- const assertBytesWithinSecretsManagerLimit = (value) => {
370
- const s = JSON.stringify(value);
371
- const bytes = Buffer.byteLength(s, 'utf8');
372
- if (bytes > 65_536) {
373
- throw new Error(`SecretString size ${String(bytes)} bytes exceeds 65536 bytes; narrow selection with --from/--include/--exclude.`);
374
- }
375
- };
376
- const describeDefault = (v) => {
377
- if (Array.isArray(v))
378
- return v.length ? v.join(' ') : 'none';
379
- if (typeof v === 'string' && v.trim())
380
- return v;
381
- return 'none';
382
- };
383
- const isRecord = (v) => typeof v === 'object' && v !== null;
384
- const getAwsRegion = (ctx) => {
385
- if (!isRecord(ctx.plugins))
386
- return;
387
- const aws = ctx.plugins['aws'];
388
- if (!isRecord(aws))
389
- return;
390
- const region = aws['region'];
391
- return typeof region === 'string' ? region : undefined;
392
- };
393
- const describeConfigKeyListDefaults = ({ cfgInclude, cfgExclude, }) => {
394
- // Avoid throwing in help rendering: show an explicit invalid marker.
395
- if (cfgInclude?.length && cfgExclude?.length) {
396
- const msg = '(invalid: both set in config)';
397
- return { includeDefault: msg, excludeDefault: msg };
398
- }
399
- return {
400
- includeDefault: describeDefault(cfgExclude?.length ? undefined : cfgInclude),
401
- excludeDefault: describeDefault(cfgInclude?.length ? undefined : cfgExclude),
402
- };
403
- };
404
-
405
253
  /**
406
254
  * Requirements addressed:
407
255
  * - Provide `aws secrets delete`.
@@ -431,14 +279,14 @@ const registerDeleteCommand = ({ cli, plugin, }) => {
431
279
  const logger = console;
432
280
  const ctx = cli.getCtx();
433
281
  const cfg = plugin.readConfig(del);
434
- const envRef = buildExpansionEnv(ctx.dotenv);
282
+ const envRef = buildSpawnEnv(process.env, ctx.dotenv);
435
283
  const secretNameRaw = opts.secretName ?? cfg.secretName ?? '$STACK_NAME';
436
- const secretId = expandSecretName(secretNameRaw, envRef);
284
+ const secretId = dotenvExpand(secretNameRaw, envRef);
437
285
  if (!secretId)
438
286
  throw new Error('secret-name is required.');
439
287
  const recoveryWindowInDays = toNumber(opts.recoveryWindowDays);
440
288
  const region = getAwsRegion(ctx);
441
- const tools = await AwsSecretsManagerTools.init({
289
+ const tools = new AwsSecretsManagerTools({
442
290
  clientConfig: region
443
291
  ? { region, logger: sdkLogger }
444
292
  : { logger: sdkLogger },
@@ -715,13 +563,13 @@ const registerPullCommand = ({ cli, plugin, }) => {
715
563
  const privateToken = rootOpts.privateToken ?? 'local';
716
564
  const toRaw = opts.to ?? cfg.pull?.to ?? 'env:private';
717
565
  const to = parseToSelector(toRaw);
718
- const envRef = buildExpansionEnv(ctx.dotenv);
566
+ const envRef = buildSpawnEnv(process.env, ctx.dotenv);
719
567
  const secretNameRaw = opts.secretName ?? cfg.secretName ?? '$STACK_NAME';
720
- const secretId = expandSecretName(secretNameRaw, envRef);
568
+ const secretId = dotenvExpand(secretNameRaw, envRef);
721
569
  if (!secretId)
722
570
  throw new Error('secret-name is required.');
723
- const region = getAwsRegion(ctx);
724
- const tools = await AwsSecretsManagerTools.init({
571
+ const region = getAwsRegion$1(ctx);
572
+ const tools = new AwsSecretsManagerTools({
725
573
  clientConfig: region
726
574
  ? { region, logger: sdkLogger }
727
575
  : { logger: sdkLogger },
@@ -747,7 +595,7 @@ const registerPullCommand = ({ cli, plugin, }) => {
747
595
  ? await editDotenvFile(secrets, {
748
596
  ...editCommon,
749
597
  scope: 'env',
750
- env: requireString(bag.env ?? bag.defaultEnv, 'env is required (use --env or defaultEnv).'),
598
+ env: requireString(bag.env, 'env is required (use --env or defaultEnv).'),
751
599
  })
752
600
  : await editDotenvFile(secrets, {
753
601
  ...editCommon,
@@ -820,16 +668,16 @@ const registerPushCommand = ({ cli, plugin, }) => {
820
668
  cfgInclude: cfg.push?.include,
821
669
  cfgExclude: cfg.push?.exclude,
822
670
  });
823
- const envRef = buildExpansionEnv(ctx.dotenv);
671
+ const envRef = buildSpawnEnv(process.env, ctx.dotenv);
824
672
  const secretNameRaw = opts.secretName ?? cfg.secretName ?? '$STACK_NAME';
825
- const secretId = expandSecretName(secretNameRaw, envRef);
673
+ const secretId = dotenvExpand(secretNameRaw, envRef);
826
674
  if (!secretId)
827
675
  throw new Error('secret-name is required.');
828
676
  const selected = selectEnvByProvenance(ctx.dotenv, ctx.dotenvProvenance, fromSelectors);
829
677
  const secrets = applyIncludeExclude(selected, { include, exclude });
830
- assertBytesWithinSecretsManagerLimit(secrets);
831
- const region = getAwsRegion(ctx);
832
- const tools = await AwsSecretsManagerTools.init({
678
+ assertByteLimit(secrets, 65_536, (v, l) => `SecretString size ${String(v)} bytes exceeds ${String(l)} bytes; narrow selection with --from/--include/--exclude.`);
679
+ const region = getAwsRegion$1(ctx);
680
+ const tools = new AwsSecretsManagerTools({
833
681
  clientConfig: region
834
682
  ? { region, logger: sdkLogger }
835
683
  : { logger: sdkLogger },
package/package.json CHANGED
@@ -13,12 +13,9 @@
13
13
  "url": "https://github.com/karmaniverous/aws-secrets-manager-tools/issues"
14
14
  },
15
15
  "dependencies": {
16
- "@aws-sdk/client-secrets-manager": "^3.958.0",
17
- "@karmaniverous/get-dotenv": "^6.4.0",
18
- "radash": "^12.1.1"
19
- },
20
- "peerDependencies": {
21
- "aws-xray-sdk": "^3.12.0"
16
+ "@aws-sdk/client-secrets-manager": "^3.965.0",
17
+ "@karmaniverous/aws-xray-tools": "^0.2.0",
18
+ "@karmaniverous/get-dotenv": "^7.0.5"
22
19
  },
23
20
  "peerDependenciesMeta": {
24
21
  "aws-xray-sdk": {
@@ -36,7 +33,7 @@
36
33
  "@types/fs-extra": "^11.0.4",
37
34
  "@types/node": "^25.0.3",
38
35
  "@vitest/coverage-v8": "^4.0.16",
39
- "@vitest/eslint-plugin": "^1.6.4",
36
+ "@vitest/eslint-plugin": "^1.6.6",
40
37
  "auto-changelog": "^2.5.0",
41
38
  "aws-xray-sdk": "^3.12.0",
42
39
  "eslint": "^9.39.2",
@@ -45,13 +42,13 @@
45
42
  "eslint-plugin-simple-import-sort": "^12.1.1",
46
43
  "eslint-plugin-tsdoc": "^0.5.0",
47
44
  "fs-extra": "^11.3.3",
48
- "happy-dom": "^20.0.11",
49
- "knip": "^5.78.0",
45
+ "happy-dom": "^20.1.0",
46
+ "knip": "^5.80.0",
50
47
  "lefthook": "^2.0.13",
51
48
  "prettier": "^3.7.4",
52
- "release-it": "^19.2.2",
49
+ "release-it": "^19.2.3",
53
50
  "rimraf": "^6.1.2",
54
- "rollup": "^4.54.0",
51
+ "rollup": "^4.55.1",
55
52
  "rollup-plugin-dts": "^6.3.0",
56
53
  "tslib": "^2.8.1",
57
54
  "tsx": "^4.21.0",
@@ -59,7 +56,7 @@
59
56
  "typedoc-plugin-mdn-links": "^5.0.10",
60
57
  "typedoc-plugin-replace-text": "^4.2.0",
61
58
  "typescript": "^5.9.3",
62
- "typescript-eslint": "^8.51.0",
59
+ "typescript-eslint": "^8.52.0",
63
60
  "vitest": "^4.0.16"
64
61
  },
65
62
  "engines": {
@@ -108,15 +105,15 @@
108
105
  "npm run knip",
109
106
  "npm run build"
110
107
  ],
111
- "before:npm:release": [
112
- "npx auto-changelog -p",
113
- "npm run docs",
114
- "git add -A"
115
- ],
116
108
  "after:release": [
117
109
  "git switch -c release/${version}",
118
110
  "git push -u origin release/${version}",
119
111
  "git switch ${branchName}"
112
+ ],
113
+ "after:bump": [
114
+ "npx auto-changelog -p",
115
+ "npm run docs",
116
+ "git add CHANGELOG.md"
120
117
  ]
121
118
  },
122
119
  "npm": {
@@ -144,5 +141,5 @@
144
141
  },
145
142
  "type": "module",
146
143
  "types": "dist/index.d.ts",
147
- "version": "0.1.1"
144
+ "version": "0.2.1"
148
145
  }