{"id":20579380,"url":"https://github.com/supersoniko/dynamodb-paginator","last_synced_at":"2025-07-18T22:07:57.192Z","repository":{"id":50922124,"uuid":"191924986","full_name":"supersoniko/dynamodb-paginator","owner":"supersoniko","description":"Paginate DynamoDB results easily","archived":false,"fork":false,"pushed_at":"2024-05-04T11:04:41.000Z","size":501,"stargazers_count":27,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-26T15:52:02.972Z","etag":null,"topics":["aws","database","dynamodb","nodejs","pagination"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/dynamodb-paginator","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/supersoniko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-06-14T10:33:41.000Z","updated_at":"2024-06-17T16:57:07.000Z","dependencies_parsed_at":"2023-12-20T17:45:13.337Z","dependency_job_id":"a1771a25-c40e-4200-8ace-e86627277f45","html_url":"https://github.com/supersoniko/dynamodb-paginator","commit_stats":{"total_commits":49,"total_committers":3,"mean_commits":"16.333333333333332","dds":0.04081632653061229,"last_synced_commit":"e7876fef8cbe383fe1fadd4367cbdc59bc33ec21"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/supersoniko/dynamodb-paginator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supersoniko%2Fdynamodb-paginator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supersoniko%2Fdynamodb-paginator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supersoniko%2Fdynamodb-paginator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supersoniko%2Fdynamodb-paginator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supersoniko","download_url":"https://codeload.github.com/supersoniko/dynamodb-paginator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supersoniko%2Fdynamodb-paginator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265845027,"owners_count":23837706,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","database","dynamodb","nodejs","pagination"],"created_at":"2024-11-16T06:16:51.044Z","updated_at":"2025-07-18T22:07:57.174Z","avatar_url":"https://github.com/supersoniko.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![npm](https://img.shields.io/npm/v/dynamodb-paginator.svg)\n![NPM](https://img.shields.io/npm/l/dynamodb-paginator.svg)\n![CircleCI](https://img.shields.io/circleci/build/github/supersoniko/dynamodb-paginator.svg)\n[![codecov](https://codecov.io/gh/supersoniko/dynamodb-paginator/branch/master/graph/badge.svg)](https://codecov.io/gh/supersoniko/dynamodb-paginator)\n\n**NOTE**: This pagination library only works on indexes with a sort key.\n\n# Usage\n\nCompatible with AWS SDK v3\n\n```typescript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { QueryCommand, DynamoDBDocumentClient } from \"@aws-sdk/lib-dynamodb\";\nimport { getPaginatedResult, decodeCursor } from \"dynamodb-paginator\";\n\ninterface UserPet {\n  userId: number; // partition key (hash)\n  petId: number; // sort key (range)\n}\n\nconst client = new DynamoDBClient({});\nconst docClient = DynamoDBDocumentClient.from(client);\n\nconst limit = 25;\nconst defaultInput = {\n  TableName: \"UserPets\",\n  Limit: limit,\n  KeyConditionExpression: \"userId = :userId\",\n  ExpressionAttributeValues: {\n    \":userId\": 1,\n  },\n  ConsistentRead: true,\n};\n\n// Could be a cursor from a previous paginated result\nconst cursor = undefined;\nconst paginationInput = decodeCursor(cursor) || defaultInput;\n\nconst command = new QueryCommand(paginationInput);\n\nconst response = await docClient.send(command);\n\n// By default the cursors are encoded in base64, but you can supply your own encoding function\nconst paginatedResult = getPaginatedResult\u003cUserPet\u003e(\n  paginationInput,\n  limit,\n  response\n);\n\n// Output:\n// {\n//     data: T[],\n//     meta: {\n//         limit: number,\n//         hasMoreData: boolean,\n//         cursor: string,\n//         backCursor: string,\n//         count: number\n//     }\n// }\n```\n\n## Security disclaimer\n\nIt's important to validate that the cursor has been generated by your service before passing it to the DynamoDB. If you don't, this opens a NoSQL vulnerability.\nA solution for this is signing/encrypting the cursor with a key.\n\nWithout encrypting the cursor, the partition and range key are also visible to the client consuming the cursor.\n\nIf your service offers authentication, it's also wise to validate that the cursor being parsed, was originally generated for that user/session. This is to prevent replay attacks.\n\n### Cursor encryption example\n\nA simplified example of encrypting and decrypting the generated pagination cursor.\n\nIt's recommended to encapsulate the secured pagination code in a service, for ease of use.\n\n```typescript\nimport { randomBytes, createCipheriv, createDecipheriv } from \"crypto\";\nimport { getPaginatedResult, decodeCursor } from \"dynamodb-paginator\";\n\nconst ENC_KEY = randomBytes(32); // set random encryption key\nconst IV = randomBytes(16); // set random initialisation vector\nconst ALGORITHM = \"aes-256-cbc\";\n\nconst encrypt = (val) =\u003e {\n  const cipher = createCipheriv(ALGORITHM, ENC_KEY, IV);\n  let encrypted = cipher.update(JSON.stringify(val), \"utf8\", \"base64\");\n  encrypted += cipher.final(\"base64\");\n\n  return encrypted;\n};\n\nconst decrypt = (encrypted) =\u003e {\n  const decipher = createDecipheriv(ALGORITHM, ENC_KEY, IV);\n  const decrypted = decipher.update(encrypted, \"base64\", \"utf8\");\n\n  return JSON.parse(decrypted + decipher.final(\"utf8\"));\n};\n\nconst limit = 2;\nconst params = { TableName: \"UserPets\", Limit: limit };\n// Example DynamoDB Output\nconst result = {\n  Count: 2,\n  Items: [\n    { userId: 1, petId: 1 },\n    { userId: 1, petId: 2 },\n  ],\n  LastEvaluatedKey: { userId: 1, petId: 2 },\n  ScannedCount: 2,\n};\n\n// Pass a custom encoding function\nconst paginatedResult = getPaginatedResult(params, limit, result, encrypt);\n\n// Pass a custom decoding function\nconst decodedCursor = decodeCursor(paginatedResult.meta.cursor, decrypt);\n\nconsole.log(decodedCursor);\n// Output:\n// {\n//   TableName: 'UserPets',\n//   Limit: 2,\n//   ExclusiveStartKey: { userId: 1, petId: 2 },\n//   previousKeys: [ { userId: 1, petId: 2 } ],\n//   back: false\n// }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupersoniko%2Fdynamodb-paginator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupersoniko%2Fdynamodb-paginator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupersoniko%2Fdynamodb-paginator/lists"}