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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@worktif/purews

v0.2.20

Published

Work TIF TypeScript-based AWS infrastructure toolkit featuring DynamoDB integration, AppSync support, SES functionality, and GraphQL capabilities with comprehensive audit logging and AWS Signature V4 authentication.

Readme

@worktif/purews

Enterprise-grade TypeScript utilities for AWS-centric serverless systems. Provides a composable DI-powered bundle with batteries-included services for DynamoDB, AppSync (GraphQL), SES, S3, Lambda middy middlewares, Zod validation, and environment configuration via Zod.

npm version Node Support TypeScript License


Overview

@worktif/purews is a production-ready utility toolkit designed for critical workloads (financial, cloud-native, distributed systems). It standardizes how you wire AWS services, validate configuration, instrument Lambdas, and execute GraphQL/DynamoDB/S3/SES operations with consistent logging and error semantics.

It emphasizes:

  • Strong typing with TypeScript
  • Deterministic environment/config validation (Zod)
  • Inversion of control and factory-based DI
  • Reliable logging + structured middlewares
  • Low-overhead, testable service classes

Key Features

  • Dependency Injection Bundle
    • Pure container with explicit bindings for env/config and AWS services
  • Configuration
    • Zod-validated env schema for AWS AppSync and SES; dotenv support
  • AWS Services
    • DynamoDbService (abstract): typed CRUD helpers, update expression generator
    • AppSyncService: typed GraphQL query/mutation with serializer hooks
    • SesService: verify and send emails, verified-address checks
    • S3Service: safe object read to string
  • Lambda Utilities
    • middy-based handlers for API Gateway and SQS
    • Request parsing, logger injection, request-id correlation, Zod middleware
    • Decorators: API injection, validation injector
  • GraphQL Utils
    • Types for internal GraphQL shapes; helpers for enum/case transformations
  • Serialization
    • Composable serializer for API and GraphQL payloads
  • Observability
    • Consistent logging via AWS Powertools logger with contextual metadata

Installation

# npm
npm install @worktif/purews

# yarn
yarn add @worktif/purews

Peer assumptions:


Usage

Basic bootstrapping

import 'reflect-metadata';

import { bundlePurews } from '@worktif/purews';

// Access DI-provisioned services
const { appSync, ses, dynamoDb } = bundlePurews.aws.services;
// Access validated environment
const env = bundlePurews.env;

console.log(env.aws.credentials.region);

AppSync GraphQL query

import { AppSyncService } from '@worktif/purews';

const appSync = bundlePurews.aws.services.appSync as AppSyncService;

const query = `
  query GetItem($id: ID!) {
    getItem(id: $id) {
      id
      name
      updatedAt
    }
  }
`;

const result = await appSync.query<{ id: string; name: string; updatedAt: string }>({
  query,
  payload: { id: 'abc-123' }, // Variables
});

console.log(result.data); // { id, name, updatedAt }

AppSync GraphQL mutation with serializer

import { identityToNull, identityToVoid } from '@worktif/utils';

const mutation = `
  mutation UpdateItem($input: UpdateItemInput!, $condition: ModelItemConditionInput) {
    updateItem(input: $input, condition: $condition) {
      id
      name
      updatedAt
    }
  }
`;

const updated = await appSync.mutate<{ id: string; name: string }>({
  mutation,
  payload: { id: 'abc-123', name: 'New Name' },
}, {
  serializer: identityToNull,
  deserializer: identityToVoid,
});

console.log(updated.data.updateItem);

SES: send email

import { SesService } from '@worktif/purews';

const ses = bundlePurews.aws.services.ses as SesService;
await ses.sendEmail('<b>Hello</b> from PureWS', '[email protected]', 'Subject');

S3: read object

import { S3Service } from '@worktif/purews';

const s3 = new S3Service(bundlePurews.env);
const content = await s3.getS3ObjectContent({ Bucket: 'my-bucket', Key: 'path/to/file.txt' });
console.log(content);

Lambda API handler with middy

import { lambdaApi } from '@worktif/purews';

type Payload = { id: string };

export const handler = lambdaApi<Payload, 'post'>(
  async (event, context, internal) => {
    internal?.log?.now({ body: event.body }, { message: 'Handling POST' });
    return {
      statusCode: 200,
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ ok: true, id: event.body.id }),
    };
  },
  {
    logger: { service: { entity: 'Example', name: 'CreateItem' } },
  }
);

