From c681627e74a639a6fd1bc1b13c4f2fad6fb8234d Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 26 Aug 2026 11:59:21 +0000 Subject: [PATCH 1/4] docs(npm): README for the @extenddb/dev launcher package The npm package pages have no README today, the same blank front door the Docker Hub repositories had before their Overviews were published. npm renders the package README from the published tarball and includes README.md automatically regardless of the files whitelist, so this lands on npmjs.com with the next version publish. Content is written against the real launcher API in index.js (start() options, returned shape, stop semantics) rather than from memory, and the quick-start block was executed verbatim against the published 0.1.10 candidate with @aws-sdk/client-dynamodb v3: server starts on an ephemeral port, ListTables succeeds against the returned endpoint/credentials/region, stop() resolves cleanly. The vitest globalSetup example mirrors the pattern verified in earlier launcher testing. Trademark and plain-HTTP security notes match the Docker Hub dev Overview wording. --- packaging/npm/README.md | 100 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 packaging/npm/README.md diff --git a/packaging/npm/README.md b/packaging/npm/README.md new file mode 100644 index 00000000..f8f4b75b --- /dev/null +++ b/packaging/npm/README.md @@ -0,0 +1,100 @@ +# @extenddb/dev + +A DynamoDB-compatible server for local development and CI, installed from npm. +One function call starts a real server on localhost: no Docker daemon, no JVM, +no AWS account, no configuration. Any AWS SDK, CLI, or tool that talks to +DynamoDB works against it unchanged. + +The server is a single native binary (Rust, SQLite storage) downloaded for +your platform at install time. Linux binaries are statically linked and run +on any distribution; macOS (Intel and Apple silicon) and Windows are also +supported. Node 18 or later. + +## Getting started + +```bash +npm install --save-dev @extenddb/dev +``` + +```js +const { start } = require("@extenddb/dev"); + +const server = await start({ memory: true }); +// server.endpoint -> "http://127.0.0.1:53211" (ephemeral port) +// server.credentials -> { accessKeyId, secretAccessKey } +// server.region -> "us-east-1" + +// Point any DynamoDB client at it: +const { DynamoDBClient, ListTablesCommand } = require("@aws-sdk/client-dynamodb"); +const client = new DynamoDBClient({ + endpoint: server.endpoint, + region: server.region, + credentials: server.credentials, +}); +await client.send(new ListTablesCommand({})); + +await server.stop(); +``` + +## Options + +`start(options)` accepts: + +| Option | Default | Description | +|---|---|---| +| `storage` | `"file"` | `"file"` persists between runs; `"memory"` vanishes on stop. | +| `memory` | `false` | Shorthand for `storage: "memory"`. | +| `dbPath` | data dir | SQLite file location (file mode only). | +| `port` | ephemeral | Fixed port instead of an OS-assigned one. | +| `binary` | bundled | Path to an `extenddb` binary, overriding the bundled one. | +| `startupTimeoutMs` | `15000` | How long to wait for the server to become healthy. | + +The returned object carries `endpoint`, `port`, `credentials`, `region`, +`storage`, and `stop()`, which shuts the server down and resolves when the +process has exited. + +## Use in a test suite + +Ephemeral ports mean parallel test shards never collide. With Vitest: + +```js +// globalSetup.js +const { start } = require("@extenddb/dev"); + +module.exports = async function () { + const server = await start({ memory: true }); + process.env.DDB_ENDPOINT = server.endpoint; + process.env.AWS_ACCESS_KEY_ID = server.credentials.accessKeyId; + process.env.AWS_SECRET_ACCESS_KEY = server.credentials.secretAccessKey; + process.env.AWS_REGION = server.region; + return () => server.stop(); +}; +``` + +Each account's data is isolated, so suites that need clean separation can use +distinct credentials rather than distinct servers. + +## What it supports + +The DynamoDB API surface for application development: tables, items, +expressions, queries and scans (including parallel scan), secondary indexes, +transactions, batch operations, TTL, streams, backup and restore, and vector +indexes with `SearchVectors`. Behavioral differences from the service are +documented in [Differences from DynamoDB](https://github.com/ExtendDB/extenddb/blob/main/docs/differences-from-dynamodb.md). + +## Note + +This package is built for local development and CI. The server speaks plain +HTTP on 127.0.0.1 and seeds AWS's documented example credential, printed at +startup; whoever holds it can do anything. Do not expose it beyond localhost +and do not keep real data in it. For a durable, TLS-terminated deployment, +use [`extenddb/extenddb-postgres`](https://hub.docker.com/r/extenddb/extenddb-postgres). + +ExtendDB is an independent open source project managed by Amazon Web +Services. It is not Amazon DynamoDB and does not contain any DynamoDB source +code. "DynamoDB" is a trademark of Amazon.com, Inc. ExtendDB is a clean-room +implementation that speaks the DynamoDB wire protocol. + +More at [extenddb.org](https://extenddb.org) and +[github.com/ExtendDB/extenddb](https://github.com/ExtendDB/extenddb). +Licensed under Apache-2.0. From 0ebba909022162fd61b62be10a4bb2337eaa5b1c Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 26 Aug 2026 12:07:49 +0000 Subject: [PATCH 2/4] docs(npm): quickstart must be runnable as pasted The quickstart mixed require() with top-level await, which Node rejects as a file (ERR_AMBIGUOUS_MODULE_SYNTAX on current Node, SyntaxError on older): top-level await is ESM-only while require marks the file CommonJS. Rewritten as an ESM file with imports, executed verbatim as quickstart.mjs against the published 0.1.10 candidate (named import from the CJS module resolves via Node's static export detection; ListTables succeeds; stop resolves). A one-line CommonJS note covers the require-plus-async-wrapper form. --- packaging/npm/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packaging/npm/README.md b/packaging/npm/README.md index f8f4b75b..bbb298e6 100644 --- a/packaging/npm/README.md +++ b/packaging/npm/README.md @@ -17,15 +17,15 @@ npm install --save-dev @extenddb/dev ``` ```js -const { start } = require("@extenddb/dev"); +// quickstart.mjs -- run with: node quickstart.mjs +import { start } from "@extenddb/dev"; +import { DynamoDBClient, ListTablesCommand } from "@aws-sdk/client-dynamodb"; const server = await start({ memory: true }); // server.endpoint -> "http://127.0.0.1:53211" (ephemeral port) // server.credentials -> { accessKeyId, secretAccessKey } // server.region -> "us-east-1" -// Point any DynamoDB client at it: -const { DynamoDBClient, ListTablesCommand } = require("@aws-sdk/client-dynamodb"); const client = new DynamoDBClient({ endpoint: server.endpoint, region: server.region, @@ -36,6 +36,9 @@ await client.send(new ListTablesCommand({})); await server.stop(); ``` +From CommonJS, use `const { start } = require("@extenddb/dev")` and wrap the +calls in an async function (top-level `await` is ESM-only). + ## Options `start(options)` accepts: From 4fe52b10e554b8ec13668872915a7f448e8dacb8 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 26 Aug 2026 12:10:30 +0000 Subject: [PATCH 3/4] docs(npm): globalSetup example in ESM, matching the quickstart Vitest is ESM-native and the quickstart is already ESM; the test-suite section still showed a CommonJS globalSetup. Converted to an .mjs default export and verified literally: the exact file from this README was extracted and run under a real vitest with globalSetup wired, a test resolving the env-passed endpoint/credentials passed 1/1 against the published 0.1.10 candidate, and the returned teardown stopped the server. --- packaging/npm/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/npm/README.md b/packaging/npm/README.md index bbb298e6..99c3775a 100644 --- a/packaging/npm/README.md +++ b/packaging/npm/README.md @@ -61,17 +61,17 @@ process has exited. Ephemeral ports mean parallel test shards never collide. With Vitest: ```js -// globalSetup.js -const { start } = require("@extenddb/dev"); +// globalSetup.mjs +import { start } from "@extenddb/dev"; -module.exports = async function () { +export default async function () { const server = await start({ memory: true }); process.env.DDB_ENDPOINT = server.endpoint; process.env.AWS_ACCESS_KEY_ID = server.credentials.accessKeyId; process.env.AWS_SECRET_ACCESS_KEY = server.credentials.secretAccessKey; process.env.AWS_REGION = server.region; return () => server.stop(); -}; +} ``` Each account's data is isolated, so suites that need clean separation can use From 32bed9acee511ad5ee114d0625db90898158dd7a Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 26 Aug 2026 12:11:34 +0000 Subject: [PATCH 4/4] docs(npm): drop a filler intensifier from the opening --- packaging/npm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/npm/README.md b/packaging/npm/README.md index 99c3775a..cbacb5e8 100644 --- a/packaging/npm/README.md +++ b/packaging/npm/README.md @@ -1,7 +1,7 @@ # @extenddb/dev A DynamoDB-compatible server for local development and CI, installed from npm. -One function call starts a real server on localhost: no Docker daemon, no JVM, +One function call starts it on localhost: no Docker daemon, no JVM, no AWS account, no configuration. Any AWS SDK, CLI, or tool that talks to DynamoDB works against it unchanged.