Skip to content

feat(event-handler): add type-safe Store API for request and shared state - #5081

Merged
svozza merged 22 commits into
mainfrom
feat/store-api
Mar 18, 2026
Merged

svozza merged 22 commits into
mainfrom
feat/store-api

Conversation

@svozza

@svozza svozza commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Add a Store API to the HTTP event handler that provides type-safe, scoped state management for route handlers. This gives users two storage scopes:

  • Request store — per-invocation state (set in middleware, read in handlers). Cleared automatically between requests.
  • Shared store — router-scoped state (set at cold start, read everywhere). Persists across invocations.

Changes

  • Add Store class backed by a Map with generic key/value typing via an Env type parameter
  • Make Router generic over TEnv extends Env so that reqCtx.get(), reqCtx.set(), and reqCtx.shared.get() are fully typed
  • Add includeRouter overload that returns Router<MergeEnv<[TEnv, TOther]>>, enabling a fluent chaining style that accumulates store types across sub-routers
  • Export MergeEnv utility type for users who prefer declaring the full environment upfront
  • Add store subpath export (@aws-lambda-powertools/event-handler/store)
  • Unit tests, type-level tests, and e2e tests for both store scopes
  • Documentation with examples for untyped usage, typed usage, and split-router patterns

Issue number: closes #5072


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

svozza added 15 commits March 10, 2026 14:45
Add a generic Store<T> class backed by a Map with set, get, has, and
delete methods. This is the foundation for the Store API that will
enable type-safe state sharing across the request lifecycle.

Refs: #5072
Add Env type and helper types (RequestStoreOf, SharedStoreOf) for
extracting store types. Thread TEnv generic parameter through
RequestContext, TypedRequestContext, Middleware, RouteHandler,
TypedRouteHandler, MiddlewareOrHandler, and HandlerOrOptions.

All generics default to Env so existing code is unaffected.

Refs: #5072
Replace all hardcoded Env references with TEnv type parameter across
Router class, middleware, route handlers, and HTTP method overloads.
Add IStore interface to avoid invariance issues from private class
fields. Add request-scoped store methods (set/get/has/delete) and
shared store to RequestContext. Wire up store creation in Router#resolve.
Add runtime tests for request-scoped store (set/get/has/delete,
isolation between requests, middleware-handler sharing, post-next
access) and shared store (persistence across requests, cross-route
sharing, middleware access). Add type tests for RequestContext store
properties and IStore typing.
Add ./store package entry point exporting Store class and IStore
interface. Export Env type from ./types for users to define typed
router environments.
includeRouter now returns Router<MergeEnv<[TEnv, TOther]>> so chaining
accumulates store types automatically without upfront declaration.

Also threads RouteHandler<TEnv> through all HTTP method overloads so
handler callbacks receive the router's actual store types, and widens
internal middleware storage to Middleware[] to avoid casts when merging
sub-router middleware.
…ctAll

Extract duplicated request store closure methods (set/get/has/delete)
into a single #createStoreAccessors private method, removing the
copy-paste between the error path and normal path in #resolve.

Change IntersectAll base case from Record<string, unknown> to unknown
(the intersection identity type) to eliminate noisy trailing
& Record<string, unknown> in resolved types.
Add documentation for the request and shared store, typed stores with
Env generics, and typed stores with split routers (chained includeRouter
and upfront MergeEnv patterns). Export MergeEnv from the public types
entry point and add a type test for the upfront pattern.
…types script

Use typed Router<AppEnv> in store tests so store get/set calls are
type-safe. Use ?? fallbacks instead of non-null assertions. Wire up
the test:unit:types npm script to run vitest --typecheck on tests/types.
Add storeRouter with request-scoped and shared store routes. Update
FunctionCode to use chained includeRouter syntax with StoreEnv typing.
Add e2e tests verifying request store isolation and shared store
persistence. Fix nestedRouter type error by using req.url instead of
event.path.
Co-locate Store module with its entry point so src/store/index.ts
re-exports from a sibling rather than reaching up to the parent.
svozza added 2 commits March 10, 2026 22:22
…ate type tests

Remove ?? '' fallbacks in test handlers where values are expected to
exist so assertions catch undefined instead of silently passing.

Move Store type tests from unit/Store.test.ts to types/store.test-d.ts
so they run under test:unit:types.
…outer

The chained includeRouter calls infer the merged type automatically.
… MergeEnv

When an untyped Router was merged with a typed one via includeRouter,
the fallback Record<string, unknown> from the untyped side would poison
the intersection, making the store accept any string key. Introduce
ForMerge extractors that fall back to {} (intersection identity) and
DefaultIfEmpty to widen back to Record<string, unknown> only when all
envs are untyped. Also constrain MergeEnv to require at least 2 envs.

@sdangol sdangol left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few comments but overall functionality looks good

Comment thread docs/features/event-handler/http.md Resolved
svozza and others added 3 commits March 18, 2026 10:52
Co-authored-by: Swopnil Dangol <swopnildangol@gmail.com>
…erty

Add Prepare/Act/Assess comments to type test files and add type
assertions for Router's implicit Env type parameter. Deprecate
the `context` property in favor of `requestContext.shared`.
@sonarqubecloud

sonarqubecloud Bot commented Mar 18, 2026 •

Copy link
Copy Markdown
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XXL PRs with 1K+ LOC, largely documentation related

2 participants