Validation decorator and middleware

import { z } from 'zod';

import { injectApi, injectValidation } from '@worktif/purews';
import { lambdaApi } from '@worktif/purews';

const BodySchema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
});

const withValidation = injectValidation({ body: BodySchema });

export const handler = lambdaApi<{ email: string; name: string }, 'post'>(
  async (event) => {
    // event.body is typed and validated
    return {
      statusCode: 201,
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ created: true }),
    };
  },
  { logger: { service: { entity: 'Users', name: 'CreateUser' } } }
).before(withValidation);

API Reference

  • Bundle and DI
    • class BundlePurews
      • aws.services: { dynamoDb: DynamoDbService, appSync: AppSyncService, ses: SesService }
      • env: EnvConfigPurews
  • Environment Config
    • class EnvConfigPurews extends EnvConfigDefault
      • aws.appSync: { appId?: string; apiKey?: string; appUrl?: string; appRealTimeUrl?: string }
      • aws.ses: { notificationEmail?: string }
      • Validates from process.env:
        • AWS_APP_SYNC_APP_ID,
        • AWS_APP_SYNC_API_KEY,
        • AWS_APP_SYNC_APP_URL,
        • AWS_APP_SYNC_APP_REAL_TIME_URL,
        • SES_NOTIFICATION_EMAIL
  • DynamoDbService (abstract) – Service is development
    • tableName: string
    • put<T>(payload: Partial<DynamoEntity<T>>): Promise<T | undefined>
    • get<T>(id: string): Promise<T | undefined>
    • update<T extends DynamoEntity<object>>(payload: Partial<DynamoEntity<T>>): Promise<T | undefined>
    • delete<T extends DynamoEntity<object>>(payload: Partial<T>): Promise<Partial<T> | undefined>
    • queryByAttribute<T>(options: QueryByAttrOptions): Promise<T[] | undefined>
    • scanFinder<T>(): Promise<T[] | undefined>
    • static generateExpressionForUpdate<T>(payload, listAttributes?): { updateExpression: string; expressionAttributeValues: Record<string, unknown> }
    • Types:
      • DynamoEntity<T> = T & { id: string; createdAt?: string | null; updatedAt?: string | null }
  • AppSyncService
    • query<TResult, TVariables>(args: { query: string; payload: TVariables }, serializer?: GraphQlSerializer): Promise<GqlQueryResult<TResult>>
    • mutate<TResult, TVariables>(args: { mutation: string; payload: TVariables; conditions?: ModelConditionInput<TResult> }, serializer?: GraphQlSerializer): Promise<GqlMutationResult<TResult>>
    • GraphQlSerializer: { serializer?: (variables) => any; deserializer?: (result) => any }
    • Internals:
      • parses input variable names and output key from DocumentNode
  • SesService
    • sendEmail(messageHtml: string, toAddress: string, subject?: string): Promise<SendEmailCommandOutput>
    • verifyEmailAddress(email: string): Promise<void>
    • isEmailAddressVerified(email: string): Promise<boolean>
  • S3Service
    • getS3ObjectContent({ Bucket, Key }: { Bucket: string; Key: string }): Promise<string | undefined>
  • Lambda utilities
    • lambdaApi<T, TMethod>(handler, internalContext?, schema?): Middy handler for API Gateway
    • lambdaSqs<T>(handler, internalContext?): Middy handler for SQS
    • injectApi(injectFunction, injectCatchFunction?): MethodDecorator to pre-parse body and handle catches
    • injectValidation(schemas, service?): returns function(event, context) to validate body/path with Zod
    • zodValidationMiddleware(schema): middy before middleware that validates event.body
    • Types:
      • LambdaEventApi<T, TMethod>,
      • LambdaEventMethod,
      • LambdaEventSqs<T>,
      • ValidationService

Use Cases

  • Payments/Financial Services
    • Deterministic GraphQL mutations to AppSync with safe serializers; strict audit fields on Dynamo entities
  • Multi-tenant SaaS
    • Composable DI container to wire per-tenant configuration sources; consistent SES notifications and verification
  • Data Pipelines
    • SQS consumer lambdas using lambdaSqs with uniform logging, Zod validation per record schema
  • API Gateways at scale
    • lambdaApi with standard parsing, logging context injection, error wrapping; easy adoption of Zod validation middleware
  • Regulated environments
    • Zod-validated env eliminates misconfiguration class; serializer boundaries for IO control; consistent logger metadata

