{"_id":"@bm8/aws-dynamodb","_rev":"2-db81a16c314390b554e3fd22edfa7a8d","name":"@bm8/aws-dynamodb","dist-tags":{"latest":"0.1.0"},"versions":{"0.0.1":{"name":"@bm8/aws-dynamodb","version":"0.0.1","author":{"name":"Paul Carter"},"license":"MIT","_id":"@bm8/aws-dynamodb@0.0.1","maintainers":[{"name":"bewdym8","email":"bewdym85176@gmail.com"}],"homepage":"https://github.com/pgcarter/aws-utils#readme","bugs":{"url":"https://github.com/pgcarter/aws-utils/issues"},"dist":{"shasum":"58fd1754b12f15d08b7be3a9023ecd0a5688d7e3","tarball":"https://registry.npmjs.org/@bm8/aws-dynamodb/-/aws-dynamodb-0.0.1.tgz","fileCount":5,"integrity":"sha512-XAgUqogL3/FBA3Ppc0T9htjHeqcBkGcpRx9zNfMkD9MKsZh92gjikvD2/yrcOh51XFyl37zfmgClAaS2R4W8iQ==","signatures":[{"sig":"MEYCIQClCniuLfQ/kUU4j9Ql7JrHp9y6iSM7qHZQdCaLL0o7hwIhAMh7suIzZZ0U3amz4VbClCK5+T+s9P+rRyToFDIJxGV5","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36628},"main":"./dist/index.js","type":"module","_from":"file:bm8-aws-dynamodb-0.0.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"tsup","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc --noEmit && pnpm typecheck:tests","typecheck:tests":"tsc --noEmit -p tsconfig.test.json"},"_npmUser":{"name":"bewdym8","email":"bewdym85176@gmail.com"},"_resolved":"/private/var/folders/5v/_kwm0fcx53l5447mf1l54sp80000gn/T/22b4506e786170085b6f5af99fb01b2d/bm8-aws-dynamodb-0.0.1.tgz","_integrity":"sha512-XAgUqogL3/FBA3Ppc0T9htjHeqcBkGcpRx9zNfMkD9MKsZh92gjikvD2/yrcOh51XFyl37zfmgClAaS2R4W8iQ==","repository":{"url":"git+https://github.com/pgcarter/aws-utils.git","type":"git","directory":"packages/aws-dynamodb"},"_npmVersion":"11.9.0","description":"A small, type-safe wrapper around `@aws-sdk/lib-dynamodb` for single-table DynamoDB designs. You declare your entities once with `defineEntity`, then `createDynamoClient` returns a per-entity client where `put`/`get`/`update`/`upsert`/`pagedQuery` are typ","directories":{},"_nodeVersion":"24.14.0","dependencies":{"@bm8/aws-core":"0.0.0","@aws-sdk/lib-dynamodb":"^3.693.0","@aws-sdk/client-dynamodb":"^3.693.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/aws-dynamodb_0.0.1_1779523434426_0.18102445164736336","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@bm8/aws-dynamodb","version":"0.1.0","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"dependencies":{"@aws-sdk/client-dynamodb":"^3.693.0","@aws-sdk/lib-dynamodb":"^3.693.0","@bm8/aws-core":"0.1.0"},"publishConfig":{"access":"public","provenance":true},"repository":{"type":"git","url":"git+https://github.com/pgcarter/aws-utils.git","directory":"packages/aws-dynamodb"},"license":"MIT","author":{"name":"Paul Carter"},"scripts":{"build":"tsup","test":"vitest run","typecheck":"tsc --noEmit && pnpm typecheck:tests","typecheck:tests":"tsc --noEmit -p tsconfig.test.json","clean":"rm -rf dist *.tsbuildinfo"},"_id":"@bm8/aws-dynamodb@0.1.0","description":"A small, type-safe wrapper around `@aws-sdk/lib-dynamodb` for single-table DynamoDB designs. You declare your entities once with `defineEntity`, then `createDynamoClient` returns a per-entity client where `put`/`get`/`update`/`upsert`/`pagedQuery` are typ","bugs":{"url":"https://github.com/pgcarter/aws-utils/issues"},"homepage":"https://github.com/pgcarter/aws-utils#readme","_integrity":"sha512-bjegrwoy97whY5+RC1QnqxOKtOj+1WtKGBF/4T3/BUzHJWhw7vSJUc0eHGPx8V4aO36Dr3cAQxB6CszaYJOFIg==","_resolved":"/tmp/e25cce476f78a71255e6e565d9952a07/bm8-aws-dynamodb-0.1.0.tgz","_from":"file:bm8-aws-dynamodb-0.1.0.tgz","_nodeVersion":"24.16.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-bjegrwoy97whY5+RC1QnqxOKtOj+1WtKGBF/4T3/BUzHJWhw7vSJUc0eHGPx8V4aO36Dr3cAQxB6CszaYJOFIg==","shasum":"bdcc29116b29ec2eff3e4bf278dfc370aa502a35","tarball":"https://registry.npmjs.org/@bm8/aws-dynamodb/-/aws-dynamodb-0.1.0.tgz","fileCount":5,"unpackedSize":36628,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bm8%2faws-dynamodb@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCu7duKBpxFbyiuRoOAOsnV3R2OUVCBBzVjSK5+MR5KPAIgb9uKP5m7HcCh6tKWcHNPZ1D9yrK5aeTSgtyMwWfo5N8="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:894c9be5-fe7f-4292-bf73-cf402dcf0422"}},"directories":{},"maintainers":[{"name":"bewdym8","email":"bewdym85176@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/aws-dynamodb_0.1.0_1780111550776_0.31152664010543973"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-23T08:03:54.253Z","modified":"2026-05-30T03:25:51.252Z","0.0.1":"2026-05-23T08:03:54.567Z","0.1.0":"2026-05-30T03:25:50.935Z"},"bugs":{"url":"https://github.com/pgcarter/aws-utils/issues"},"author":{"name":"Paul Carter"},"license":"MIT","homepage":"https://github.com/pgcarter/aws-utils#readme","repository":{"type":"git","url":"git+https://github.com/pgcarter/aws-utils.git","directory":"packages/aws-dynamodb"},"description":"A small, type-safe wrapper around `@aws-sdk/lib-dynamodb` for single-table DynamoDB designs. You declare your entities once with `defineEntity`, then `createDynamoClient` returns a per-entity client where `put`/`get`/`update`/`upsert`/`pagedQuery` are typ","maintainers":[{"name":"bewdym8","email":"bewdym85176@gmail.com"}],"readme":"# @bm8/aws-dynamodb\n\nA small, type-safe wrapper around `@aws-sdk/lib-dynamodb` for single-table DynamoDB designs. You declare your entities once with `defineEntity`, then `createDynamoClient` returns a per-entity client where `put`/`get`/`update`/`upsert`/`pagedQuery` are typed against the entity's attributes and indexes.\n\n## Install\n\n```sh\npnpm add @bm8/aws-dynamodb\n```\n\n## Concepts\n\n- **Single table.** All entities live in one table keyed by `PK` / `SK`.\n- **Type discriminator.** Every item carries a `type` attribute set from the entity definition. Queries automatically filter by `type`, so a `pagedQuery` on the `user` entity will not return `order` items that happen to share a partition.\n- **GSIs.** Supported index names are `GSI1` and `GSI2`. Declaring an index on an entity surfaces `GSI1PK` / `GSI1SK` (etc.) as typed attributes you can write and query against.\n\n## Defining entities\n\n```ts\nimport { defineEntity, type Entity } from '@bm8/aws-dynamodb';\n\ntype UserAttrs = {\n  PK: `USER#${string}`;\n  SK: `USER#${string}`;\n  GSI1PK?: 'USERS';\n  GSI1SK?: string;\n  name: string;\n  email: string;\n};\n\nexport const userEntity = defineEntity<'USER', UserAttrs, ['GSI1']>(\n  'USER',\n  { indexes: ['GSI1'] },\n);\n\ntype OrderAttrs = {\n  PK: `USER#${string}`;\n  SK: `ORDER#${string}`;\n  total: number;\n};\n\nexport const orderEntity = defineEntity<'ORDER', OrderAttrs>('ORDER');\n\nexport const entities = { user: userEntity, order: orderEntity };\n```\n\nThe first generic must be uppercase — the type tag is enforced as `Uppercase<TType>`.\n\n## Creating the client\n\n```ts\nimport { DynamoDBClient } from '@aws-sdk/client-dynamodb';\nimport { createDynamoClient } from '@bm8/aws-dynamodb';\nimport { entities } from './entities';\n\nconst db = createDynamoClient({\n  tableName: 'app-table',\n  entities,\n  // optional: pass your own DynamoDBClient (region, endpoint, credentials, etc.)\n  client: new DynamoDBClient({}),\n});\n```\n\n`db` is shaped as `{ user: EntityOperations, order: EntityOperations }`, one entry per key in `entities`.\n\n## Operations\n\n### `put(entity)`\n\nWrites the full item. The `type` attribute is set automatically from the entity definition; any value you pass for `type` is overwritten.\n\n```ts\nawait db.user.put({\n  PK: 'USER#1',\n  SK: 'USER#1',\n  GSI1PK: 'USERS',\n  GSI1SK: 'alice',\n  name: 'Alice',\n  email: 'alice@example.com',\n});\n```\n\n### `get(key)`\n\nReads by primary key. Returns `undefined` if the item does not exist.\n\n```ts\nconst user = await db.user.get({ PK: 'USER#1', SK: 'USER#1' });\n```\n\n### `update(key, patch, remove?)`\n\nSets the attributes in `patch` and removes the attributes listed in `remove`. Fails if the item does not exist (`attribute_exists(PK)`). The `type` attribute cannot be updated.\n\n```ts\nawait db.user.update(\n  { PK: 'USER#1', SK: 'USER#1' },\n  { name: 'Alice B.', GSI1SK: 'alice b.' },\n);\n\n// remove optional attributes\nawait db.user.update(\n  { PK: 'USER#1', SK: 'USER#1' },\n  {},\n  ['GSI1PK', 'GSI1SK'],\n);\n```\n\nOnly attributes typed as optional on the entity are accepted in the `remove` list.\n\n### `upsert(key, patch)`\n\nLike `update`, but creates the item if it does not exist. Sets `type` on insert.\n\n```ts\nawait db.user.upsert(\n  { PK: 'USER#2', SK: 'USER#2' },\n  { name: 'Bob', email: 'bob@example.com' },\n);\n```\n\n### `pagedQuery(params)`\n\nQueries the base table or a GSI, paginating through `LastEvaluatedKey` and returning the accumulated results. A `type` filter is always applied so cross-entity items in the same partition are excluded.\n\n```ts\n// base table — all orders for a user\nconst orders = await db.order.pagedQuery({\n  pk: 'USER#1',\n  sk: { beginsWith: 'ORDER#' },\n});\n\n// GSI1 — first 50 users alphabetically\nconst users = await db.user.pagedQuery({\n  index: 'GSI1',\n  pk: 'USERS',\n  sk: { between: ['a', 'm'] },\n  limit: 50,\n});\n```\n\n`sk` accepts one of:\n\n```ts\n{ equals: string }\n{ beginsWith: string }\n{ between: [string, string] }\n{ lt: string } | { lte: string } | { gt: string } | { gte: string }\n```\n\n`limit` caps the in-memory result count; pagination stops as soon as that many items have been collected.\n\n## Testing\n\nThe package's tests run against [`amazon/dynamodb-local`](./docker-compose.yml). With the container up:\n\n```sh\npnpm --filter @bm8/aws-dynamodb test\n```\n","readmeFilename":"README.md"}