npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@abstraks-dev/aws-helpers

v1.0.0

Published

AWS SDK helpers with caching and retry logic for Secrets Manager and SSM Parameter Store

Readme

@abstraks-dev/aws-helpers

AWS SDK helpers with caching and retry logic for Secrets Manager and SSM Parameter Store.

Features

  • 🔐 Secrets Manager: Retrieve secrets with automatic JSON parsing
  • 📦 SSM Parameter Store: Get single or multiple parameters
  • Caching: 5-minute cache reduces AWS API calls and costs
  • 🔄 Retry Logic: Exponential backoff for transient errors
  • 🎯 Lazy Loading: AWS SDK loaded only when needed
  • 🛡️ Error Handling: Smart retry vs. immediate failure
  • 📊 Cache Management: Clear cache and get statistics
  • 🔌 Drop-in Replacement: Compatible with existing getSecret() patterns

Installation

npm install @abstraks-dev/aws-helpers

Optional Peer Dependencies

Install only what you need:

# For Secrets Manager
npm install @aws-sdk/client-secrets-manager

# For SSM Parameter Store
npm install @aws-sdk/client-ssm

Usage

Secrets Manager - Simple

import { getSecret } from '@abstraks-dev/aws-helpers';

// Get entire JSON secret
const config = await getSecret('app-config');
console.log(config.API_KEY, config.DB_URL);

// Extract specific key from JSON secret
const apiKey = await getSecret('app-config', 'API_KEY');

// Get plain text secret
const token = await getSecret('github-token');

Secrets Manager - With Caching

import { createSecretsManagerHelper } from '@abstraks-dev/aws-helpers';

const secrets = createSecretsManagerHelper({
	region: 'us-west-2',
	cacheTTL: 5 * 60 * 1000, // 5 minutes (default)
	maxRetries: 3, // Default
});

// First call fetches from AWS
const key1 = await secrets.getSecret('app-config', 'API_KEY');

// Second call uses cache (no AWS API call)
const key2 = await secrets.getSecret('app-config', 'API_KEY');

// Clear cache when secrets rotate
secrets.clearCache('app-config');

// Get cache statistics
const stats = secrets.getCacheStats();
console.log(stats); // { size: 2, entries: [...] }

SSM Parameter Store - Single Parameter

import { getParameter } from '@abstraks-dev/aws-helpers';

// Get decrypted parameter
const dbUrl = await getParameter('/app/database-url');

// Get without decryption
const value = await getParameter('/app/config', { withDecryption: false });

SSM Parameter Store - Multiple Parameters

import { createSSMHelper } from '@abstraks-dev/aws-helpers';

const ssm = createSSMHelper({ region: 'us-west-2' });

// Get multiple parameters efficiently
const params = await ssm.getParameters([
	'/app/database-url',
	'/app/api-key',
	'/app/redis-url',
]);

console.log(params['/app/database-url']);
console.log(params['/app/api-key']);

Integration with Existing Code

Drop-in replacement for existing patterns:

// Before: Custom getSecret helper
import { getSecret } from './helpers/secrets.js';

// After: @abstraks-dev/aws-helpers
import { getSecret } from '@abstraks-dev/aws-helpers';

// Same API!
const secret = await getSecret('app-config', 'JWT_SECRET');

API Documentation

createSecretsManagerHelper(options)

Creates a Secrets Manager helper with caching and retry logic.

Parameters:

  • options.region (string, optional): AWS region (default: AWS_REGION env var or 'us-west-2')
  • options.cacheTTL (number, optional): Cache TTL in milliseconds (default: 300000 = 5 minutes)
  • options.maxRetries (number, optional): Maximum retry attempts (default: 3)
  • options.retryDelay (number, optional): Initial retry delay in ms (default: 100)

Returns: Object with methods: getSecret, clearCache, getCacheStats

Example:

const secrets = createSecretsManagerHelper({
	region: 'us-west-2',
	cacheTTL: 10 * 60 * 1000, // 10 minutes
	maxRetries: 5,
	retryDelay: 200,
});

helper.getSecret(secretName, key)

Retrieves a secret from AWS Secrets Manager with caching.

Parameters:

  • secretName (string, required): Name or ARN of the secret
  • key (string, optional): Key to extract from JSON secret

Returns: Promise<string | object>

Behavior:

  • Returns full object if secret is JSON and no key provided
  • Returns specific value if key provided
  • Returns raw string for non-JSON secrets
  • Throws if trying to extract key from non-JSON secret

Example:

// JSON secret: {"API_KEY": "abc123", "DB": "mongodb://..."}
const fullConfig = await helper.getSecret('app-config');
// Returns: { API_KEY: 'abc123', DB: 'mongodb://...' }