Design Principles

  • Type-first: all public APIs are strongly typed, including GraphQL and Dynamo helpers
  • Composability: DI container + service factories to swap/test components
  • Functional boundaries: pure serializers, explicit side-effect services
  • Predictable IO: Zod validation at boundaries; identity serializers as defaults
  • Low-latency: AWS SDK v3 usage, disabled AppSync offline cache, lightweight middlewares
  • Observability: structured logs with contextual service names and stages

Best Practices

  • Export concrete DynamoDB services by extending DynamoDbService and setting tableName
  • Always validate env in CI: boot bundle in a smoke test to fail-fast on missing vars
  • Keep GraphQL operations typed with TResult and TVariables; use serializer to normalize cases
  • Use lambdaApi for all API Gateway handlers to standardize parsing/logging
  • Keep SES notificationEmail verified; call verifyEmailAddress in provisioning workflows

Compatibility and Performance

  • Node.js: 18+ recommended
  • AppSync: AUTH_TYPE.API_KEY supported; pluggable if you extend for Cognito/JWT
  • DynamoDB: AWS SDK v3 (lib-dynamodb); uses DocumentClient marshalling with removeUndefinedValues
  • Performance notes:
    • Query/mutate configured with no cache thrash and typenames disabled
    • Dynamo batch/get/update paths minimize marshalling overhead
    • Middy handlers inject logger once, avoiding repeated construction

Contributing

This section is intended for external publishers responsible for releasing the package to npm. Follow the sequence precisely to ensure auditability, semantic versioning integrity, and a clean release trail.

  • Authenticate to the scoped registry
    • npm login --scope=@worktif
    • If you encounter a TLS/registry error, set the registry explicitly:
      • npm config set registry https://registry.npmjs.org/
  • Complete your enhancement
    • Implement and locally validate your changes (types, build, docs as applicable).
  • Open a Pull Request (PR)
    • Submit your changes for review.
    • Await approval before proceeding.
  • Merge the PR
    • After approval, merge into main using your standard merge policy.
  • Synchronize your local main
    • git checkout main
    • git pull to ensure you’re up to date.
  • Prepare a release branch
    • Create a branch using the release template:
      • releases/v[your.semantic.version-[pre+[meta]]]-next-release-description
  • Bump the version
    • Update the package version according to SemVer (major/minor/patch).
  • Commit the version bump to the release branch
    • Commit only the version change (and any generated artifacts if required by your policy).
  • Push the release branch
    • Push the branch to the remote to trigger any CI gates.
  • Open a Release PR
    • Create a PR from the release branch to main.
    • Await approval and required checks.
  • Merge the Release PR
    • Merge into main after approvals and passing checks.
  • Final synchronization
    • Pull the latest changes from main locally.
  • Validate the version in package.json
    • Ensure the version reflects the intended release.
  • Publish
    • If the version was not increased (npm will reject):
      • Bump the version, commit, and then run yarn run publish:npm.
    • If the version has been increased and publishing fails unexpectedly:
      • Contact the maintainer at [email protected] with context (command output, Node/npm versions, CI logs).

Successful publish output resembles:

+ @worktif/purews@[your.semantic.version-[pre+[meta]]]
✨  Done in 28.81s.

Security and responsible disclosure

  • Do not commit secrets
  • Do not include secrets in tests or examples
  • Report vulnerabilities privately to the maintainers contact below
  • Use .npmrc with correct registry config for scoped publish
  • New services must include error translation via CustomException and structured logs

License

This project is licensed under the Elastic License 2.0.

  • See LICENSE for the full license text.
  • See NOTICE for attribution and relicensing details (re-licensed from BUSL-1.1 on 2025-09-15).
  • See THIRD_PARTY_LICENSES.txt for third-party attributions and license texts.

Rationale:

  • Suitable for commercial use with restrictions on offering as a managed service; fit for enterprise deployments requiring source access with guardrails.

Maintainers / Contact

  • Maintainer: Raman Marozau, [email protected]
  • Documentation and support: docs/ generated via TypeDoc

For security reports, please contact [email protected].