@worktif/purews
v0.4.0
Published
Target Pure AWS – TypeScript-based AWS infrastructure toolkit featuring DynamoDB integration, AppSync support, SES functionality, and GraphQL capabilities with comprehensive audit logging and AWS Signature V4 authentication.
Maintainers
Readme
Contents
- Overview
- Installation
- Runtime Requirements
- Public API
- Usage
- Environment Variables
- Development
- Release Process
- Security
- License
- Maintainer
Overview
@worktif/purews centralizes common AWS infrastructure code used by TypeScript Lambda services:
- Configuration:
EnvConfigPurewsvalidates package-specific environment shape with Zod and extendsEnvConfigDefaultfrom@worktif/utils. - Bundle / DI:
BundlePurewsandbundlePurewsexpose the configured environment and default service accessors. - DynamoDB:
DynamoDbServiceis an abstract base class for table-specific services with typed CRUD/query helpers. - S3:
S3Servicereads S3 object content as UTF-8 text. - SES:
SesServicesends emails and manages SES email verification checks. - Lambda:
lambdaApi,lambdaSqs,composeLambdaLogger,injectApi,injectValidation, andzodValidationMiddlewarestandardize Lambda event parsing, logging, and validation. - Serialization:
SerializerPurewscomposes serializers supplied by@worktif/utils.
This README tracks APIs present in the current src exports.
Installation
npm install @worktif/purewsyarn add @worktif/purewsMost consumers also need reflect-metadata imported once at application startup:
import 'reflect-metadata';Runtime Requirements
- Node.js:
>=20.0.0 - TypeScript: strict mode is supported; this package is built with TypeScript
5.8.x - AWS credentials: resolved from the runtime environment or the execution role used by the workload
- Package manager for this repository: Yarn
1.22.22
Public API
The package root exports:
export * from './config';
export * from './services';
export * from './bundle';
export * from './utils';Bundle and Config
BundlePurewsbundlePurewsPurewsContainerPurewsDiBundleAwsEnvConfigPurewsenvConfigPurewsSchemaEnvConfigPurewsSchema
Services
DynamoDbServiceDynamoEntityAuditLogsAwsSignatureV4HeaderOptionsS3ServiceSesServiceLambdaApiInternalContextInternalContextLoggerInternalContextLoggerServiceLambdaEventApiLambdaEventMethodLambdaEventSqsResponseOptionalFields
Utilities
lambdaApilambdaSqscomposeLambdaLoggerinjectApiinjectValidationzodValidationMiddlewareSerializerPurewsValidationServiceLambdaContext
Usage
Read Validated Environment
import 'reflect-metadata';
import { bundlePurews } from '@worktif/purews';
const env = bundlePurews.env;
console.log(env.aws.credentials.region);Send Email with SES
SesService is registered in the default bundle. SES_NOTIFICATION_EMAIL must be set before sending mail.
import 'reflect-metadata';
import { bundlePurews, SesService } from '@worktif/purews';
const ses = bundlePurews.aws.services.ses as SesService;
await ses.sendEmail(
'<b>Hello from PureWS</b>',
'[email protected]',
'Message from @worktif/purews',
);Create a Table-Specific DynamoDB Service
DynamoDbService is abstract. Extend it for each table and provide tableName.
import 'reflect-metadata';
import {
bundlePurews,
DynamoDbService,
type DynamoEntity,
} from '@worktif/purews';
type User = {
email: string;
name: string;
};
class UserDynamoDbService extends DynamoDbService {
tableName = 'users';
}
const users = new UserDynamoDbService(bundlePurews.env);
const created = await users.put<User>({
email: '[email protected]',
name: 'Ada',
});
const user = created?.id
? await users.get<DynamoEntity<User>>(created.id)
: undefined;
console.log(user);Read an S3 Object as Text
import 'reflect-metadata';
import { bundlePurews, S3Service } from '@worktif/purews';
const s3 = new S3Service(bundlePurews.env);
const content = await s3.getS3ObjectContent({
Bucket: 'example-bucket',
Key: 'path/to/file.txt',
});
console.log(content);Wrap an API Gateway Lambda
lambdaApi parses JSON request bodies for POST requests, normalizes the HTTP method to lowercase, injects AWS Lambda Powertools logger context, and passes the optional internal logger context to the handler.
import 'reflect-metadata';
import { lambdaApi, type LambdaEventApi } from '@worktif/purews';
type CreateUserPayload = {
email: string;
name: string;
};
export const handler = lambdaApi<CreateUserPayload, 'post'>(
async (
event: LambdaEventApi<CreateUserPayload, 'post'>,
_context,
internal,
) => {
internal?.log?.now(
{ body: event.body },
{ message: 'Create user request' },
);
return {
statusCode: 201,
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ created: true }),
};
},
{
logger: {
service: {
entity: 'Users',
name: 'CreateUser',
},
},
},
);Validate a Lambda Body with Zod Middleware
import 'reflect-metadata';
import { z } from 'zod';
import { lambdaApi, zodValidationMiddleware } from '@worktif/purews';
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
});
type CreateUserPayload = z.infer<typeof CreateUserSchema>;
export const handler = lambdaApi<CreateUserPayload, 'post'>(
async (event) => ({
statusCode: 201,
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ email: event.body.email }),
}),
).use(zodValidationMiddleware(CreateUserSchema));Validate Before Calling a Decorated Handler
injectValidation returns a function that can normalize API Gateway or EventBridge payloads before the decorated method receives them.
import 'reflect-metadata';
import { z } from 'zod';
import { injectApi, injectValidation } from '@worktif/purews';
const BodySchema = z.object({
email: z.string().email(),
});
class CreateUserController {
@injectApi(injectValidation({ body: BodySchema }))
async handle(event: { body: z.infer<typeof BodySchema> }) {
return {
statusCode: 200,
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ email: event.body.email }),
};
}
}Environment Variables
The current package-specific configuration is scoped to SES notification email:
| Variable | Required | Used By |
| --- | --- | --- |
| SES_NOTIFICATION_EMAIL | No, but required by SesService.sendEmail | SES source, BCC, and reply-to address |
AWS credential values are read through the inherited default environment configuration:
| Variable | Fallback | Purpose |
| --- | --- | --- |
| AWS_REGION | us-east-1 | AWS client region |
| AWS_ACCESS_KEY_ID | dump in support mode | Explicit AWS access key for non-role execution |
| AWS_SECRET_ACCESS_KEY | dump in support mode | Explicit AWS secret key for non-role execution |
| AWS_SESSION_TOKEN | dump in support mode | Optional AWS session token |
Prefer IAM roles for deployed Lambda workloads. Use explicit credentials only for local development or controlled automation.
Development
Install dependencies:
yarn installGenerate TypeDoc documentation:
yarn docsEmit declaration files:
yarn typesBuild the package:
yarn buildPublish through the configured package script:
yarn publish:npmCurrent repository note: package.json does not define a real test runner; yarn test exits with Error: no test specified. Do not add passing-test badges until a test suite exists and is wired into the package scripts.
Release Process
This package is published to npm as @worktif/purews. Keep releases traceable:
- Implement the change and run the applicable local validation.
- Open a PR and wait for review approval.
- Merge the implementation PR into
main. - Pull the latest
main. - Create a release branch using a semantic-versioned name, for example
releases/v0.3.2-next-release-description. - Bump the version in
package.json. - Open and merge the release PR after required checks pass.
- Pull the latest
mainagain. - Confirm the package version.
- Publish with
yarn publish:npm.
If npm rejects the publish because the version already exists, bump the version and repeat the release branch flow. If publishing fails for another reason, capture the command output, Node/npm/Yarn versions, and CI logs before escalating to the maintainer.
Security
- Do not commit secrets.
- Do not include secrets in examples, tests, fixtures, or generated documentation.
- Prefer IAM roles over long-lived AWS credentials.
- Keep SES source identities verified before sending production mail.
- Report vulnerabilities privately to the maintainer contact below.
License
This package is distributed under the Elastic License 2.0.
- See
LICENSEfor the full license text. - See
NOTICEfor the relicensing notice. - See
THIRD_PARTY_LICENSES.txtif it is distributed with the package artifact.
Maintainers / Contact
- Maintainer: Raman Marozau, [email protected]
- Documentation and support:
docs/generated via TypeDoc
For security reports, please contact [email protected].
