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

@cipherstash/protect-dynamodb

v9.0.0

Published

Protect.js DynamoDB Helpers

Downloads

2,547

Readme

Protect.js DynamoDB Helpers

Helpers for using CipherStash Protect.js with DynamoDB.

Built by CipherStash NPM version License

Installation

npm install @cipherstash/protect-dynamodb
# or
yarn add @cipherstash/protect-dynamodb
# or
pnpm add @cipherstash/protect-dynamodb

Quick Start

import { protectDynamoDB } from '@cipherstash/protect-dynamodb'
import { protect, csColumn, csTable } from '@cipherstash/protect'
import { PutCommand, GetCommand } from '@aws-sdk/lib-dynamodb'

// Define your protected table schema
const users = csTable('users', {
  email: csColumn('email').equality(),
})

// Initialize the Protect client
const protectClient = await protect({
  schemas: [users],
})

// Create the DynamoDB helper instance
const protectDynamo = protectDynamoDB({
  protectClient,
})

// Encrypt and store a user
const user = {
  email: '[email protected]',
}

const encryptResult = await protectDynamo.encryptModel(user, users)
if (encryptResult.failure) {
  throw new Error(`Failed to encrypt user: ${encryptResult.failure.message}`)
}

// Store in DynamoDB
await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: encryptResult.data,
}))

// Create search terms for querying
const searchTermsResult = await protectDynamo.createSearchTerms([
  {
    value: '[email protected]',
    column: users.email,
    table: users,
  },
])

if (searchTermsResult.failure) {
  throw new Error(`Failed to create search terms: ${searchTermsResult.failure.message}`)
}

// Query using the search term
const [emailHmac] = searchTermsResult.data
const result = await docClient.send(new GetCommand({
  TableName: 'Users',
  Key: { email__hmac: emailHmac },
}))

if (!result.Item) {
  throw new Error('Item not found')
}

// Decrypt the result
const decryptResult = await protectDynamo.decryptModel<User>(
  result.Item,
  users,
)

if (decryptResult.failure) {
  throw new Error(`Failed to decrypt user: ${decryptResult.failure.message}`)
}

const decryptedUser = decryptResult.data

Features

Encryption and Decryption

The package provides methods to encrypt and decrypt data for DynamoDB:

  • encryptModel: Encrypts a single model
  • bulkEncryptModels: Encrypts multiple models in bulk
  • decryptModel: Decrypts a single model
  • bulkDecryptModels: Decrypts multiple models in bulk

All methods return a Result type that must be checked for failures:

const result = await protectDynamo.encryptModel(user, users)
if (result.failure) {
  // Handle error
  console.error(result.failure.message)
} else {
  // Use encrypted data
  const encryptedData = result.data
}

Search Terms

Create search terms for querying encrypted data:

  • createSearchTerms: Creates search terms for one or more columns
const searchTermsResult = await protectDynamo.createSearchTerms([
  {
    value: '[email protected]',
    column: users.email,
    table: users,
  },
])

if (searchTermsResult.failure) {
  throw new Error(`Failed to create search terms: ${searchTermsResult.failure.message}`)
}

const [emailHmac] = searchTermsResult.data

DynamoDB Integration

The package automatically handles:

  • Converting encrypted data to DynamoDB's format
  • Adding HMAC attributes for searchable fields
  • Preserving unencrypted fields
  • Converting DynamoDB items back to encrypted format for decryption

Usage Patterns

Simple Table with Encrypted Fields

const users = csTable('users', {
  email: csColumn('email').equality(),
})

// Encrypt and store
const encryptResult = await protectDynamo.encryptModel({
  pk: 'user#1',
  email: '[email protected]',
}, users)

if (encryptResult.failure) {
  throw new Error(`Failed to encrypt user: ${encryptResult.failure.message}`)
}

// Query using search terms
const searchTermsResult = await protectDynamo.createSearchTerms([
  {
    value: '[email protected]',
    column: users.email,
    table: users,
  },
])

if (searchTermsResult.failure) {
  throw new Error(`Failed to create search terms: ${searchTermsResult.failure.message}`)
}

Encrypted Partition Key

// Table with encrypted partition key
const table = {
  TableName: 'Users',
  AttributeDefinitions: [
    {
      AttributeName: 'email__hmac',
      AttributeType: 'S',
    },
  ],
  KeySchema: [
    {
      AttributeName: 'email__hmac',
      KeyType: 'HASH',
    },
  ],
}

// Create search terms for querying
const searchTermsResult = await protectDynamo.createSearchTerms([
  {
    value: '[email protected]',
    column: users.email,
    table: users,
  },
])

if (searchTermsResult.failure) {
  throw new Error(`Failed to create search terms: ${searchTermsResult.failure.message}`)
}

const [emailHmac] = searchTermsResult.data

Encrypted Sort Key

// Table with encrypted sort key
const table = {
  TableName: 'Users',
  AttributeDefinitions: [
    {
      AttributeName: 'pk',
      AttributeType: 'S',
    },
    {
      AttributeName: 'email__hmac',
      AttributeType: 'S',
    },
  ],
  KeySchema: [
    {
      AttributeName: 'pk',
      KeyType: 'HASH',
    },
    {
      AttributeName: 'email__hmac',
      KeyType: 'RANGE',
    },
  ],
}

// Create search terms for querying
const searchTermsResult = await protectDynamo.createSearchTerms([
  {
    value: '[email protected]',
    column: users.email,
    table: users,
  },
])

if (searchTermsResult.failure) {
  throw new Error(`Failed to create search terms: ${searchTermsResult.failure.message}`)
}

const [emailHmac] = searchTermsResult.data

Global Secondary Index with Encrypted Key

// Table with GSI using encrypted key
const table = {
  TableName: 'Users',
  AttributeDefinitions: [
    {
      AttributeName: 'pk',
      AttributeType: 'S',
    },
    {
      AttributeName: 'email__hmac',
      AttributeType: 'S',
    },
  ],
  KeySchema: [
    {
      AttributeName: 'pk',
      KeyType: 'HASH',
    },
  ],
  GlobalSecondaryIndexes: [
    {
      IndexName: 'EmailIndex',
      KeySchema: [
        {
          AttributeName: 'email__hmac',
          KeyType: 'HASH',
        },
      ],
      Projection: {
        ProjectionType: 'INCLUDE',
        NonKeyAttributes: ['email__source'],
      },
    },
  ],
}

// Create search terms for querying
const searchTermsResult = await protectDynamo.createSearchTerms([
  {
    value: '[email protected]',
    column: users.email,
    table: users,
  },
])

if (searchTermsResult.failure) {
  throw new Error(`Failed to create search terms: ${searchTermsResult.failure.message}`)
}

const [emailHmac] = searchTermsResult.data

Error Handling

All methods return a Result type from @byteslice/result that must be checked for failures:

const result = await protectDynamo.encryptModel(user, users)

if (result.failure) {
  // Handle error
  console.error(result.failure.message)
} else {
  // Use encrypted data
  const encryptedData = result.data
}

Type Safety

The package is fully typed and supports TypeScript:

type User = {
  pk: string
  email: string
}

// Type-safe encryption
const encryptResult = await protectDynamo.encryptModel<User>(user, users)
if (encryptResult.failure) {
  throw new Error(`Failed to encrypt user: ${encryptResult.failure.message}`)
}
const encryptedUser = encryptResult.data

// Type-safe decryption
const decryptResult = await protectDynamo.decryptModel<User>(item, users)
if (decryptResult.failure) {
  throw new Error(`Failed to decrypt user: ${decryptResult.failure.message}`)
}
const decryptedUser = decryptResult.data