@open-aih/payload-ddb 3.1.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +141 -18
  2. package/dist/count.d.ts.map +1 -1
  3. package/dist/count.js +4 -2
  4. package/dist/count.js.map +1 -1
  5. package/dist/countGlobalVersions.d.ts.map +1 -1
  6. package/dist/countGlobalVersions.js +6 -1
  7. package/dist/countGlobalVersions.js.map +1 -1
  8. package/dist/countVersions.d.ts.map +1 -1
  9. package/dist/countVersions.js +6 -1
  10. package/dist/countVersions.js.map +1 -1
  11. package/dist/create.d.ts.map +1 -1
  12. package/dist/create.js +31 -15
  13. package/dist/create.js.map +1 -1
  14. package/dist/createGlobal.d.ts.map +1 -1
  15. package/dist/createGlobal.js +2 -14
  16. package/dist/createGlobal.js.map +1 -1
  17. package/dist/createGlobalVersion.d.ts +1 -1
  18. package/dist/createGlobalVersion.d.ts.map +1 -1
  19. package/dist/createGlobalVersion.js +3 -41
  20. package/dist/createGlobalVersion.js.map +1 -1
  21. package/dist/createVersion.d.ts +6 -5
  22. package/dist/createVersion.d.ts.map +1 -1
  23. package/dist/createVersion.js +8 -48
  24. package/dist/createVersion.js.map +1 -1
  25. package/dist/deleteMany.d.ts +1 -6
  26. package/dist/deleteMany.d.ts.map +1 -1
  27. package/dist/deleteMany.js +8 -19
  28. package/dist/deleteMany.js.map +1 -1
  29. package/dist/deleteOne.d.ts.map +1 -1
  30. package/dist/deleteOne.js +20 -24
  31. package/dist/deleteOne.js.map +1 -1
  32. package/dist/deleteVersions.d.ts.map +1 -1
  33. package/dist/deleteVersions.js +8 -14
  34. package/dist/deleteVersions.js.map +1 -1
  35. package/dist/find.d.ts.map +1 -1
  36. package/dist/find.js +15 -2
  37. package/dist/find.js.map +1 -1
  38. package/dist/findDistinct.d.ts.map +1 -1
  39. package/dist/findDistinct.js +3 -1
  40. package/dist/findDistinct.js.map +1 -1
  41. package/dist/findGlobal.d.ts.map +1 -1
  42. package/dist/findGlobal.js +3 -2
  43. package/dist/findGlobal.js.map +1 -1
  44. package/dist/findGlobalVersions.d.ts.map +1 -1
  45. package/dist/findGlobalVersions.js +10 -2
  46. package/dist/findGlobalVersions.js.map +1 -1
  47. package/dist/findOne.d.ts.map +1 -1
  48. package/dist/findOne.js +17 -6
  49. package/dist/findOne.js.map +1 -1
  50. package/dist/findVersions.d.ts.map +1 -1
  51. package/dist/findVersions.js +10 -2
  52. package/dist/findVersions.js.map +1 -1
  53. package/dist/index.d.ts +2 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +7 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/queryDrafts.d.ts.map +1 -1
  58. package/dist/queryDrafts.js +24 -4
  59. package/dist/queryDrafts.js.map +1 -1
  60. package/dist/updateGlobal.d.ts +5 -4
  61. package/dist/updateGlobal.d.ts.map +1 -1
  62. package/dist/updateGlobal.js +22 -36
  63. package/dist/updateGlobal.js.map +1 -1
  64. package/dist/updateGlobalVersion.d.ts.map +1 -1
  65. package/dist/updateGlobalVersion.js +3 -49
  66. package/dist/updateGlobalVersion.js.map +1 -1
  67. package/dist/updateJobs.d.ts +21 -0
  68. package/dist/updateJobs.d.ts.map +1 -0
  69. package/dist/updateJobs.js +83 -0
  70. package/dist/updateJobs.js.map +1 -0
  71. package/dist/updateMany.d.ts +9 -3
  72. package/dist/updateMany.d.ts.map +1 -1
  73. package/dist/updateMany.js +47 -30
  74. package/dist/updateMany.js.map +1 -1
  75. package/dist/updateOne.d.ts +6 -1
  76. package/dist/updateOne.d.ts.map +1 -1
  77. package/dist/updateOne.js +49 -49
  78. package/dist/updateOne.js.map +1 -1
  79. package/dist/updateVersion.d.ts.map +1 -1
  80. package/dist/updateVersion.js +3 -52
  81. package/dist/updateVersion.js.map +1 -1
  82. package/dist/upsert.d.ts +6 -0
  83. package/dist/upsert.d.ts.map +1 -1
  84. package/dist/upsert.js +57 -41
  85. package/dist/upsert.js.map +1 -1
  86. package/dist/utilities/backfillUniqueGuards.d.ts +42 -0
  87. package/dist/utilities/backfillUniqueGuards.d.ts.map +1 -0
  88. package/dist/utilities/backfillUniqueGuards.js +39 -0
  89. package/dist/utilities/backfillUniqueGuards.js.map +1 -0
  90. package/dist/utilities/buildFilterExpression.d.ts +29 -14
  91. package/dist/utilities/buildFilterExpression.d.ts.map +1 -1
  92. package/dist/utilities/buildFilterExpression.js +55 -14
  93. package/dist/utilities/buildFilterExpression.js.map +1 -1
  94. package/dist/utilities/castWhere.d.ts +84 -0
  95. package/dist/utilities/castWhere.d.ts.map +1 -0
  96. package/dist/utilities/castWhere.js +254 -0
  97. package/dist/utilities/castWhere.js.map +1 -0
  98. package/dist/utilities/findFirst.d.ts +3 -2
  99. package/dist/utilities/findFirst.d.ts.map +1 -1
  100. package/dist/utilities/findFirst.js +14 -46
  101. package/dist/utilities/findFirst.js.map +1 -1
  102. package/dist/utilities/geo.d.ts +36 -0
  103. package/dist/utilities/geo.d.ts.map +1 -0
  104. package/dist/utilities/geo.js +108 -0
  105. package/dist/utilities/geo.js.map +1 -0
  106. package/dist/utilities/mapWithConcurrency.d.ts +12 -0
  107. package/dist/utilities/mapWithConcurrency.d.ts.map +1 -0
  108. package/dist/utilities/mapWithConcurrency.js +32 -0
  109. package/dist/utilities/mapWithConcurrency.js.map +1 -0
  110. package/dist/utilities/matchesWhere.d.ts +25 -5
  111. package/dist/utilities/matchesWhere.d.ts.map +1 -1
  112. package/dist/utilities/matchesWhere.js +150 -38
  113. package/dist/utilities/matchesWhere.js.map +1 -1
  114. package/dist/utilities/operators.d.ts +22 -12
  115. package/dist/utilities/operators.d.ts.map +1 -1
  116. package/dist/utilities/operators.js +36 -31
  117. package/dist/utilities/operators.js.map +1 -1
  118. package/dist/utilities/optimistic.d.ts +29 -0
  119. package/dist/utilities/optimistic.d.ts.map +1 -0
  120. package/dist/utilities/optimistic.js +58 -0
  121. package/dist/utilities/optimistic.js.map +1 -0
  122. package/dist/utilities/prepareWhere.d.ts +63 -0
  123. package/dist/utilities/prepareWhere.d.ts.map +1 -0
  124. package/dist/utilities/prepareWhere.js +198 -0
  125. package/dist/utilities/prepareWhere.js.map +1 -0
  126. package/dist/utilities/queryCount.d.ts +6 -3
  127. package/dist/utilities/queryCount.d.ts.map +1 -1
  128. package/dist/utilities/queryCount.js +16 -45
  129. package/dist/utilities/queryCount.js.map +1 -1
  130. package/dist/utilities/queryMatching.d.ts +8 -7
  131. package/dist/utilities/queryMatching.d.ts.map +1 -1
  132. package/dist/utilities/queryMatching.js +17 -54
  133. package/dist/utilities/queryMatching.js.map +1 -1
  134. package/dist/utilities/queryPartition.d.ts +26 -0
  135. package/dist/utilities/queryPartition.d.ts.map +1 -0
  136. package/dist/utilities/queryPartition.js +55 -0
  137. package/dist/utilities/queryPartition.js.map +1 -0
  138. package/dist/utilities/resolveJoins.d.ts +37 -0
  139. package/dist/utilities/resolveJoins.d.ts.map +1 -0
  140. package/dist/utilities/resolveJoins.js +195 -0
  141. package/dist/utilities/resolveJoins.js.map +1 -0
  142. package/dist/utilities/stripInternalKeys.d.ts +17 -3
  143. package/dist/utilities/stripInternalKeys.d.ts.map +1 -1
  144. package/dist/utilities/stripInternalKeys.js +25 -4
  145. package/dist/utilities/stripInternalKeys.js.map +1 -1
  146. package/dist/utilities/uniqueGuards.d.ts +39 -0
  147. package/dist/utilities/uniqueGuards.d.ts.map +1 -0
  148. package/dist/utilities/uniqueGuards.js +106 -0
  149. package/dist/utilities/uniqueGuards.js.map +1 -0
  150. package/dist/utilities/updateVersionRow.d.ts +19 -0
  151. package/dist/utilities/updateVersionRow.d.ts.map +1 -0
  152. package/dist/utilities/updateVersionRow.js +40 -0
  153. package/dist/utilities/updateVersionRow.js.map +1 -0
  154. package/dist/utilities/writeErrors.d.ts +11 -0
  155. package/dist/utilities/writeErrors.d.ts.map +1 -0
  156. package/dist/utilities/writeErrors.js +27 -0
  157. package/dist/utilities/writeErrors.js.map +1 -0
  158. package/dist/utilities/writeItems.d.ts +124 -0
  159. package/dist/utilities/writeItems.d.ts.map +1 -0
  160. package/dist/utilities/writeItems.js +383 -0
  161. package/dist/utilities/writeItems.js.map +1 -0
  162. package/package.json +21 -14
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/writeItems.ts"],"sourcesContent":["import type { TransactWriteCommandInput } from '@aws-sdk/lib-dynamodb'\n\nimport {\n DeleteCommand,\n GetCommand,\n PutCommand,\n TransactWriteCommand,\n} from '@aws-sdk/lib-dynamodb'\nimport { APIError } from 'payload'\n\nimport type { DynamoAdapter } from '../types.js'\n\nimport { mapWithConcurrency } from './mapWithConcurrency.js'\nimport { normalizeForDynamo } from './normalizeForDynamo.js'\nimport { revisionOf, stripInternalKeys } from './stripInternalKeys.js'\nimport { sameGuard, type UniqueGuard, uniqueGuardsFor } from './uniqueGuards.js'\n\n/**\n * The single place the adapter's methods mutate the table. Every `create*`,\n * `update*`, `upsert` and `delete*` method hands its finished document (or\n * the id to remove) to one of the helpers below instead of building its own\n * DynamoDB command.\n *\n * Keeping writes behind one module means the row's physical shape — the\n * `pk`/`sk` composite key, the `_rev` revision counter, value normalization,\n * and any future index attributes — is derived in exactly one spot\n * (`toItem`), and anything that needs to see every mutation (e.g. buffering\n * writes for a Payload-level transaction) has one seam to hook into.\n *\n * Three guarantees are enforced here, each by a condition DynamoDB checks\n * atomically with the write:\n *\n * - **Insert-only** (`mustNotExist`): a new document can't replace one that\n * already has its id.\n * - **No lost updates** (`replaces`): a read-merge-write only lands if the\n * row is still at the revision that was read. See `stripInternalKeys`.\n * - **Unique fields** (`unique`): the document and a guard row per unique\n * value are written in one transaction. See `uniqueGuards`.\n *\n * Callers stay responsible for everything Payload-shaped: locating the\n * target, merging the patch, defaulting timestamps, and projecting against\n * the collection/global schema. These helpers only persist what they're\n * given.\n *\n * Not routed through here: `scrubUnknownFields`, a one-shot maintenance pass\n * that re-puts raw rows at their original keys without normalizing them.\n */\n\n/**\n * How many single-row writes a bulk operation keeps in flight at once.\n * Matches `BatchWriteItem`'s page size and stays well under the SDK's default\n * socket pool (50), so a large `deleteMany` / `updateMany` doesn't starve\n * every other request the process is making.\n */\nexport const WRITE_CONCURRENCY = 25\n\n/**\n * The write's own precondition didn't hold: the id was already taken\n * (`mustNotExist`), or the row changed since it was read (`replaces`).\n */\nexport class ConditionFailedError extends Error {\n constructor() {\n super('payload-ddb: write condition failed')\n this.name = 'ConditionFailedError'\n }\n}\n\n/** Another document already holds this value of a unique field. */\nexport class UniqueViolationError extends Error {\n readonly path: string\n\n constructor(path: string) {\n super(`payload-ddb: value of unique field \"${path}\" is already in use`)\n this.name = 'UniqueViolationError'\n this.path = path\n }\n}\n\n/**\n * True when `err` means \"this write's precondition didn't hold\" — the signal\n * a read-merge-write loop retries on, and that `create` reports as a\n * duplicate id.\n */\nexport function isConditionalCheckFailed(err: unknown): boolean {\n return (\n err instanceof ConditionFailedError ||\n (err instanceof Error && err.name === 'ConditionalCheckFailedException')\n )\n}\n\nconst ITEM_TOO_LARGE = /item size.*exceeded/i\n\ntype CancellationReason = { Code?: string; Message?: string }\n\nfunction cancellationReasons(err: unknown): CancellationReason[] | null {\n if (!(err instanceof Error) || err.name !== 'TransactionCanceledException') return null\n const reasons = (err as { CancellationReasons?: CancellationReason[] }).CancellationReasons\n return Array.isArray(reasons) ? reasons : []\n}\n\n/**\n * DynamoDB caps a single item at 400 KB and reports a breach as a bare\n * `ValidationException` (or, inside a transaction, as one of the\n * cancellation reasons). Re-throw it as an error that says which document\n * was too big and why, and that Payload will show to the API caller.\n */\nfunction rethrowIfItemTooLarge(err: unknown, partition: string, id: unknown): void {\n if (!(err instanceof Error)) return\n const tooLarge =\n ITEM_TOO_LARGE.test(err.message) ||\n (cancellationReasons(err) ?? []).some((reason) => ITEM_TOO_LARGE.test(reason?.Message ?? ''))\n if (!tooLarge) return\n\n throw new APIError(\n `payload-ddb: document \"${String(id)}\" in \"${partition}\" is too large to store. ` +\n 'DynamoDB limits a single item to 400 KB, including every field and (for versions) the full snapshot.',\n 413,\n null,\n true,\n )\n}\n\nfunction requireDocClient(adapter: DynamoAdapter) {\n const docClient = adapter.docClient\n if (!docClient) {\n throw new Error('payload-ddb: docClient is not initialized — call connect() first.')\n }\n return docClient\n}\n\n/**\n * Composite key for a row. `sk` is always the stringified `id` — collections\n * with Number ids keep the original type on the `id` attribute while the\n * sort key stays String (see `ensureTable`).\n */\nfunction keyFor(partition: string, id: unknown): { pk: string; sk: string } {\n return { pk: partition, sk: String(id) }\n}\n\n/**\n * Turn a Payload-facing document into the row we store: normalized values\n * plus the internal attributes, keyed by the document's own `id`.\n * The inverse of `stripInternalKeys`.\n */\nfunction toItem(\n partition: string,\n doc: Record<string, unknown>,\n revision: number,\n): Record<string, unknown> {\n return normalizeForDynamo({ ...doc, ...keyFor(partition, doc['id']), _rev: revision })\n}\n\ntype Condition = {\n ConditionExpression?: string\n ExpressionAttributeNames?: Record<string, string>\n ExpressionAttributeValues?: Record<string, unknown>\n}\n\n/** \"This guard row is free, or it is already mine.\" */\nfunction ownedBy(owner: string): Required<Condition> {\n return {\n ConditionExpression: 'attribute_not_exists(pk) OR #owner = :owner',\n ExpressionAttributeNames: { '#owner': 'owner' },\n ExpressionAttributeValues: { ':owner': owner },\n }\n}\n\n/**\n * Claim one unique guard for `owner` outside of a document write (used by\n * `backfillUniqueGuards`). Returns `null` when the guard is now the owner's,\n * or the id of the document that already holds it.\n */\nexport async function claimGuard(\n adapter: DynamoAdapter,\n guard: UniqueGuard,\n owner: string,\n): Promise<null | string> {\n const docClient = requireDocClient(adapter)\n try {\n await docClient.send(\n new PutCommand({\n TableName: adapter.tableName,\n Item: { ...guard.key, owner },\n ...ownedBy(owner),\n }),\n )\n return null\n } catch (err) {\n if (!(err instanceof Error) || err.name !== 'ConditionalCheckFailedException') throw err\n const held = await docClient.send(\n new GetCommand({ TableName: adapter.tableName, Key: guard.key, ConsistentRead: true }),\n )\n return String(held.Item?.['owner'] ?? 'unknown')\n }\n}\n\nexport type PutOptions = {\n /** Insert-only: fail if a row already occupies this id. */\n mustNotExist?: boolean\n /**\n * The row, as read, that this write was merged onto. The write lands only\n * if the stored row is still at that revision.\n */\n replaces?: Record<string, unknown>\n /** Enforce the unique fields of this collection for `doc`. */\n unique?: { collection: string }\n}\n\n/**\n * Write `doc` as the full row at (`partition`, `doc.id`). The adapter's\n * update paths are read-merge-write, so this is the write half of both\n * inserts and updates.\n *\n * Throws `ConditionFailedError` when `mustNotExist` / `replaces` doesn't\n * hold, and `UniqueViolationError` when a unique value is taken.\n */\nexport async function putItem(\n adapter: DynamoAdapter,\n partition: string,\n doc: Record<string, unknown>,\n options: PutOptions = {},\n): Promise<void> {\n const docClient = requireDocClient(adapter)\n const { mustNotExist, replaces, unique } = options\n\n const previousRevision = replaces ? revisionOf(replaces) : undefined\n const item = toItem(partition, doc, (previousRevision ?? 0) + 1)\n\n let condition: Condition = {}\n if (mustNotExist) {\n // Every row carries `pk`, so \"no `pk` attribute\" means \"no row here\".\n condition = { ConditionExpression: 'attribute_not_exists(pk)' }\n } else if (replaces && previousRevision === undefined) {\n // Read from a row written before revisions existed: it must still be\n // there, and nobody may have given it a revision in the meantime.\n condition = {\n ConditionExpression: 'attribute_exists(pk) AND attribute_not_exists(#rev)',\n ExpressionAttributeNames: { '#rev': '_rev' },\n }\n } else if (replaces) {\n condition = {\n ConditionExpression: '#rev = :rev',\n ExpressionAttributeNames: { '#rev': '_rev' },\n ExpressionAttributeValues: { ':rev': previousRevision },\n }\n }\n\n const guards = unique ? uniqueGuardsFor(adapter, unique.collection, partition, doc) : []\n // Guards for values this document no longer has. Those are released, but\n // only if they're ours: a row written before guards existed may share a\n // value with the document that later claimed it.\n let released =\n unique && replaces\n ? uniqueGuardsFor(adapter, unique.collection, partition, replaces).filter(\n (old) => !guards.some((current) => sameGuard(current, old)),\n )\n : []\n\n try {\n if (guards.length === 0 && released.length === 0) {\n await docClient.send(\n new PutCommand({ TableName: adapter.tableName, Item: item, ...condition }),\n )\n return\n }\n\n const owner = String(doc['id'])\n const mine = ownedBy(owner)\n\n // At most two passes: if a released guard turns out to belong to someone\n // else, leave it alone and write the rest.\n for (;;) {\n const transactItems: NonNullable<TransactWriteCommandInput['TransactItems']> = [\n { Put: { TableName: adapter.tableName, Item: item, ...condition } },\n // Re-asserted on every write, not only when a value changes, so\n // documents that predate guards pick theirs up as they're edited.\n ...guards.map((guard) => ({\n Put: { TableName: adapter.tableName, Item: { ...guard.key, owner }, ...mine },\n })),\n ...released.map((guard) => ({\n Delete: { TableName: adapter.tableName, Key: guard.key, ...mine },\n })),\n ]\n\n try {\n await docClient.send(new TransactWriteCommand({ TransactItems: transactItems }))\n return\n } catch (err) {\n const reasons = cancellationReasons(err)\n if (!reasons) throw err\n const failed = (index: number) => {\n const code = reasons[index]?.Code\n return code !== undefined && code !== 'None'\n }\n\n if (failed(0)) throw new ConditionFailedError()\n const taken = guards.findIndex((_, index) => failed(1 + index))\n if (taken !== -1) {\n // A clash with a concurrent transaction on the same guard isn't\n // proof the value is taken — let the caller retry and find out.\n if (reasons[1 + taken]?.Code === 'TransactionConflict') throw new ConditionFailedError()\n throw new UniqueViolationError(guards[taken]!.path)\n }\n const kept = released.filter((_, index) => !failed(1 + guards.length + index))\n if (kept.length === released.length) throw err\n released = kept\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === 'ConditionalCheckFailedException') {\n throw new ConditionFailedError()\n }\n rethrowIfItemTooLarge(err, partition, doc['id'])\n throw err\n }\n}\n\nexport type DeleteOptions = {\n returnOld?: boolean\n /**\n * The document being deleted, in a collection with unique fields: its\n * guards are released in the same transaction.\n */\n unique?: { collection: string; doc: Record<string, unknown> }\n}\n\n/**\n * Delete the row at (`partition`, `id`). With `returnOld`, the deleted row\n * comes back (internal keys stripped) so callers can delete and capture the\n * document in one round trip; `null` if no row existed. Without it the\n * result is always `null`.\n */\nexport async function deleteItem(\n adapter: DynamoAdapter,\n partition: string,\n id: unknown,\n options: DeleteOptions = {},\n): Promise<null | Record<string, unknown>> {\n const docClient = requireDocClient(adapter)\n const key = keyFor(partition, id)\n\n const guards = options.unique\n ? uniqueGuardsFor(adapter, options.unique.collection, partition, options.unique.doc)\n : []\n\n if (guards.length > 0) {\n const mine = ownedBy(String(id))\n try {\n await docClient.send(\n new TransactWriteCommand({\n TransactItems: [\n { Delete: { TableName: adapter.tableName, Key: key } },\n ...guards.map((guard) => ({\n Delete: { TableName: adapter.tableName, Key: guard.key, ...mine },\n })),\n ],\n }),\n )\n } catch (err) {\n // A guard that belongs to another document (possible for rows that\n // predate guards) cancels the transaction. The document must still go,\n // so delete it alone and leave that guard with its owner.\n if (!cancellationReasons(err)) throw err\n await docClient.send(new DeleteCommand({ TableName: adapter.tableName, Key: key }))\n }\n return options.returnOld ? options.unique!.doc : null\n }\n\n const result = await docClient.send(\n new DeleteCommand({\n TableName: adapter.tableName,\n Key: key,\n ...(options.returnOld ? { ReturnValues: 'ALL_OLD' as const } : {}),\n }),\n )\n\n return options.returnOld && result.Attributes ? stripInternalKeys(result.Attributes) : null\n}\n\n/**\n * Delete several rows from one partition, one request each, at most\n * `WRITE_CONCURRENCY` in flight at a time. Pass `uniqueCollection` when the\n * rows belong to a collection whose unique guards must be released with them.\n *\n * `BatchWriteItem` could cut the request count (25 deletes per call) but has\n * partial-failure semantics that need retry logic — out of scope until we\n * wire up retries. Bounded single deletes are simple and correct.\n */\nexport async function deleteItems(\n adapter: DynamoAdapter,\n partition: string,\n rows: Record<string, unknown>[],\n uniqueCollection?: string,\n): Promise<void> {\n await mapWithConcurrency(rows, WRITE_CONCURRENCY, (row) =>\n deleteItem(\n adapter,\n partition,\n row['id'],\n uniqueCollection ? { unique: { collection: uniqueCollection, doc: row } } : {},\n ),\n )\n}\n\n/**\n * Insert `doc` as a version row and, in the same `TransactWriteItems` call,\n * clear `latest` on the row that held it before. If a crash occurs mid-flow\n * neither mutation lands, so a parent never ends up with two `latest=true`\n * rows or zero.\n *\n * `previousLatest` is the row the caller found holding `latest=true`, or\n * `null` when this is the first version.\n */\nexport async function putVersionAsLatest(\n adapter: DynamoAdapter,\n partition: string,\n doc: Record<string, unknown>,\n previousLatest: null | Record<string, unknown>,\n): Promise<void> {\n const docClient = requireDocClient(adapter)\n\n const transactItems: NonNullable<TransactWriteCommandInput['TransactItems']> = []\n\n if (previousLatest) {\n transactItems.push({\n Update: {\n TableName: adapter.tableName,\n Key: keyFor(partition, previousLatest['id']),\n // Bumping `_rev` along with the flip means a read-merge-write that\n // read this row while it was still latest can't write `latest` back.\n UpdateExpression: 'SET #latest = :false ADD #rev :one',\n ExpressionAttributeNames: { '#latest': 'latest', '#rev': '_rev' },\n ExpressionAttributeValues: { ':false': false, ':one': 1 },\n // Fail the whole transaction if the previous row was deleted between\n // the caller's read and this transaction. Better to error and let the\n // caller retry than to silently leave the new version with a phantom\n // flip.\n ConditionExpression: 'attribute_exists(pk)',\n },\n })\n }\n\n transactItems.push({\n Put: {\n TableName: adapter.tableName,\n Item: toItem(partition, doc, 1),\n },\n })\n\n try {\n await docClient.send(new TransactWriteCommand({ TransactItems: transactItems }))\n } catch (err) {\n rethrowIfItemTooLarge(err, partition, doc['id'])\n throw err\n }\n}\n"],"names":["DeleteCommand","GetCommand","PutCommand","TransactWriteCommand","APIError","mapWithConcurrency","normalizeForDynamo","revisionOf","stripInternalKeys","sameGuard","uniqueGuardsFor","WRITE_CONCURRENCY","ConditionFailedError","Error","name","UniqueViolationError","path","isConditionalCheckFailed","err","ITEM_TOO_LARGE","cancellationReasons","reasons","CancellationReasons","Array","isArray","rethrowIfItemTooLarge","partition","id","tooLarge","test","message","some","reason","Message","String","requireDocClient","adapter","docClient","keyFor","pk","sk","toItem","doc","revision","_rev","ownedBy","owner","ConditionExpression","ExpressionAttributeNames","ExpressionAttributeValues","claimGuard","guard","send","TableName","tableName","Item","key","held","Key","ConsistentRead","putItem","options","mustNotExist","replaces","unique","previousRevision","undefined","item","condition","guards","collection","released","filter","old","current","length","mine","transactItems","Put","map","Delete","TransactItems","failed","index","code","Code","taken","findIndex","_","kept","deleteItem","returnOld","result","ReturnValues","Attributes","deleteItems","rows","uniqueCollection","row","putVersionAsLatest","previousLatest","push","Update","UpdateExpression"],"mappings":"AAEA,SACEA,aAAa,EACbC,UAAU,EACVC,UAAU,EACVC,oBAAoB,QACf,wBAAuB;AAC9B,SAASC,QAAQ,QAAQ,UAAS;AAIlC,SAASC,kBAAkB,QAAQ,0BAAyB;AAC5D,SAASC,kBAAkB,QAAQ,0BAAyB;AAC5D,SAASC,UAAU,EAAEC,iBAAiB,QAAQ,yBAAwB;AACtE,SAASC,SAAS,EAAoBC,eAAe,QAAQ,oBAAmB;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BC,GAED;;;;;CAKC,GACD,OAAO,MAAMC,oBAAoB,GAAE;AAEnC;;;CAGC,GACD,OAAO,MAAMC,6BAA6BC;IACxC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,iEAAiE,GACjE,OAAO,MAAMC,6BAA6BF;IAC/BG,KAAY;IAErB,YAAYA,IAAY,CAAE;QACxB,KAAK,CAAC,CAAC,oCAAoC,EAAEA,KAAK,mBAAmB,CAAC;QACtE,IAAI,CAACF,IAAI,GAAG;QACZ,IAAI,CAACE,IAAI,GAAGA;IACd;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASC,yBAAyBC,GAAY;IACnD,OACEA,eAAeN,wBACdM,eAAeL,SAASK,IAAIJ,IAAI,KAAK;AAE1C;AAEA,MAAMK,iBAAiB;AAIvB,SAASC,oBAAoBF,GAAY;IACvC,IAAI,CAAEA,CAAAA,eAAeL,KAAI,KAAMK,IAAIJ,IAAI,KAAK,gCAAgC,OAAO;IACnF,MAAMO,UAAU,AAACH,IAAuDI,mBAAmB;IAC3F,OAAOC,MAAMC,OAAO,CAACH,WAAWA,UAAU,EAAE;AAC9C;AAEA;;;;;CAKC,GACD,SAASI,sBAAsBP,GAAY,EAAEQ,SAAiB,EAAEC,EAAW;IACzE,IAAI,CAAET,CAAAA,eAAeL,KAAI,GAAI;IAC7B,MAAMe,WACJT,eAAeU,IAAI,CAACX,IAAIY,OAAO,KAC/B,AAACV,CAAAA,oBAAoBF,QAAQ,EAAE,AAAD,EAAGa,IAAI,CAAC,CAACC,SAAWb,eAAeU,IAAI,CAACG,QAAQC,WAAW;IAC3F,IAAI,CAACL,UAAU;IAEf,MAAM,IAAIxB,SACR,CAAC,uBAAuB,EAAE8B,OAAOP,IAAI,MAAM,EAAED,UAAU,yBAAyB,CAAC,GAC/E,wGACF,KACA,MACA;AAEJ;AAEA,SAASS,iBAAiBC,OAAsB;IAC9C,MAAMC,YAAYD,QAAQC,SAAS;IACnC,IAAI,CAACA,WAAW;QACd,MAAM,IAAIxB,MAAM;IAClB;IACA,OAAOwB;AACT;AAEA;;;;CAIC,GACD,SAASC,OAAOZ,SAAiB,EAAEC,EAAW;IAC5C,OAAO;QAAEY,IAAIb;QAAWc,IAAIN,OAAOP;IAAI;AACzC;AAEA;;;;CAIC,GACD,SAASc,OACPf,SAAiB,EACjBgB,GAA4B,EAC5BC,QAAgB;IAEhB,OAAOrC,mBAAmB;QAAE,GAAGoC,GAAG;QAAE,GAAGJ,OAAOZ,WAAWgB,GAAG,CAAC,KAAK,CAAC;QAAEE,MAAMD;IAAS;AACtF;AAQA,qDAAqD,GACrD,SAASE,QAAQC,KAAa;IAC5B,OAAO;QACLC,qBAAqB;QACrBC,0BAA0B;YAAE,UAAU;QAAQ;QAC9CC,2BAA2B;YAAE,UAAUH;QAAM;IAC/C;AACF;AAEA;;;;CAIC,GACD,OAAO,eAAeI,WACpBd,OAAsB,EACtBe,KAAkB,EAClBL,KAAa;IAEb,MAAMT,YAAYF,iBAAiBC;IACnC,IAAI;QACF,MAAMC,UAAUe,IAAI,CAClB,IAAIlD,WAAW;YACbmD,WAAWjB,QAAQkB,SAAS;YAC5BC,MAAM;gBAAE,GAAGJ,MAAMK,GAAG;gBAAEV;YAAM;YAC5B,GAAGD,QAAQC,MAAM;QACnB;QAEF,OAAO;IACT,EAAE,OAAO5B,KAAK;QACZ,IAAI,CAAEA,CAAAA,eAAeL,KAAI,KAAMK,IAAIJ,IAAI,KAAK,mCAAmC,MAAMI;QACrF,MAAMuC,OAAO,MAAMpB,UAAUe,IAAI,CAC/B,IAAInD,WAAW;YAAEoD,WAAWjB,QAAQkB,SAAS;YAAEI,KAAKP,MAAMK,GAAG;YAAEG,gBAAgB;QAAK;QAEtF,OAAOzB,OAAOuB,KAAKF,IAAI,EAAE,CAAC,QAAQ,IAAI;IACxC;AACF;AAcA;;;;;;;CAOC,GACD,OAAO,eAAeK,QACpBxB,OAAsB,EACtBV,SAAiB,EACjBgB,GAA4B,EAC5BmB,UAAsB,CAAC,CAAC;IAExB,MAAMxB,YAAYF,iBAAiBC;IACnC,MAAM,EAAE0B,YAAY,EAAEC,QAAQ,EAAEC,MAAM,EAAE,GAAGH;IAE3C,MAAMI,mBAAmBF,WAAWxD,WAAWwD,YAAYG;IAC3D,MAAMC,OAAO1B,OAAOf,WAAWgB,KAAK,AAACuB,CAAAA,oBAAoB,CAAA,IAAK;IAE9D,IAAIG,YAAuB,CAAC;IAC5B,IAAIN,cAAc;QAChB,sEAAsE;QACtEM,YAAY;YAAErB,qBAAqB;QAA2B;IAChE,OAAO,IAAIgB,YAAYE,qBAAqBC,WAAW;QACrD,qEAAqE;QACrE,kEAAkE;QAClEE,YAAY;YACVrB,qBAAqB;YACrBC,0BAA0B;gBAAE,QAAQ;YAAO;QAC7C;IACF,OAAO,IAAIe,UAAU;QACnBK,YAAY;YACVrB,qBAAqB;YACrBC,0BAA0B;gBAAE,QAAQ;YAAO;YAC3CC,2BAA2B;gBAAE,QAAQgB;YAAiB;QACxD;IACF;IAEA,MAAMI,SAASL,SAAStD,gBAAgB0B,SAAS4B,OAAOM,UAAU,EAAE5C,WAAWgB,OAAO,EAAE;IACxF,yEAAyE;IACzE,wEAAwE;IACxE,iDAAiD;IACjD,IAAI6B,WACFP,UAAUD,WACNrD,gBAAgB0B,SAAS4B,OAAOM,UAAU,EAAE5C,WAAWqC,UAAUS,MAAM,CACrE,CAACC,MAAQ,CAACJ,OAAOtC,IAAI,CAAC,CAAC2C,UAAYjE,UAAUiE,SAASD,SAExD,EAAE;IAER,IAAI;QACF,IAAIJ,OAAOM,MAAM,KAAK,KAAKJ,SAASI,MAAM,KAAK,GAAG;YAChD,MAAMtC,UAAUe,IAAI,CAClB,IAAIlD,WAAW;gBAAEmD,WAAWjB,QAAQkB,SAAS;gBAAEC,MAAMY;gBAAM,GAAGC,SAAS;YAAC;YAE1E;QACF;QAEA,MAAMtB,QAAQZ,OAAOQ,GAAG,CAAC,KAAK;QAC9B,MAAMkC,OAAO/B,QAAQC;QAErB,yEAAyE;QACzE,2CAA2C;QAC3C,OAAS;YACP,MAAM+B,gBAAyE;gBAC7E;oBAAEC,KAAK;wBAAEzB,WAAWjB,QAAQkB,SAAS;wBAAEC,MAAMY;wBAAM,GAAGC,SAAS;oBAAC;gBAAE;gBAClE,gEAAgE;gBAChE,kEAAkE;mBAC/DC,OAAOU,GAAG,CAAC,CAAC5B,QAAW,CAAA;wBACxB2B,KAAK;4BAAEzB,WAAWjB,QAAQkB,SAAS;4BAAEC,MAAM;gCAAE,GAAGJ,MAAMK,GAAG;gCAAEV;4BAAM;4BAAG,GAAG8B,IAAI;wBAAC;oBAC9E,CAAA;mBACGL,SAASQ,GAAG,CAAC,CAAC5B,QAAW,CAAA;wBAC1B6B,QAAQ;4BAAE3B,WAAWjB,QAAQkB,SAAS;4BAAEI,KAAKP,MAAMK,GAAG;4BAAE,GAAGoB,IAAI;wBAAC;oBAClE,CAAA;aACD;YAED,IAAI;gBACF,MAAMvC,UAAUe,IAAI,CAAC,IAAIjD,qBAAqB;oBAAE8E,eAAeJ;gBAAc;gBAC7E;YACF,EAAE,OAAO3D,KAAK;gBACZ,MAAMG,UAAUD,oBAAoBF;gBACpC,IAAI,CAACG,SAAS,MAAMH;gBACpB,MAAMgE,SAAS,CAACC;oBACd,MAAMC,OAAO/D,OAAO,CAAC8D,MAAM,EAAEE;oBAC7B,OAAOD,SAASlB,aAAakB,SAAS;gBACxC;gBAEA,IAAIF,OAAO,IAAI,MAAM,IAAItE;gBACzB,MAAM0E,QAAQjB,OAAOkB,SAAS,CAAC,CAACC,GAAGL,QAAUD,OAAO,IAAIC;gBACxD,IAAIG,UAAU,CAAC,GAAG;oBAChB,gEAAgE;oBAChE,gEAAgE;oBAChE,IAAIjE,OAAO,CAAC,IAAIiE,MAAM,EAAED,SAAS,uBAAuB,MAAM,IAAIzE;oBAClE,MAAM,IAAIG,qBAAqBsD,MAAM,CAACiB,MAAM,CAAEtE,IAAI;gBACpD;gBACA,MAAMyE,OAAOlB,SAASC,MAAM,CAAC,CAACgB,GAAGL,QAAU,CAACD,OAAO,IAAIb,OAAOM,MAAM,GAAGQ;gBACvE,IAAIM,KAAKd,MAAM,KAAKJ,SAASI,MAAM,EAAE,MAAMzD;gBAC3CqD,WAAWkB;YACb;QACF;IACF,EAAE,OAAOvE,KAAK;QACZ,IAAIA,eAAeL,SAASK,IAAIJ,IAAI,KAAK,mCAAmC;YAC1E,MAAM,IAAIF;QACZ;QACAa,sBAAsBP,KAAKQ,WAAWgB,GAAG,CAAC,KAAK;QAC/C,MAAMxB;IACR;AACF;AAWA;;;;;CAKC,GACD,OAAO,eAAewE,WACpBtD,OAAsB,EACtBV,SAAiB,EACjBC,EAAW,EACXkC,UAAyB,CAAC,CAAC;IAE3B,MAAMxB,YAAYF,iBAAiBC;IACnC,MAAMoB,MAAMlB,OAAOZ,WAAWC;IAE9B,MAAM0C,SAASR,QAAQG,MAAM,GACzBtD,gBAAgB0B,SAASyB,QAAQG,MAAM,CAACM,UAAU,EAAE5C,WAAWmC,QAAQG,MAAM,CAACtB,GAAG,IACjF,EAAE;IAEN,IAAI2B,OAAOM,MAAM,GAAG,GAAG;QACrB,MAAMC,OAAO/B,QAAQX,OAAOP;QAC5B,IAAI;YACF,MAAMU,UAAUe,IAAI,CAClB,IAAIjD,qBAAqB;gBACvB8E,eAAe;oBACb;wBAAED,QAAQ;4BAAE3B,WAAWjB,QAAQkB,SAAS;4BAAEI,KAAKF;wBAAI;oBAAE;uBAClDa,OAAOU,GAAG,CAAC,CAAC5B,QAAW,CAAA;4BACxB6B,QAAQ;gCAAE3B,WAAWjB,QAAQkB,SAAS;gCAAEI,KAAKP,MAAMK,GAAG;gCAAE,GAAGoB,IAAI;4BAAC;wBAClE,CAAA;iBACD;YACH;QAEJ,EAAE,OAAO1D,KAAK;YACZ,mEAAmE;YACnE,uEAAuE;YACvE,0DAA0D;YAC1D,IAAI,CAACE,oBAAoBF,MAAM,MAAMA;YACrC,MAAMmB,UAAUe,IAAI,CAAC,IAAIpD,cAAc;gBAAEqD,WAAWjB,QAAQkB,SAAS;gBAAEI,KAAKF;YAAI;QAClF;QACA,OAAOK,QAAQ8B,SAAS,GAAG9B,QAAQG,MAAM,CAAEtB,GAAG,GAAG;IACnD;IAEA,MAAMkD,SAAS,MAAMvD,UAAUe,IAAI,CACjC,IAAIpD,cAAc;QAChBqD,WAAWjB,QAAQkB,SAAS;QAC5BI,KAAKF;QACL,GAAIK,QAAQ8B,SAAS,GAAG;YAAEE,cAAc;QAAmB,IAAI,CAAC,CAAC;IACnE;IAGF,OAAOhC,QAAQ8B,SAAS,IAAIC,OAAOE,UAAU,GAAGtF,kBAAkBoF,OAAOE,UAAU,IAAI;AACzF;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeC,YACpB3D,OAAsB,EACtBV,SAAiB,EACjBsE,IAA+B,EAC/BC,gBAAyB;IAEzB,MAAM5F,mBAAmB2F,MAAMrF,mBAAmB,CAACuF,MACjDR,WACEtD,SACAV,WACAwE,GAAG,CAAC,KAAK,EACTD,mBAAmB;YAAEjC,QAAQ;gBAAEM,YAAY2B;gBAAkBvD,KAAKwD;YAAI;QAAE,IAAI,CAAC;AAGnF;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeC,mBACpB/D,OAAsB,EACtBV,SAAiB,EACjBgB,GAA4B,EAC5B0D,cAA8C;IAE9C,MAAM/D,YAAYF,iBAAiBC;IAEnC,MAAMyC,gBAAyE,EAAE;IAEjF,IAAIuB,gBAAgB;QAClBvB,cAAcwB,IAAI,CAAC;YACjBC,QAAQ;gBACNjD,WAAWjB,QAAQkB,SAAS;gBAC5BI,KAAKpB,OAAOZ,WAAW0E,cAAc,CAAC,KAAK;gBAC3C,mEAAmE;gBACnE,qEAAqE;gBACrEG,kBAAkB;gBAClBvD,0BAA0B;oBAAE,WAAW;oBAAU,QAAQ;gBAAO;gBAChEC,2BAA2B;oBAAE,UAAU;oBAAO,QAAQ;gBAAE;gBACxD,qEAAqE;gBACrE,sEAAsE;gBACtE,qEAAqE;gBACrE,QAAQ;gBACRF,qBAAqB;YACvB;QACF;IACF;IAEA8B,cAAcwB,IAAI,CAAC;QACjBvB,KAAK;YACHzB,WAAWjB,QAAQkB,SAAS;YAC5BC,MAAMd,OAAOf,WAAWgB,KAAK;QAC/B;IACF;IAEA,IAAI;QACF,MAAML,UAAUe,IAAI,CAAC,IAAIjD,qBAAqB;YAAE8E,eAAeJ;QAAc;IAC/E,EAAE,OAAO3D,KAAK;QACZO,sBAAsBP,KAAKQ,WAAWgB,GAAG,CAAC,KAAK;QAC/C,MAAMxB;IACR;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-aih/payload-ddb",
3
- "version": "3.1.0",
3
+ "version": "4.1.0",
4
4
  "description": "An unofficial database provider for PayloadCMS, utilizing DynamoDb",
5
5
  "keywords": [
6
6
  "payloadcms",
@@ -14,6 +14,7 @@
14
14
  "registry": "https://registry.npmjs.org",
15
15
  "access": "public"
16
16
  },
17
+ "packageManager": "pnpm@10.33.2",
17
18
  "homepage": "https://github.com/AIH-Software/payload-ddb#readme",
18
19
  "bugs": {
19
20
  "url": "https://github.com/AIH-Software/payload-ddb/issues"
@@ -36,6 +37,17 @@
36
37
  "files": [
37
38
  "dist"
38
39
  ],
40
+ "scripts": {
41
+ "build": "swc src -d dist --strip-leading-paths && tsc --emitDeclarationOnly",
42
+ "prepublishOnly": "pnpm run build",
43
+ "docker:start": "docker compose up -d dynamodb-local",
44
+ "docker:stop": "docker compose down",
45
+ "docker:logs": "docker compose logs -f dynamodb-local",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest",
48
+ "typecheck:test": "tsc -p test/tsconfig.json",
49
+ "changeset": "changeset"
50
+ },
39
51
  "peerDependencies": {
40
52
  "payload": ">=3.0.0"
41
53
  },
@@ -45,21 +57,16 @@
45
57
  },
46
58
  "devDependencies": {
47
59
  "@changesets/cli": "^2.27.0",
48
- "@swc/cli": "^0.8.1",
60
+ "@swc/cli": "^0.8.2",
49
61
  "@swc/core": "^1.15.32",
50
62
  "@types/node": "^25.6.0",
51
- "payload": "^3.84.1",
63
+ "payload": "^3.93.0",
52
64
  "typescript": "^6.0.3",
53
- "vitest": "^3.0.0"
65
+ "vitest": "^4.1.12"
54
66
  },
55
- "scripts": {
56
- "build": "swc src -d dist --strip-leading-paths && tsc --emitDeclarationOnly",
57
- "docker:start": "docker compose up -d dynamodb-local",
58
- "docker:stop": "docker compose down",
59
- "docker:logs": "docker compose logs -f dynamodb-local",
60
- "test": "vitest run",
61
- "test:watch": "vitest",
62
- "typecheck:test": "tsc -p test/tsconfig.json",
63
- "changeset": "changeset"
67
+ "pnpm": {
68
+ "onlyBuiltDependencies": [
69
+ "@swc/core"
70
+ ]
64
71
  }
65
- }
72
+ }