Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @awslabs/aws-sdk-js-team
27 changes: 27 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: build

on:
workflow_call:

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x, 22.x]

steps:
- uses: actions/checkout@v4
- name: corepack
run: npm i -g corepack
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- name: install
run: yarn
- name: build
run: yarn build
- name: test
run: yarn test
9 changes: 9 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: pull_request

on:
pull_request:
branches: [main]

jobs:
call-build:
uses: ./.github/workflows/build.yml
10 changes: 10 additions & 0 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: pull_request

on:
push:
branches: [main]

jobs:
call-build:
uses: ./.github/workflows/build.yml
# ToDo: Add release code for 0.0.2 onwards
112 changes: 112 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
177 changes: 171 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,177 @@
## My Project
# Node.js Invoke Store for AWS Lambda

TODO: Fill this README out!
`@aws/lambda-invoke-store` provides a generic, per-invocation context store for
AWS Lambda Node.js Runtime Environment. It enables storing and retrieving data
within the scope of a single Lambda invocation, with proper isolation between
concurrent executions.

Be sure to:
## Features

* Change the title in this README
* Edit your repository description on GitHub
- **Invocation Isolation**: Safely store and retrieve data within a single Lambda invocation.
- **Protected Lambda Context**: Built-in protection for Lambda execution metadata (requestId, [traceId](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-traces))
- **Custom Data Storage**: Store any custom data within the invocation context
- **Async/Await Support**: Full support for asynchronous operations with context preservation
- **Type Safety**: Complete TypeScript type definitions
- **Singleton Pattern**: Ensures a single shared instance across all imports
- **Global Namespace Integration**: Integrates with the Lambda runtime global namespace

## Installation

```bash
npm install @aws/lambda-invoke-store
```

## Quick Start

> **Note**: In the AWS Lambda environment, the Runtime Interface Client (RIC) automatically initializes the InvokeStore context at the beginning of each invocation. Lambda function developers typically don't need to call `InvokeStore.run()` directly.

```typescript
import { InvokeStore } from "@aws/lambda-invoke-store";

// Lambda handler with invoke store
export const handler = async (event, context) => {
// The RIC has already initialized the InvokeStore with requestId and X-Ray traceId

// Access Lambda context data
console.log(`Processing request: ${InvokeStore.getRequestId()}`);

// Store custom data
InvokeStore.set("userId", event.userId);

// Data persists across async operations
await processData(event);

// Retrieve custom data
const userId = InvokeStore.get("userId");

return {
requestId: InvokeStore.getRequestId(),
userId,
};
};

// Context is preserved in async operations
async function processData(event) {
// Still has access to the same invoke context
console.log(`Processing in same context: ${InvokeStore.getRequestId()}`);

// Can set additional data
InvokeStore.set("processedData", { result: "success" });
}
```

## API Reference

### InvokeStore.getContext()

Returns the complete current context or `undefined` if outside a context.

```typescript
const context = InvokeStore.getContext();
```

### InvokeStore.get(key)

Gets a value from the current context.

```typescript
const requestId = InvokeStore.get(InvokeStore.PROTECTED_KEYS.REQUEST_ID);
const customValue = InvokeStore.get("customKey");
```

### InvokeStore.set(key, value)

Sets a custom value in the current context. Protected Lambda fields cannot be modified.

```typescript
InvokeStore.set("userId", "user-123");
InvokeStore.set("timestamp", Date.now());

// This will throw an error:
// InvokeStore.set(InvokeStore.PROTECTED_KEYS.REQUEST_ID, 'new-id');
```

### InvokeStore.getRequestId()

Convenience method to get the current request ID.

```typescript
const requestId = InvokeStore.getRequestId(); // Returns '-' if outside context
```

### InvokeStore.getXRayTraceId()

Convenience method to get the current [X-Ray trace ID](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-traces). This ID is used for distributed tracing across AWS services.

```typescript
const traceId = InvokeStore.getXRayTraceId(); // Returns undefined if not set or outside context
```

### InvokeStore.hasContext()

Checks if code is currently running within an invoke context.

```typescript
if (InvokeStore.hasContext()) {
// We're inside an invoke context
}
```

### InvokeStore.run(context, fn)

> **Note**: This method is primarily used by the Lambda Runtime Interface Client (RIC) to initialize the context for each invocation. Lambda function developers typically don't need to call this method directly.

Runs a function within an invoke context.

```typescript
InvokeStore.run(
{
[InvokeStore.PROTECTED_KEYS.REQUEST_ID]: "request-123",
[InvokeStore.PROTECTED_KEYS.X_RAY_TRACE_ID]: "trace-456", // Optional X-Ray trace ID
customField: "value", // Optional custom fields
},
() => {
// Function to execute within context
}
);
```

## Integration with AWS Lambda Runtime

The `@aws/lambda-invoke-store` package is designed to be integrated with the AWS Lambda Node.js Runtime Interface Client (RIC). The RIC automatically:

1. Initializes the InvokeStore context at the beginning of each Lambda invocation
2. Sets the `requestId` and [X-Ray `traceId`](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-traces) in the context
3. Ensures proper context isolation between concurrent invocations
4. Cleans up the context after the invocation completes

Lambda function developers can focus on using the context without worrying about initialization or cleanup.

## Global Namespace and Singleton Pattern

The InvokeStore uses a singleton pattern to ensure that all imports of the module use the same instance, which is critical for maintaining proper context isolation across different parts of your application.

### Global Namespace Integration

The InvokeStore integrates with the Lambda runtime's global namespace:

```typescript
// The InvokeStore is available globally
const globalInstance = globalThis.awslambda.InvokeStore;
```

This enables seamless integration between the Lambda Runtime Interface Client (RIC), AWS SDK, and your function code, ensuring they all share the same context.

### Environment Variable Opt-Out

If you prefer not to modify the global namespace, you can opt out by setting the environment variable:

```bash
# Disable global namespace modification
AWS_LAMBDA_NODEJS_NO_GLOBAL_AWSLAMBDA=1
```

When this environment variable is set, the InvokeStore will still function correctly, but it won't be stored in the global namespace.

## Security

Expand All @@ -14,4 +180,3 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform
## License

This project is licensed under the Apache-2.0 License.

36 changes: 36 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@aws/lambda-invoke-store",
"version": "0.0.1",
"description": "Invoke scoped data storage for AWS Lambda Node.js Runtime Environment",
"homepage": "https://github.com/awslabs/aws-lambda-invoke-store",
"main": "./dist/invoke-store.js",
"types": "./dist/invoke-store.d.ts",
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/awslabs/aws-lambda-invoke-store.git"
},
"license": "Apache-2.0",
"author": {
"name": "Amazon Web Services",
"url": "http://aws.amazon.com"
},
"scripts": {
"build": "tsc",
"test": "vitest run",
"test:watch": "vitest watch",
"clean": "rm -rf dist"
},
"devDependencies": {
"@tsconfig/node18": "^18.2.4",
"@types/node": "^18.19.112",
"typescript": "~5.4.5",
"vitest": "^3.1.1"
},
"engines": {
"node": ">=18.0.0"
},
"packageManager": "yarn@4.9.4"
}
Loading