@johnmmackey/app-toolkit
v0.5.1
Published
A collection of shared utility functions
Downloads
75
Readme
app-toolkit
A collection of shared utility functions for common application tasks.
Installation
npm install @johnmmackey/app-toolkitUsage
import {
getLogger, setBaseLevel, setDebugModules,
getAssumedRoleCredentials,
HttpRouteHandlerError,
SystemsManager,
} from '@johnmmackey/app-toolkit';Development
Prerequisites
- Node.js >= 18
- npm >= 9
Setup
npm installScripts
| Command | Description |
|---|---|
| npm run build | Compile TypeScript to dist/ |
| npm run dev | Build in watch mode |
| npm test | Run tests |
| npm run test:watch | Run tests in watch mode |
| npm run typecheck | Type-check without emitting |
| npm run lint | Lint source files |
Project Structure
app-toolkit/
├── src/
│ ├── index.ts # Public API entry point
│ ├── logger.ts # Winston logger utilities
│ ├── aws-role-credentials.ts # STS role assumption
│ ├── SystemsManager.ts # AWS SSM parameter store
│ ├── HttpRouteHandlerError.ts # HTTP-aware error class
│ └── types/
│ └── index.ts # Shared type re-exports
├── dist/ # Compiled output (generated)
├── package.json
├── tsconfig.json
└── README.mdAPI
getLogger(label: string): Logger
Returns a Winston child logger bound to the given module label.
Every log entry is emitted as structured JSON with a timestamp and label field, ready to be ingested by any log aggregator.
import { getLogger } from '@johnmmackey/app-toolkit';
const log = getLogger('my-module');
log.info('server started', { port: 3000 });
// → {"level":"info","label":"my-module","port":3000,"timestamp":"..."}
log.error('unexpected failure', new Error('oops'));
// → {"level":"error","label":"my-module","message":"oops","stack":"...","timestamp":"..."}Environment variables
| Variable | Default | Description |
|---|---|---|
| LOG_LEVEL | "info" | Global log level (error | warn | info | debug) |
| APP_DEBUG_MODULES | — | Space-separated list of micromatch glob patterns. Any logger whose label matches is promoted to debug level regardless of LOG_LEVEL. |
# promote only the "db" and "auth-*" loggers to debug
APP_DEBUG_MODULES="db auth-*" node dist/server.jssetBaseLevel(level: string): void
Changes the log level on all existing child loggers at runtime.
import { setBaseLevel } from '@johnmmackey/app-toolkit';
setBaseLevel('debug');setDebugModules(patterns: string[]): void
Promotes any logger whose label matches one of the provided micromatch glob patterns to debug level.
import { setDebugModules } from '@johnmmackey/app-toolkit';
setDebugModules(['db', 'auth-*']);getAssumedRoleCredentials(roleArn: string, region?: string): Promise<AwsCredentialIdentity>
Assumes an AWS IAM role via STS and returns temporary credentials. Results are cached in-process and automatically refreshed 5 minutes before expiry.
| Parameter | Type | Default | Description |
|---|---|---|---|
| roleArn | string | — | ARN of the role to assume (required) |
| region | string | "us-east-1" | AWS region for the STS API call |
import { getAssumedRoleCredentials } from '@johnmmackey/app-toolkit';
const creds = await getAssumedRoleCredentials(
'arn:aws:iam::123456789012:role/MyRole',
'eu-west-1',
);
// Pass credentials to any AWS SDK client
import { S3Client } from '@aws-sdk/client-s3';
const s3 = new S3Client({ credentials: creds, region: 'eu-west-1' });or, since credentials can by an async function,
import { getAssumedRoleCredentials } from '@johnmmackey/app-toolkit';
// Pass credentials to any AWS SDK client
import { S3Client } from '@aws-sdk/client-s3';
const s3 = new S3Client({ credentials: async () => getAssumedRoleCredentials(arn)});Credential resolution (STS client)
- Dev: relies on environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) or a shared credentials file. - Prod / ECS / Lambda: relies on the instance / task metadata service (IMDSv2).
HttpRouteHandlerError
An Error subclass that carries an HTTP status code. Intended to be caught by route-level error handlers.
import { HttpRouteHandlerError } from '@johnmmackey/app-toolkit';
throw new HttpRouteHandlerError('Not found', 404);
throw new HttpRouteHandlerError('Something went wrong'); // defaults to 500| Property | Type | Description |
|---|---|---|
| message | string | Error description |
| code | number | HTTP status code (default 500) |
SystemsManager
A class that loads and caches application configuration from AWS Systems Manager Parameter Store. Parameters are fetched under the path /{appName}/{envName}/ and can be overridden by environment variables of the same name.
new SystemsManager(appName, envName, roleArn)
| Parameter | Type | Description |
|---|---|---|
| appName | string | Application name (first path segment) |
| envName | string | Environment name, e.g. "prod" (second path segment) |
| roleArn | string | ARN of the IAM role to assume for SSM access |
import { SystemsManager } from '@johnmmackey/app-toolkit';
const config = new SystemsManager(
'my-app',
'prod',
'arn:aws:iam::123456789012:role/SsmReadRole'
);config.loadSystemParameters(): Promise<void>
Fetches all parameters for the configured app/env path. Must be called once at application startup before any get* method.
await config.loadSystemParameters();config.getSystemParameter(name): string
Returns the string value of a named parameter. Throws if the parameter is a StringList.
const dbUrl = config.getSystemParameter('DATABASE_URL');config.findSystemParameter(name): string | undefined
Returns the string value of a named parameter, or undefined if the parameter is missing or is not a plain string.
const dbUrl = config.findSystemParameter('DATABASE_URL');
if (dbUrl) {
// use DATABASE_URL
}config.getSystemParameterArray(name): string[]
Returns the value of a StringList parameter as a string[]. Throws if the parameter is a plain string.
const allowedOrigins = config.getSystemParameterArray('ALLOWED_ORIGINS');config.findSystemParameterArray(name): string[] | undefined
Returns the value of a StringList parameter as a string[], or undefined if the parameter is missing or is not an array.
const allowedOrigins = config.findSystemParameterArray('ALLOWED_ORIGINS') ?? [];config.loggableSystemParameters(): Record<string, SystemParameter>
Returns a snapshot of all cached parameters safe for logging — SecureString values are masked, showing only the first and last 4 characters.
const log = getLogger('startup');
log.info('loaded config', config.loggableSystemParameters());Types
The package exports the AppToolkitTypes namespace for consumers that want stable type-only imports from the public entrypoint.
import type { AppToolkitTypes } from '@johnmmackey/app-toolkit';
type MyLogger = AppToolkitTypes.AppLogger;
type AwsCreds = AppToolkitTypes.AwsCredentialIdentity;| Type | Source | Description |
|---|---|---|
| AppToolkitTypes.AppLogger | winston | Winston Logger instance type |
| AppToolkitTypes.AwsCredentialIdentity | @aws-sdk/types | AWS temporary credential shape |
Contributing
- Create a feature branch from
main - Make your changes with tests
- Run
npm testandnpm run typecheckto verify - Open a pull request
Changelog
See CHANGELOG.md.
License
MIT