const apiKey = await helper.getSecret('app-config', 'API_KEY');
// Returns: 'abc123'

// Plain text secret
const token = await helper.getSecret('github-token');
// Returns: 'ghp_abc123...'

helper.clearCache(secretName)

Clears cached secrets.

Parameters:

  • secretName (string, optional): Secret name to clear (clears all if omitted)

Example:

// Clear specific secret (including all keys)
helper.clearCache('app-config');

// Clear all cached secrets
helper.clearCache();

helper.getCacheStats()

Returns cache statistics.

Returns: Object with size (number) and entries (array of strings)

Example:

const stats = helper.getCacheStats();
console.log(stats.size); // 3
console.log(stats.entries); // ['secret1:KEY1', 'secret2', 'secret3:KEY2']

createSSMHelper(options)

Creates an SSM Parameter Store helper with caching and retry logic.

Parameters:

  • options.region (string, optional): AWS region (default: AWS_REGION env var or 'us-west-2')
  • options.cacheTTL (number, optional): Cache TTL in milliseconds (default: 300000 = 5 minutes)
  • options.maxRetries (number, optional): Maximum retry attempts (default: 3)
  • options.retryDelay (number, optional): Initial retry delay in ms (default: 100)

Returns: Object with methods: getParameter, getParameters, clearCache, getCacheStats


helper.getParameter(name, options)

Retrieves a parameter from SSM Parameter Store with caching.

Parameters:

  • name (string, required): Parameter name or path
  • options.withDecryption (boolean, optional): Decrypt SecureString (default: true)

Returns: Promise

Example:

const dbUrl = await helper.getParameter('/app/database-url');

const publicConfig = await helper.getParameter('/app/version', {
	withDecryption: false,
});

helper.getParameters(names, options)

Retrieves multiple parameters efficiently with caching.

Parameters:

  • names (string[], required): Array of parameter names
  • options.withDecryption (boolean, optional): Decrypt SecureString (default: true)

Returns: Promise - Map of parameter names to values

Behavior:

  • Uses cache for already-fetched parameters
  • Fetches uncached parameters in single AWS API call
  • Caches all fetched parameters

Example:

const params = await helper.getParameters([
	'/app/db-url',
	'/app/api-key',
	'/app/redis-url',
]);

console.log(params['/app/db-url']);

Simple Wrapper Functions

getSecret(secretName, key, options)

Simple wrapper for one-off secret retrieval (no persistent cache).

Example:

import { getSecret } from '@abstraks-dev/aws-helpers';

const secret = await getSecret('app-config', 'API_KEY', {
	region: 'us-west-2',
});

getParameter(name, options)

Simple wrapper for one-off parameter retrieval (no persistent cache).

Example:

import { getParameter } from '@abstraks-dev/aws-helpers';

const value = await getParameter('/app/config');

Caching Strategy

How Caching Works

  1. First Request: Fetches from AWS, stores in memory with timestamp
  2. Subsequent Requests: Returns cached value if within TTL
  3. After TTL: Fetches fresh value from AWS, updates cache
  4. Per-Container: Each Lambda container has independent cache

Cache Benefits

const secrets = createSecretsManagerHelper({ cacheTTL: 5 * 60 * 1000 });

await secrets.getSecret('config', 'KEY'); // AWS API call
await secrets.getSecret('config', 'KEY'); // Cache (0ms)
await secrets.getSecret('config', 'KEY'); // Cache (0ms)

// After 5 minutes...
await secrets.getSecret('config', 'KEY'); // Fresh fetch from AWS

Performance Impact:

  • ✅ Reduces AWS API calls by ~90%+
  • ✅ Saves $0.05 per 10,000 requests (Secrets Manager pricing)
  • ✅ Improves Lambda response time (cache: <1ms vs AWS: 50-100ms)
  • ✅ Reduces throttling risk

Considerations:

  • ⚠️ Secret rotation takes up to TTL to propagate
  • ⚠️ Cache is per-container (not shared across containers)
  • ⚠️ Cold starts always fetch fresh secrets
  • ⚠️ Call clearCache() after manual secret updates

Retry Logic

Automatic Retries

The package automatically retries transient errors with exponential backoff:

const helper = createSecretsManagerHelper({
	maxRetries: 3,
	retryDelay: 100, // Initial delay
});

// Retry delays: 100ms, 200ms, 400ms
// Total max wait: 700ms before giving up

Errors That Are Retried

  • ServiceUnavailableException
  • ThrottlingException
  • InternalServiceErrorException
  • Network timeouts and connection errors

