-
Notifications
You must be signed in to change notification settings - Fork 0
Release notes
Reverse-chronological. Links to the npm version history and this repo's git tags.
Security + correctness hardening sweep. Full module-by-module audit — 19 bug fixes + 9 defensive improvements. All changes are either bug fixes restoring the documented / intended contract, or additive opt-in options with sensible defaults — so this is a patch release.
-
Prototype pollution guards (4 vectors closed):
-
paths/getPathno longer reads through the prototype chain.getPath({}, 'toString')now returnsdefaultValueinstead ofFunction.prototype.toString. -
paths/setPath/paths/deletePathrefuse to walk or write through__proto__/constructor/prototypesegments. -
rest-core/parsePatchuses a null-prototype accumulator — a PATCH body containing"__proto__"no longer reassigns the patch's prototype. -
mass/readOrderedListByKeysusesObject.create(null)accumulators — a record with partition-key value'__proto__'no longer pollutesObject.prototypeglobally.
-
-
DoS-on-self vectors closed (3):
-
batchWrite/batchGetcap at 8 retry attempts (was infinite loop on persistent throttling). -
handlerrejects bodies larger than 1 MB with HTTP 413PayloadTooLarge(was unbounded memory accumulation). -
parsePagingcaps?offset=at 100 000 by default (was unbounded —?offset=1e15could DoS via astronomical skip-page calls).
-
-
AWS-aligned retry backoff:
backoff()default per-retry cap is now 20 s (was undocumented 60 s with infinite retries). Matches AWS SDK v3 default and AWS DynamoDB retry guidance ("stop around one minute"). WithMAX_ATTEMPTS = 8, worst-case total wait is ~43 s.
-
Adapter.moveByKeysandmass/moveListnow pairput+deleteper item. Previously, a falsymapFnreturn could drop the put but leave the delete in flight — silent data loss. Now both legs drop together. -
Adapterconstructor rejects non-arraykeyFields.new Adapter({..., keyFields: 'name'})previously silently produced broken queries (attribute alias'n'); now throws. -
applyBatch/applyTransactionthrow on unknownactionvalues (were silently dropped — caused phantom "processed" counts and missing writes). -
buildUpdatethrows on unknownarrayOp.opvalues (typos like'increment'were silently dropped, producing partial UpdateExpressions). -
buildUpdateguardsoptions.deleteandoptions.arrayOpswithArray.isArray(string input no longer iterates characters). -
applyBatchtotalcounts only items actually added to the batch (was inflating the count with dropped items). -
normalizeFields(',,,')now returnsnullinstead of[](restores the "no fields requested → project everything" contract). -
applyPatch(o, null)returnsounchanged instead of crashing onObject.keys(null). -
applyPatchoptions.deletenow gated withArray.isArray. -
cloneParams(null)returns a fresh clone instead of crashing. -
handlerstrips leading//fromreq.urlsoGET //evil.com/pathcannot pivot the URL's origin; sanitizes theHostheader to prevent crashes on malformed headers. -
handler405 error body no longer echoesurl.pathname(minor information disclosure removed).
-
createHandler(adapter, {maxBodyBytes})— HTTP body-size cap. Default 1 MB. -
parseFields(input, {maxItems})— output-length cap. Default 1000. -
parseNames(input, {maxItems})— output-length cap. Default 1000. -
parseFilter(input, {maxLength})— query-string length cap. Default 1024. -
parsePaging(input, {maxOffset})— offset ceiling. Default 100 000. -
defaultPolicy.maxOffsetadded (same default).
| Change | Before | After |
|---|---|---|
backoff() default cap |
undocumented 60 s | 20 s |
batchWrite / batchGet attempts |
infinite retry | 8 (throws after) |
Unknown action in applyBatch / applyTransaction
|
silent drop | throws |
Unknown arrayOp.op in buildUpdate
|
silent drop | throws |
Adapter with non-array keyFields
|
silently accepted (broken) | throws |
| Handler request body > 1 MB | unbounded | 413 PayloadTooLarge
|
?offset= on list routes |
unbounded | capped at 100 000 |
getPath({}, 'toString') |
Function.prototype.toString |
defaultValue |
See the per-page wiki updates (REST core, HTTP handler, Batch and transactions, Mass operations) for the detailed surface.
Additive features. No breaking changes.
-
returnFailedItemoption onpost/put/patch/deleteand theirmake*batch builders. SetsReturnValuesOnConditionCheckFailure: 'ALL_OLD'; the thrownConditionalCheckFailedExceptioncarries the colliding item on itsItemfield (or the matchingCancellationReason.Iteminside a transaction). -
{options: ...}sentinel forapplyTransaction— position-independent descriptor carrying transaction-level knobs:clientRequestToken(idempotency),returnConsumedCapacity,returnItemCollectionMetrics. -
explainTransactionCancellation(err, ...descriptors)in/batch. MapsTransactionCanceledException.CancellationReasonsback to the input descriptors and returns{failures, message} | null. Paired withreturnFailedItemto surface the colliding item in one call. -
Cross-runtime test matrix — Node, Deno, Bun (
npm test,npm run test:deno,npm run test:bun). - CJS smoke test + TypeScript smoke test wired into the suite.
-
LICENSE file shipped (BSD-3-Clause).
llms.txt+llms-full.txtincluded in the npm tarball. - CI lint step re-enabled (
.github/dependabot.ymlin.prettierignore). - Three CodeQL alerts cleared (workflow permissions, two ReDoS candidates).
Typed .d.ts sidecars updated throughout. See Adapter: CRUD methods, Batch and transactions, and Compatibility for the detailed coverage.
Green-field rewrite on AWS SDK v3. Not a drop-in upgrade from v2. v2 consumers stay on dynamodb-toolkit@2.3.0. The v3 line is the actively-developed branch.
Highlights:
-
AWS SDK v3 (
@aws-sdk/client-dynamodb+@aws-sdk/lib-dynamodb) peer deps, replacing v2'saws-sdk. -
ESM-only,
"type": "module", hand-written.d.tssidecars next to every.js. No build step. -
One data format — plain JS via
lib-dynamodbmiddleware. The v2Raw/DbRawpair collapsed into a singleRaw<T>bypass marker. -
Options bags everywhere:
put(item, {force: true})instead ofput(item, true);patch(key, patch, {delete, separator, arrayOps, conditions}). -
Hooks renamed:
prepareListParams→prepareListInput,updateParams→updateInput. Hooks bag (options.hooks) is the canonical extension point. -
Patch wire format:
_delete/_separator(single underscore); configurable viapolicy.metaPrefix. -
REST split:
dynamodb-toolkit/rest-coreis framework-agnostic;dynamodb-toolkit/handleris thenode:httpadapter. Koa / Express / Hono / Fetch / Lambda adapters live in separate packages. -
Transaction auto-upgrade: single-op CRUD automatically upgrades to
TransactWriteItemswhencheckConsistencyreturns extra descriptors. - Indirect-index second-hop for sparse GSIs with key-only projection.
- Dropped:
makeClient,getProfileName,specialTypes,converter,converterOptions— use@aws-sdk/credential-providersdirectly.
See Migration: v2 to v3 and SDK v2 to v3 cheat sheet.
The v2 documentation snapshot lives at the v2.3-docs git tag of this wiki repo. The v2 source code remains on npm as dynamodb-toolkit@2.3.0 and on GitHub at the matching git tag.
Start here
- Getting started
- Concepts
- Key and field design
- Compatibility
- Migration: v2 to v3
- SDK v2 to v3 cheat sheet
Guides
- Hierarchical data walkthrough
- Key expression patterns
- Multi-type tables
- Pagination
- Mass operation semantics
- URL schema design
Adapter
- Adapter
- Constructor options
- CRUD methods
- Mass methods
- Batch builders
- Hooks
- Raw marker
- Indirect indices
- Transaction auto-upgrade
Expression builders
Batch / transactions / mass / paths
REST surface
Framework adapters
Recipes
- Recipes index
- List records of a tier
- Per-tier sparse GSI markers
- Tier within a partition
- Reservation with auto-release
- Keys-only GSI, runtime projection
- Cascade subtree operations
- Querying subtrees with buildKey
- Filter URL grammar
- Text search
- Provisioning workflow
- Resumable mass operations
History