Errors That Are NOT Retried

  • AccessDeniedException (permission issue)
  • ResourceNotFoundException (secret/parameter doesn't exist)
  • ValidationException (bad request)

Why? These errors won't be fixed by retrying.

Migration Guide

From Social/Media Service Pattern

Before:

// helpers/secrets.js
import {
	SecretsManagerClient,
	GetSecretValueCommand,
} from '@aws-sdk/client-secrets-manager';

const client = new SecretsManagerClient({ region: 'us-west-2' });

export async function getSecret(secretName, key) {
	try {
		const command = new GetSecretValueCommand({
			SecretId: secretName,
			VersionStage: 'AWSCURRENT',
		});
		const response = await client.send(command);
		const secretString = response.SecretString;

		try {
			const secretObj = JSON.parse(secretString);
			return key ? secretObj[key] : secretObj;
		} catch (e) {
			return secretString;
		}
	} catch (error) {
		console.error(`Error retrieving secret ${secretName}:`, error);
		throw error;
	}
}

After:

import { createSecretsManagerHelper } from '@abstraks-dev/aws-helpers';

export const secrets = createSecretsManagerHelper({ region: 'us-west-2' });
export const getSecret = secrets.getSecret.bind(secrets);

Or just replace imports:

// Before
import { getSecret } from './helpers/secrets.js';

// After
import { getSecret } from '@abstraks-dev/aws-helpers';

Benefits:

  • ✅ 5-minute caching (80-90% fewer AWS calls)
  • ✅ Automatic retry with exponential backoff
  • ✅ Lazy AWS SDK loading (faster cold starts)
  • ✅ Cache management and statistics
  • ✅ Same API, drop-in compatible

Best Practices

1. Reuse Helper Instances

// Good: Single instance with shared cache
const secrets = createSecretsManagerHelper();
export const getSecret = secrets.getSecret.bind(secrets);

// Avoid: New instance every time (no cache benefit)
function getSecret(name, key) {
	const helper = createSecretsManagerHelper();
	return helper.getSecret(name, key);
}

2. Use Appropriate Cache TTL

// Production secrets (rotate monthly)
const secrets = createSecretsManagerHelper({
	cacheTTL: 10 * 60 * 1000, // 10 minutes
});

// Development secrets (rotate frequently)
const secrets = createSecretsManagerHelper({
	cacheTTL: 60 * 1000, // 1 minute
});

// High-security (no caching)
const secrets = createSecretsManagerHelper({
	cacheTTL: 0, // Always fetch fresh
});

3. Handle Secret Rotation

// After rotating secret in AWS console
secrets.clearCache('app-config'); // Force fresh fetch

4. Batch Parameter Fetches

// Good: Single API call
const params = await ssm.getParameters(['/app/db', '/app/key', '/app/url']);

// Avoid: Multiple API calls
const db = await ssm.getParameter('/app/db');
const key = await ssm.getParameter('/app/key');
const url = await ssm.getParameter('/app/url');

5. Monitor Cache Effectiveness

const stats = secrets.getCacheStats();
console.log(`Cache size: ${stats.size}`);
console.log(`Cached entries: ${stats.entries.join(', ')}`);

// Log in CloudWatch for monitoring

Troubleshooting

"AWS Secrets Manager SDK not installed"

Cause: Missing peer dependency.

Solution:

npm install @aws-sdk/client-secrets-manager

"Access denied" / "AccessDeniedException"

Cause: Lambda execution role lacks permissions.

Solution: Add IAM policy:

{
	"Effect": "Allow",
	"Action": ["secretsmanager:GetSecretValue"],
	"Resource": "arn:aws:secretsmanager:REGION:ACCOUNT:secret:SECRET_NAME-*"
}

"Secret not found" / "ResourceNotFoundException"

Cause: Secret doesn't exist or wrong name/region.

Solution:

  • Verify secret name (case-sensitive)
  • Check region matches
  • Confirm secret exists: aws secretsmanager list-secrets

"Throttling" Errors

Cause: Too many AWS API calls.

Solution: Increase cache TTL:

const secrets = createSecretsManagerHelper({
	cacheTTL: 10 * 60 * 1000, // Increase from 5 to 10 minutes
});

Secrets Not Updating After Rotation

Cause: Cache still has old value.

Solution:

// Clear cache after rotation
secrets.clearCache('app-config');

// Or reduce cache TTL for frequently-rotated secrets
const secrets = createSecretsManagerHelper({
	cacheTTL: 60 * 1000, // 1 minute
});

Performance Characteristics

| Operation | Without Cache | With Cache | Improvement | | ------------------------ | ------------- | ---------- | ------------------ | | getSecret (first call) | 50-100ms | 50-100ms | - | | getSecret (cached) | 50-100ms | <1ms | 50-100x faster | | API calls (100 requests) | 100 | ~2-5 | 20-50x fewer | | Cost (1M requests) | $400 | $8-20 | 20-50x cheaper |

Note: Actual performance depends on AWS region, network latency, and secret size.

License

MIT