@farukada/aws-langgraph-dynamodb-ts 0.9.0 → 1.0.0-rc.2

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 (512) hide show
  1. package/README.md +1720 -154
  2. package/dist/backfill/backfill.d.ts +168 -0
  3. package/dist/backfill/backfill.js +393 -0
  4. package/dist/checkpointer/actions/delete-thread.d.ts +47 -6
  5. package/dist/checkpointer/actions/delete-thread.js +58 -21
  6. package/dist/checkpointer/actions/get-tuple.d.ts +29 -4
  7. package/dist/checkpointer/actions/get-tuple.js +44 -10
  8. package/dist/checkpointer/actions/list.d.ts +46 -4
  9. package/dist/checkpointer/actions/list.js +121 -66
  10. package/dist/checkpointer/actions/put-writes.d.ts +41 -9
  11. package/dist/checkpointer/actions/put-writes.js +62 -77
  12. package/dist/checkpointer/actions/put.d.ts +83 -4
  13. package/dist/checkpointer/actions/put.js +177 -25
  14. package/dist/checkpointer/internal/delta-history.d.ts +112 -0
  15. package/dist/checkpointer/internal/delta-history.js +252 -0
  16. package/dist/checkpointer/internal/listing.d.ts +149 -0
  17. package/dist/checkpointer/internal/listing.js +245 -0
  18. package/dist/checkpointer/internal/parse.d.ts +262 -0
  19. package/dist/checkpointer/internal/parse.js +372 -0
  20. package/dist/checkpointer/internal/pending-writes.d.ts +275 -0
  21. package/dist/checkpointer/internal/pending-writes.js +588 -0
  22. package/dist/checkpointer/internal/read.d.ts +130 -0
  23. package/dist/checkpointer/internal/read.js +264 -0
  24. package/dist/checkpointer/internal/rows.d.ts +571 -0
  25. package/dist/checkpointer/internal/rows.js +834 -0
  26. package/dist/checkpointer/internal/setup.d.ts +42 -19
  27. package/dist/checkpointer/internal/setup.js +65 -29
  28. package/dist/checkpointer/saver.d.ts +256 -16
  29. package/dist/checkpointer/saver.js +275 -29
  30. package/dist/checkpointer/types.d.ts +39 -39
  31. package/dist/checkpointer/types.js +10 -1
  32. package/dist/factory/factory.d.ts +134 -28
  33. package/dist/factory/factory.js +240 -21
  34. package/dist/factory/types.d.ts +76 -0
  35. package/dist/factory/types.js +10 -0
  36. package/dist/history/actions/add-messages.d.ts +31 -4
  37. package/dist/history/actions/add-messages.js +38 -58
  38. package/dist/history/actions/clear.d.ts +49 -6
  39. package/dist/history/actions/clear.js +66 -14
  40. package/dist/history/actions/get-messages.d.ts +54 -6
  41. package/dist/history/actions/get-messages.js +126 -43
  42. package/dist/history/actions/list-sessions.d.ts +52 -10
  43. package/dist/history/actions/list-sessions.js +139 -40
  44. package/dist/history/actions/reconcile-count.d.ts +42 -10
  45. package/dist/history/actions/reconcile-count.js +45 -45
  46. package/dist/history/chat-message-history.d.ts +220 -33
  47. package/dist/history/chat-message-history.js +240 -43
  48. package/dist/history/internal/append.d.ts +212 -0
  49. package/dist/history/internal/append.js +500 -0
  50. package/dist/history/internal/message-read.d.ts +84 -0
  51. package/dist/history/internal/message-read.js +204 -0
  52. package/dist/history/internal/parse.d.ts +153 -0
  53. package/dist/history/internal/parse.js +252 -0
  54. package/dist/history/internal/rows.d.ts +195 -0
  55. package/dist/history/internal/rows.js +250 -0
  56. package/dist/history/internal/session.d.ts +331 -0
  57. package/dist/history/internal/session.js +628 -0
  58. package/dist/history/internal/setup.d.ts +52 -17
  59. package/dist/history/internal/setup.js +92 -21
  60. package/dist/history/session-adapter.d.ts +102 -7
  61. package/dist/history/session-adapter.js +103 -9
  62. package/dist/history/types.d.ts +80 -29
  63. package/dist/history/types.js +10 -1
  64. package/dist/index.d.ts +42 -11
  65. package/dist/index.js +33 -12
  66. package/dist/shared/adapter.d.ts +135 -0
  67. package/dist/shared/adapter.js +143 -0
  68. package/dist/shared/clock.d.ts +51 -2
  69. package/dist/shared/clock.js +57 -2
  70. package/dist/shared/codec/codec.d.ts +288 -13
  71. package/dist/shared/codec/codec.js +416 -19
  72. package/dist/shared/codec/compression.d.ts +43 -7
  73. package/dist/shared/codec/compression.js +53 -13
  74. package/dist/shared/codec/json-serde.d.ts +76 -4
  75. package/dist/shared/codec/json-serde.js +181 -8
  76. package/dist/shared/codec/s3/client-types.d.ts +53 -0
  77. package/dist/shared/codec/s3/client-types.js +26 -0
  78. package/dist/shared/codec/s3/client.d.ts +43 -10
  79. package/dist/shared/codec/s3/client.js +82 -9
  80. package/dist/shared/codec/s3/config.d.ts +242 -11
  81. package/dist/shared/codec/s3/config.js +293 -11
  82. package/dist/shared/codec/s3/lifecycle.d.ts +164 -6
  83. package/dist/shared/codec/s3/lifecycle.js +335 -27
  84. package/dist/shared/codec/s3/offloader.d.ts +393 -18
  85. package/dist/shared/codec/s3/offloader.js +595 -37
  86. package/dist/shared/concurrency.d.ts +43 -0
  87. package/dist/shared/concurrency.js +78 -0
  88. package/dist/shared/dynamodb/abort.d.ts +47 -0
  89. package/dist/shared/dynamodb/abort.js +59 -0
  90. package/dist/shared/dynamodb/batch-write.d.ts +77 -14
  91. package/dist/shared/dynamodb/batch-write.js +146 -27
  92. package/dist/shared/dynamodb/cancellation.d.ts +121 -4
  93. package/dist/shared/dynamodb/cancellation.js +147 -3
  94. package/dist/shared/dynamodb/client.d.ts +162 -8
  95. package/dist/shared/dynamodb/client.js +153 -5
  96. package/dist/shared/dynamodb/idempotent-write.d.ts +551 -0
  97. package/dist/shared/dynamodb/idempotent-write.js +593 -0
  98. package/dist/shared/dynamodb/paginate.d.ts +105 -9
  99. package/dist/shared/dynamodb/paginate.js +175 -7
  100. package/dist/shared/dynamodb/partition-delete.d.ts +185 -14
  101. package/dist/shared/dynamodb/partition-delete.js +314 -44
  102. package/dist/shared/dynamodb/recency-index.d.ts +231 -0
  103. package/dist/shared/dynamodb/recency-index.js +377 -0
  104. package/dist/shared/dynamodb/retry.d.ts +276 -8
  105. package/dist/shared/dynamodb/retry.js +433 -23
  106. package/dist/shared/dynamodb/table-schema.d.ts +190 -0
  107. package/dist/shared/dynamodb/table-schema.js +209 -0
  108. package/dist/shared/errors/base-error.d.ts +184 -10
  109. package/dist/shared/errors/base-error.js +160 -14
  110. package/dist/shared/errors/boundary.d.ts +71 -0
  111. package/dist/shared/errors/boundary.js +143 -0
  112. package/dist/shared/errors/classify.d.ts +97 -0
  113. package/dist/shared/errors/classify.js +257 -0
  114. package/dist/shared/errors/error-code.d.ts +77 -2
  115. package/dist/shared/errors/error-code.js +83 -1
  116. package/dist/shared/errors/errors.d.ts +158 -59
  117. package/dist/shared/errors/errors.js +219 -92
  118. package/dist/shared/logging/logger.d.ts +69 -3
  119. package/dist/shared/logging/logger.js +97 -3
  120. package/dist/shared/logging/redaction.d.ts +92 -8
  121. package/dist/shared/logging/redaction.js +273 -17
  122. package/dist/shared/logging/secret-patterns.d.ts +149 -19
  123. package/dist/shared/logging/secret-patterns.js +188 -27
  124. package/dist/shared/logging/truncate.d.ts +197 -0
  125. package/dist/shared/logging/truncate.js +231 -0
  126. package/dist/shared/options.d.ts +59 -7
  127. package/dist/shared/options.js +9 -1
  128. package/dist/shared/ulid.d.ts +77 -7
  129. package/dist/shared/ulid.js +103 -8
  130. package/dist/shared/validation/collaborators.d.ts +141 -0
  131. package/dist/shared/validation/collaborators.js +188 -0
  132. package/dist/shared/validation/option-shape.d.ts +89 -0
  133. package/dist/shared/validation/option-shape.js +113 -0
  134. package/dist/shared/validation/options.d.ts +145 -0
  135. package/dist/shared/validation/options.js +328 -0
  136. package/dist/shared/validation/primitives.d.ts +288 -21
  137. package/dist/shared/validation/primitives.js +353 -50
  138. package/dist/shared/validation/ttl.d.ts +66 -10
  139. package/dist/shared/validation/ttl.js +113 -15
  140. package/dist/store/actions/list-namespaces.d.ts +76 -6
  141. package/dist/store/actions/list-namespaces.js +166 -24
  142. package/dist/store/actions/put.d.ts +33 -8
  143. package/dist/store/actions/put.js +53 -60
  144. package/dist/store/actions/reconcile-vector-index.d.ts +31 -10
  145. package/dist/store/actions/reconcile-vector-index.js +34 -15
  146. package/dist/store/actions/search.d.ts +34 -6
  147. package/dist/store/actions/search.js +56 -51
  148. package/dist/store/internal/batch-plan.d.ts +26 -0
  149. package/dist/store/internal/batch-plan.js +109 -0
  150. package/dist/store/internal/filter.d.ts +36 -3
  151. package/dist/store/internal/filter.js +66 -15
  152. package/dist/store/internal/get-item.d.ts +45 -0
  153. package/dist/store/internal/get-item.js +115 -0
  154. package/dist/store/internal/item-write.d.ts +230 -0
  155. package/dist/store/internal/item-write.js +463 -0
  156. package/dist/store/internal/parse.d.ts +225 -0
  157. package/dist/store/internal/parse.js +350 -0
  158. package/dist/store/internal/rows.d.ts +355 -0
  159. package/dist/store/internal/rows.js +447 -0
  160. package/dist/store/internal/semantic-search.d.ts +161 -6
  161. package/dist/store/internal/semantic-search.js +360 -18
  162. package/dist/store/internal/setup.d.ts +77 -20
  163. package/dist/store/internal/setup.js +178 -47
  164. package/dist/store/internal/table-search.d.ts +100 -0
  165. package/dist/store/internal/table-search.js +213 -0
  166. package/dist/store/internal/vector-index.d.ts +247 -0
  167. package/dist/store/internal/vector-index.js +546 -0
  168. package/dist/store/store.d.ts +270 -17
  169. package/dist/store/store.js +329 -38
  170. package/dist/store/types.d.ts +76 -26
  171. package/dist/store/types.js +13 -1
  172. package/dist/store/vector-backend.d.ts +64 -4
  173. package/dist/store/vector-backend.js +15 -1
  174. package/package.json +58 -36
  175. package/dist/checkpointer/actions/delete-thread.d.ts.map +0 -1
  176. package/dist/checkpointer/actions/delete-thread.js.map +0 -1
  177. package/dist/checkpointer/actions/get-tuple.d.ts.map +0 -1
  178. package/dist/checkpointer/actions/get-tuple.js.map +0 -1
  179. package/dist/checkpointer/actions/list.d.ts.map +0 -1
  180. package/dist/checkpointer/actions/list.js.map +0 -1
  181. package/dist/checkpointer/actions/put-writes.d.ts.map +0 -1
  182. package/dist/checkpointer/actions/put-writes.js.map +0 -1
  183. package/dist/checkpointer/actions/put.d.ts.map +0 -1
  184. package/dist/checkpointer/actions/put.js.map +0 -1
  185. package/dist/checkpointer/internal/assemble.d.ts +0 -10
  186. package/dist/checkpointer/internal/assemble.d.ts.map +0 -1
  187. package/dist/checkpointer/internal/assemble.js +0 -37
  188. package/dist/checkpointer/internal/assemble.js.map +0 -1
  189. package/dist/checkpointer/internal/configurable.d.ts +0 -13
  190. package/dist/checkpointer/internal/configurable.d.ts.map +0 -1
  191. package/dist/checkpointer/internal/configurable.js +0 -23
  192. package/dist/checkpointer/internal/configurable.js.map +0 -1
  193. package/dist/checkpointer/internal/fetch.d.ts +0 -10
  194. package/dist/checkpointer/internal/fetch.d.ts.map +0 -1
  195. package/dist/checkpointer/internal/fetch.js +0 -46
  196. package/dist/checkpointer/internal/fetch.js.map +0 -1
  197. package/dist/checkpointer/internal/filter-match.d.ts +0 -12
  198. package/dist/checkpointer/internal/filter-match.d.ts.map +0 -1
  199. package/dist/checkpointer/internal/filter-match.js +0 -14
  200. package/dist/checkpointer/internal/filter-match.js.map +0 -1
  201. package/dist/checkpointer/internal/item-reader.d.ts +0 -55
  202. package/dist/checkpointer/internal/item-reader.d.ts.map +0 -1
  203. package/dist/checkpointer/internal/item-reader.js +0 -88
  204. package/dist/checkpointer/internal/item-reader.js.map +0 -1
  205. package/dist/checkpointer/internal/item-writer.d.ts +0 -26
  206. package/dist/checkpointer/internal/item-writer.d.ts.map +0 -1
  207. package/dist/checkpointer/internal/item-writer.js +0 -92
  208. package/dist/checkpointer/internal/item-writer.js.map +0 -1
  209. package/dist/checkpointer/internal/keys.d.ts +0 -31
  210. package/dist/checkpointer/internal/keys.d.ts.map +0 -1
  211. package/dist/checkpointer/internal/keys.js +0 -87
  212. package/dist/checkpointer/internal/keys.js.map +0 -1
  213. package/dist/checkpointer/internal/query.d.ts +0 -20
  214. package/dist/checkpointer/internal/query.d.ts.map +0 -1
  215. package/dist/checkpointer/internal/query.js +0 -36
  216. package/dist/checkpointer/internal/query.js.map +0 -1
  217. package/dist/checkpointer/internal/setup.d.ts.map +0 -1
  218. package/dist/checkpointer/internal/setup.js.map +0 -1
  219. package/dist/checkpointer/internal/special-write-cas.d.ts +0 -30
  220. package/dist/checkpointer/internal/special-write-cas.d.ts.map +0 -1
  221. package/dist/checkpointer/internal/special-write-cas.js +0 -104
  222. package/dist/checkpointer/internal/special-write-cas.js.map +0 -1
  223. package/dist/checkpointer/internal/special-write-cleanup.d.ts +0 -24
  224. package/dist/checkpointer/internal/special-write-cleanup.d.ts.map +0 -1
  225. package/dist/checkpointer/internal/special-write-cleanup.js +0 -47
  226. package/dist/checkpointer/internal/special-write-cleanup.js.map +0 -1
  227. package/dist/checkpointer/internal/special-write-verify.d.ts +0 -54
  228. package/dist/checkpointer/internal/special-write-verify.d.ts.map +0 -1
  229. package/dist/checkpointer/internal/special-write-verify.js +0 -65
  230. package/dist/checkpointer/internal/special-write-verify.js.map +0 -1
  231. package/dist/checkpointer/internal/validation.d.ts +0 -13
  232. package/dist/checkpointer/internal/validation.d.ts.map +0 -1
  233. package/dist/checkpointer/internal/validation.js +0 -30
  234. package/dist/checkpointer/internal/validation.js.map +0 -1
  235. package/dist/checkpointer/internal/write-guard.d.ts +0 -13
  236. package/dist/checkpointer/internal/write-guard.d.ts.map +0 -1
  237. package/dist/checkpointer/internal/write-guard.js +0 -39
  238. package/dist/checkpointer/internal/write-guard.js.map +0 -1
  239. package/dist/checkpointer/internal/write-index.d.ts +0 -37
  240. package/dist/checkpointer/internal/write-index.d.ts.map +0 -1
  241. package/dist/checkpointer/internal/write-index.js +0 -42
  242. package/dist/checkpointer/internal/write-index.js.map +0 -1
  243. package/dist/checkpointer/saver.d.ts.map +0 -1
  244. package/dist/checkpointer/saver.js.map +0 -1
  245. package/dist/checkpointer/types.d.ts.map +0 -1
  246. package/dist/checkpointer/types.js.map +0 -1
  247. package/dist/factory/factory.d.ts.map +0 -1
  248. package/dist/factory/factory.js.map +0 -1
  249. package/dist/history/actions/add-messages.d.ts.map +0 -1
  250. package/dist/history/actions/add-messages.js.map +0 -1
  251. package/dist/history/actions/clear.d.ts.map +0 -1
  252. package/dist/history/actions/clear.js.map +0 -1
  253. package/dist/history/actions/get-messages.d.ts.map +0 -1
  254. package/dist/history/actions/get-messages.js.map +0 -1
  255. package/dist/history/actions/list-sessions.d.ts.map +0 -1
  256. package/dist/history/actions/list-sessions.js.map +0 -1
  257. package/dist/history/actions/reconcile-count.d.ts.map +0 -1
  258. package/dist/history/actions/reconcile-count.js.map +0 -1
  259. package/dist/history/chat-message-history.d.ts.map +0 -1
  260. package/dist/history/chat-message-history.js.map +0 -1
  261. package/dist/history/internal/append-saga.d.ts +0 -20
  262. package/dist/history/internal/append-saga.d.ts.map +0 -1
  263. package/dist/history/internal/append-saga.js +0 -35
  264. package/dist/history/internal/append-saga.js.map +0 -1
  265. package/dist/history/internal/compensation.d.ts +0 -21
  266. package/dist/history/internal/compensation.d.ts.map +0 -1
  267. package/dist/history/internal/compensation.js +0 -84
  268. package/dist/history/internal/compensation.js.map +0 -1
  269. package/dist/history/internal/item-mapper.d.ts +0 -12
  270. package/dist/history/internal/item-mapper.d.ts.map +0 -1
  271. package/dist/history/internal/item-mapper.js +0 -33
  272. package/dist/history/internal/item-mapper.js.map +0 -1
  273. package/dist/history/internal/keys.d.ts +0 -17
  274. package/dist/history/internal/keys.d.ts.map +0 -1
  275. package/dist/history/internal/keys.js +0 -49
  276. package/dist/history/internal/keys.js.map +0 -1
  277. package/dist/history/internal/message-chunker.d.ts +0 -14
  278. package/dist/history/internal/message-chunker.d.ts.map +0 -1
  279. package/dist/history/internal/message-chunker.js +0 -68
  280. package/dist/history/internal/message-chunker.js.map +0 -1
  281. package/dist/history/internal/message-transaction.d.ts +0 -26
  282. package/dist/history/internal/message-transaction.d.ts.map +0 -1
  283. package/dist/history/internal/message-transaction.js +0 -60
  284. package/dist/history/internal/message-transaction.js.map +0 -1
  285. package/dist/history/internal/query.d.ts +0 -10
  286. package/dist/history/internal/query.d.ts.map +0 -1
  287. package/dist/history/internal/query.js +0 -31
  288. package/dist/history/internal/query.js.map +0 -1
  289. package/dist/history/internal/session-count.d.ts +0 -41
  290. package/dist/history/internal/session-count.d.ts.map +0 -1
  291. package/dist/history/internal/session-count.js +0 -109
  292. package/dist/history/internal/session-count.js.map +0 -1
  293. package/dist/history/internal/session-title.d.ts +0 -20
  294. package/dist/history/internal/session-title.d.ts.map +0 -1
  295. package/dist/history/internal/session-title.js +0 -44
  296. package/dist/history/internal/session-title.js.map +0 -1
  297. package/dist/history/internal/session-update.d.ts +0 -28
  298. package/dist/history/internal/session-update.d.ts.map +0 -1
  299. package/dist/history/internal/session-update.js +0 -70
  300. package/dist/history/internal/session-update.js.map +0 -1
  301. package/dist/history/internal/setup.d.ts.map +0 -1
  302. package/dist/history/internal/setup.js.map +0 -1
  303. package/dist/history/internal/title-generator.d.ts +0 -13
  304. package/dist/history/internal/title-generator.d.ts.map +0 -1
  305. package/dist/history/internal/title-generator.js +0 -25
  306. package/dist/history/internal/title-generator.js.map +0 -1
  307. package/dist/history/internal/ttl-anchor.d.ts +0 -25
  308. package/dist/history/internal/ttl-anchor.d.ts.map +0 -1
  309. package/dist/history/internal/ttl-anchor.js +0 -38
  310. package/dist/history/internal/ttl-anchor.js.map +0 -1
  311. package/dist/history/internal/validation.d.ts +0 -9
  312. package/dist/history/internal/validation.d.ts.map +0 -1
  313. package/dist/history/internal/validation.js +0 -16
  314. package/dist/history/internal/validation.js.map +0 -1
  315. package/dist/history/session-adapter.d.ts.map +0 -1
  316. package/dist/history/session-adapter.js.map +0 -1
  317. package/dist/history/types.d.ts.map +0 -1
  318. package/dist/history/types.js.map +0 -1
  319. package/dist/index.d.ts.map +0 -1
  320. package/dist/index.js.map +0 -1
  321. package/dist/shared/clock.d.ts.map +0 -1
  322. package/dist/shared/clock.js.map +0 -1
  323. package/dist/shared/codec/codec.d.ts.map +0 -1
  324. package/dist/shared/codec/codec.js.map +0 -1
  325. package/dist/shared/codec/compression.d.ts.map +0 -1
  326. package/dist/shared/codec/compression.js.map +0 -1
  327. package/dist/shared/codec/descriptor-keys.d.ts +0 -4
  328. package/dist/shared/codec/descriptor-keys.d.ts.map +0 -1
  329. package/dist/shared/codec/descriptor-keys.js +0 -14
  330. package/dist/shared/codec/descriptor-keys.js.map +0 -1
  331. package/dist/shared/codec/json-serde.d.ts.map +0 -1
  332. package/dist/shared/codec/json-serde.js.map +0 -1
  333. package/dist/shared/codec/s3/client.d.ts.map +0 -1
  334. package/dist/shared/codec/s3/client.js.map +0 -1
  335. package/dist/shared/codec/s3/config.d.ts.map +0 -1
  336. package/dist/shared/codec/s3/config.js.map +0 -1
  337. package/dist/shared/codec/s3/delete.d.ts +0 -8
  338. package/dist/shared/codec/s3/delete.d.ts.map +0 -1
  339. package/dist/shared/codec/s3/delete.js +0 -29
  340. package/dist/shared/codec/s3/delete.js.map +0 -1
  341. package/dist/shared/codec/s3/lifecycle.d.ts.map +0 -1
  342. package/dist/shared/codec/s3/lifecycle.js.map +0 -1
  343. package/dist/shared/codec/s3/offloader.d.ts.map +0 -1
  344. package/dist/shared/codec/s3/offloader.js.map +0 -1
  345. package/dist/shared/codec/s3/orphans.d.ts +0 -18
  346. package/dist/shared/codec/s3/orphans.d.ts.map +0 -1
  347. package/dist/shared/codec/s3/orphans.js +0 -58
  348. package/dist/shared/codec/s3/orphans.js.map +0 -1
  349. package/dist/shared/codec/s3/read-write.d.ts +0 -14
  350. package/dist/shared/codec/s3/read-write.d.ts.map +0 -1
  351. package/dist/shared/codec/s3/read-write.js +0 -43
  352. package/dist/shared/codec/s3/read-write.js.map +0 -1
  353. package/dist/shared/codec/s3/retry.d.ts +0 -5
  354. package/dist/shared/codec/s3/retry.d.ts.map +0 -1
  355. package/dist/shared/codec/s3/retry.js +0 -25
  356. package/dist/shared/codec/s3/retry.js.map +0 -1
  357. package/dist/shared/constants.d.ts +0 -64
  358. package/dist/shared/constants.d.ts.map +0 -1
  359. package/dist/shared/constants.js +0 -67
  360. package/dist/shared/constants.js.map +0 -1
  361. package/dist/shared/dynamodb/backoff.d.ts +0 -15
  362. package/dist/shared/dynamodb/backoff.d.ts.map +0 -1
  363. package/dist/shared/dynamodb/backoff.js +0 -48
  364. package/dist/shared/dynamodb/backoff.js.map +0 -1
  365. package/dist/shared/dynamodb/batch-write.d.ts.map +0 -1
  366. package/dist/shared/dynamodb/batch-write.js.map +0 -1
  367. package/dist/shared/dynamodb/cancellation.d.ts.map +0 -1
  368. package/dist/shared/dynamodb/cancellation.js.map +0 -1
  369. package/dist/shared/dynamodb/client.d.ts.map +0 -1
  370. package/dist/shared/dynamodb/client.js.map +0 -1
  371. package/dist/shared/dynamodb/conditional-put.d.ts +0 -51
  372. package/dist/shared/dynamodb/conditional-put.d.ts.map +0 -1
  373. package/dist/shared/dynamodb/conditional-put.js +0 -59
  374. package/dist/shared/dynamodb/conditional-put.js.map +0 -1
  375. package/dist/shared/dynamodb/drain-unprocessed.d.ts +0 -19
  376. package/dist/shared/dynamodb/drain-unprocessed.d.ts.map +0 -1
  377. package/dist/shared/dynamodb/drain-unprocessed.js +0 -44
  378. package/dist/shared/dynamodb/drain-unprocessed.js.map +0 -1
  379. package/dist/shared/dynamodb/paginate-core.d.ts +0 -22
  380. package/dist/shared/dynamodb/paginate-core.d.ts.map +0 -1
  381. package/dist/shared/dynamodb/paginate-core.js +0 -52
  382. package/dist/shared/dynamodb/paginate-core.js.map +0 -1
  383. package/dist/shared/dynamodb/paginate.d.ts.map +0 -1
  384. package/dist/shared/dynamodb/paginate.js.map +0 -1
  385. package/dist/shared/dynamodb/partition-delete.d.ts.map +0 -1
  386. package/dist/shared/dynamodb/partition-delete.js.map +0 -1
  387. package/dist/shared/dynamodb/retry-classifier.d.ts +0 -9
  388. package/dist/shared/dynamodb/retry-classifier.d.ts.map +0 -1
  389. package/dist/shared/dynamodb/retry-classifier.js +0 -87
  390. package/dist/shared/dynamodb/retry-classifier.js.map +0 -1
  391. package/dist/shared/dynamodb/retry.d.ts.map +0 -1
  392. package/dist/shared/dynamodb/retry.js.map +0 -1
  393. package/dist/shared/dynamodb/scan.d.ts +0 -15
  394. package/dist/shared/dynamodb/scan.d.ts.map +0 -1
  395. package/dist/shared/dynamodb/scan.js +0 -20
  396. package/dist/shared/dynamodb/scan.js.map +0 -1
  397. package/dist/shared/dynamodb/types.d.ts +0 -24
  398. package/dist/shared/dynamodb/types.d.ts.map +0 -1
  399. package/dist/shared/dynamodb/types.js +0 -3
  400. package/dist/shared/dynamodb/types.js.map +0 -1
  401. package/dist/shared/errors/base-error.d.ts.map +0 -1
  402. package/dist/shared/errors/base-error.js.map +0 -1
  403. package/dist/shared/errors/error-code.d.ts.map +0 -1
  404. package/dist/shared/errors/error-code.js.map +0 -1
  405. package/dist/shared/errors/errors.d.ts.map +0 -1
  406. package/dist/shared/errors/errors.js.map +0 -1
  407. package/dist/shared/errors/wrap-error.d.ts +0 -16
  408. package/dist/shared/errors/wrap-error.d.ts.map +0 -1
  409. package/dist/shared/errors/wrap-error.js +0 -30
  410. package/dist/shared/errors/wrap-error.js.map +0 -1
  411. package/dist/shared/logging/logger.d.ts.map +0 -1
  412. package/dist/shared/logging/logger.js.map +0 -1
  413. package/dist/shared/logging/redaction-walk.d.ts +0 -23
  414. package/dist/shared/logging/redaction-walk.d.ts.map +0 -1
  415. package/dist/shared/logging/redaction-walk.js +0 -92
  416. package/dist/shared/logging/redaction-walk.js.map +0 -1
  417. package/dist/shared/logging/redaction.d.ts.map +0 -1
  418. package/dist/shared/logging/redaction.js.map +0 -1
  419. package/dist/shared/logging/secret-patterns.d.ts.map +0 -1
  420. package/dist/shared/logging/secret-patterns.js.map +0 -1
  421. package/dist/shared/options.d.ts.map +0 -1
  422. package/dist/shared/options.js.map +0 -1
  423. package/dist/shared/ulid.d.ts.map +0 -1
  424. package/dist/shared/ulid.js.map +0 -1
  425. package/dist/shared/validation/primitives.d.ts.map +0 -1
  426. package/dist/shared/validation/primitives.js.map +0 -1
  427. package/dist/shared/validation/ttl.d.ts.map +0 -1
  428. package/dist/shared/validation/ttl.js.map +0 -1
  429. package/dist/store/actions/get.d.ts +0 -5
  430. package/dist/store/actions/get.d.ts.map +0 -1
  431. package/dist/store/actions/get.js +0 -35
  432. package/dist/store/actions/get.js.map +0 -1
  433. package/dist/store/actions/list-namespaces.d.ts.map +0 -1
  434. package/dist/store/actions/list-namespaces.js.map +0 -1
  435. package/dist/store/actions/put.d.ts.map +0 -1
  436. package/dist/store/actions/put.js.map +0 -1
  437. package/dist/store/actions/reconcile-vector-index.d.ts.map +0 -1
  438. package/dist/store/actions/reconcile-vector-index.js.map +0 -1
  439. package/dist/store/actions/search.d.ts.map +0 -1
  440. package/dist/store/actions/search.js.map +0 -1
  441. package/dist/store/internal/backend-search.d.ts +0 -5
  442. package/dist/store/internal/backend-search.d.ts.map +0 -1
  443. package/dist/store/internal/backend-search.js +0 -68
  444. package/dist/store/internal/backend-search.js.map +0 -1
  445. package/dist/store/internal/filter.d.ts.map +0 -1
  446. package/dist/store/internal/filter.js.map +0 -1
  447. package/dist/store/internal/index-reconcile.d.ts +0 -22
  448. package/dist/store/internal/index-reconcile.d.ts.map +0 -1
  449. package/dist/store/internal/index-reconcile.js +0 -105
  450. package/dist/store/internal/index-reconcile.js.map +0 -1
  451. package/dist/store/internal/index-sync.d.ts +0 -11
  452. package/dist/store/internal/index-sync.d.ts.map +0 -1
  453. package/dist/store/internal/index-sync.js +0 -26
  454. package/dist/store/internal/index-sync.js.map +0 -1
  455. package/dist/store/internal/item-mapper.d.ts +0 -25
  456. package/dist/store/internal/item-mapper.d.ts.map +0 -1
  457. package/dist/store/internal/item-mapper.js +0 -53
  458. package/dist/store/internal/item-mapper.js.map +0 -1
  459. package/dist/store/internal/keys.d.ts +0 -18
  460. package/dist/store/internal/keys.d.ts.map +0 -1
  461. package/dist/store/internal/keys.js +0 -42
  462. package/dist/store/internal/keys.js.map +0 -1
  463. package/dist/store/internal/namespace-match.d.ts +0 -12
  464. package/dist/store/internal/namespace-match.d.ts.map +0 -1
  465. package/dist/store/internal/namespace-match.js +0 -41
  466. package/dist/store/internal/namespace-match.js.map +0 -1
  467. package/dist/store/internal/overwrite-swap.d.ts +0 -33
  468. package/dist/store/internal/overwrite-swap.d.ts.map +0 -1
  469. package/dist/store/internal/overwrite-swap.js +0 -62
  470. package/dist/store/internal/overwrite-swap.js.map +0 -1
  471. package/dist/store/internal/persist.d.ts +0 -27
  472. package/dist/store/internal/persist.d.ts.map +0 -1
  473. package/dist/store/internal/persist.js +0 -59
  474. package/dist/store/internal/persist.js.map +0 -1
  475. package/dist/store/internal/query.d.ts +0 -6
  476. package/dist/store/internal/query.d.ts.map +0 -1
  477. package/dist/store/internal/query.js +0 -32
  478. package/dist/store/internal/query.js.map +0 -1
  479. package/dist/store/internal/ranker.d.ts +0 -13
  480. package/dist/store/internal/ranker.d.ts.map +0 -1
  481. package/dist/store/internal/ranker.js +0 -31
  482. package/dist/store/internal/ranker.js.map +0 -1
  483. package/dist/store/internal/read-existing.d.ts +0 -19
  484. package/dist/store/internal/read-existing.d.ts.map +0 -1
  485. package/dist/store/internal/read-existing.js +0 -29
  486. package/dist/store/internal/read-existing.js.map +0 -1
  487. package/dist/store/internal/score-direction.d.ts +0 -32
  488. package/dist/store/internal/score-direction.d.ts.map +0 -1
  489. package/dist/store/internal/score-direction.js +0 -39
  490. package/dist/store/internal/score-direction.js.map +0 -1
  491. package/dist/store/internal/search-filter.d.ts +0 -4
  492. package/dist/store/internal/search-filter.d.ts.map +0 -1
  493. package/dist/store/internal/search-filter.js +0 -11
  494. package/dist/store/internal/search-filter.js.map +0 -1
  495. package/dist/store/internal/semantic-search.d.ts.map +0 -1
  496. package/dist/store/internal/semantic-search.js.map +0 -1
  497. package/dist/store/internal/setup.d.ts.map +0 -1
  498. package/dist/store/internal/setup.js.map +0 -1
  499. package/dist/store/internal/validation.d.ts +0 -13
  500. package/dist/store/internal/validation.d.ts.map +0 -1
  501. package/dist/store/internal/validation.js +0 -35
  502. package/dist/store/internal/validation.js.map +0 -1
  503. package/dist/store/internal/write-verify.d.ts +0 -37
  504. package/dist/store/internal/write-verify.d.ts.map +0 -1
  505. package/dist/store/internal/write-verify.js +0 -68
  506. package/dist/store/internal/write-verify.js.map +0 -1
  507. package/dist/store/store.d.ts.map +0 -1
  508. package/dist/store/store.js.map +0 -1
  509. package/dist/store/types.d.ts.map +0 -1
  510. package/dist/store/types.js.map +0 -1
  511. package/dist/store/vector-backend.d.ts.map +0 -1
  512. package/dist/store/vector-backend.js.map +0 -1
@@ -0,0 +1,463 @@
1
+ "use strict";
2
+ /**
3
+ * Hides how an item's row is replaced or removed without stranding its S3
4
+ * object or deleting one a live row still names.
5
+ *
6
+ * A put with an offloader pins its write to the revision it observed and
7
+ * re-reads when a concurrent writer wins; once the budget is spent it
8
+ * overwrites and may leak one object to the lifecycle rule. A delete pins
9
+ * itself the same way. Either releases the payload it superseded only once its
10
+ * own write committed, and a write whose outcome was lost is read back before
11
+ * anything is released. Without an offloader there is no object to protect,
12
+ * and a put is a plain write.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.deleteStoreItem = deleteStoreItem;
16
+ exports.persistRow = persistRow;
17
+ exports.putWithRevisionSwap = putWithRevisionSwap;
18
+ exports.isRetryExhausted = isRetryExhausted;
19
+ exports.verifyWriteLanded = verifyWriteLanded;
20
+ const codec_1 = require("../../shared/codec/codec");
21
+ const offloader_1 = require("../../shared/codec/s3/offloader");
22
+ const idempotent_write_1 = require("../../shared/dynamodb/idempotent-write");
23
+ const retry_1 = require("../../shared/dynamodb/retry");
24
+ const table_schema_1 = require("../../shared/dynamodb/table-schema");
25
+ const base_error_1 = require("../../shared/errors/base-error");
26
+ const error_code_1 = require("../../shared/errors/error-code");
27
+ const rows_1 = require("./rows");
28
+ const vector_index_1 = require("./vector-index");
29
+ /**
30
+ * What a refused attempt licenses next: the observation to re-pin on, or
31
+ * `undefined` for "stop, the row is gone".
32
+ *
33
+ * Two failures end the loop without an error, and they are different events. A
34
+ * cancellation carrying **no** row means the row was deleted between the
35
+ * observation and this attempt, so there is nothing left to remove. A spent
36
+ * retry budget is *ambiguous* — the delete may have landed with only its
37
+ * acknowledgement lost — and is resolved the way `persistRow` resolves its
38
+ * own: with a strongly-consistent read, treating a confirmed absence as a
39
+ * delete that landed. Under a request token that read has little to settle,
40
+ * because every attempt inside one budget re-sends the identical request and a
41
+ * replay is answered from the idempotency cache rather than re-applied; only
42
+ * the last attempt's outcome is in question.
43
+ *
44
+ * `isRowAbsent` reports a read that itself failed as `false` — "not confirmed",
45
+ * never "still there" — so an unknown outcome rethrows and releases nothing.
46
+ */
47
+ async function repinOrResolve(context, key, error) {
48
+ if ((0, idempotent_write_1.isConditionalCheckFailed)(error)) {
49
+ // Raw `AttributeValue`s: `rejectedRow` unmarshalls, `existingFrom` does not.
50
+ const rejected = (0, idempotent_write_1.rejectedRow)(error);
51
+ return rejected === undefined ? undefined : (0, rows_1.existingFrom)(rejected);
52
+ }
53
+ if (isRetryExhausted(error) && (await (0, idempotent_write_1.isRowAbsent)(context, key)))
54
+ return undefined;
55
+ throw error;
56
+ }
57
+ /**
58
+ * Delete the row while it still holds the revision this call observed,
59
+ * re-pinning from each rejection, and report the observation whose descriptor
60
+ * the delete superseded.
61
+ *
62
+ * Returns `undefined` when the compare-and-swap is exhausted: the row is still
63
+ * there, held by whoever kept winning, and nothing may be released because a
64
+ * live row names it.
65
+ *
66
+ * The pin and the token close different failures and the loop needs both. The
67
+ * pin refuses a delete of a row a put replaced after the observation, which
68
+ * takes no lost acknowledgement at all — only a put landing between the
69
+ * pre-read and this write. The token covers the lost acknowledgement, and what
70
+ * it buys is that a rejection reaching the catch below is *informative*:
71
+ * inside one budget the re-send of an attempt that already committed is
72
+ * answered from the idempotency cache rather than turned away by whatever has
73
+ * arrived at the key since — a rejection the loop would re-pin on, deleting
74
+ * next iteration a row this call never read — so a cancellation means a
75
+ * genuine race and not this call's own landed delete reported back as a loss. An unconditional
76
+ * `DeleteItem` can be neither turned away nor deduplicated, which is why the
77
+ * write takes a transaction's shape ({@link deleteIdempotently}).
78
+ *
79
+ * A rejection carries no idempotency forward — a cancelled attempt commits
80
+ * nothing, so nothing is cached for its token — and here that is exactly what
81
+ * is wanted, because the next iteration must be evaluated afresh, against a
82
+ * fresh pin taken from the row the rejection returned. The deadline inside the
83
+ * helper keeps each iteration's retrying within the window its token is
84
+ * honoured for; past that window a re-send is re-evaluated like any other
85
+ * request and the rejection is ambiguous again.
86
+ */
87
+ async function removeObservedRow(context, key, existing) {
88
+ let observed = existing;
89
+ for (let attempt = 1; attempt <= idempotent_write_1.OVERWRITE_CAS_MAX_ATTEMPTS; attempt++) {
90
+ try {
91
+ await (0, idempotent_write_1.deleteIdempotently)(context, key, (0, idempotent_write_1.revisionGuard)(rows_1.REVISION_ATTRIBUTE, observed));
92
+ return observed;
93
+ }
94
+ catch (error) {
95
+ const repinned = await repinOrResolve(context, key, error);
96
+ if (repinned === undefined)
97
+ return observed;
98
+ observed = repinned;
99
+ }
100
+ }
101
+ return undefined;
102
+ }
103
+ /**
104
+ * Delete the item and, when a vector backend is configured, drop its vector.
105
+ *
106
+ * The row is read first, then removed inside a one-item `TransactWriteItems`
107
+ * conditioned on the revision that read observed. An unconditional delete
108
+ * erases a put that commits between the caller's call and the write — no lost
109
+ * acknowledgement needed, no S3 involved — and releases the object that put
110
+ * uploaded. The condition refuses that, and the request token makes a lost
111
+ * acknowledgement harmless: the replay is answered from DynamoDB's idempotency
112
+ * cache instead of removing whatever has arrived since.
113
+ *
114
+ * **A key with no row costs one read and sends no write at all**, which is the
115
+ * same race closed from the other side: there is nothing to pin, so a put that
116
+ * lands mid-call survives. The S3 release and the vector sync still run, since
117
+ * a key with no row can still have a stranded vector and clearing it is a
118
+ * repair path callers have today — and the vector sync goes through the same
119
+ * confirmation as every other path rather than letting the pre-read stand in
120
+ * for it, so the put that lands mid-call keeps its vector too.
121
+ *
122
+ * What a caller can and cannot tell apart:
123
+ *
124
+ * - **Compare-and-swap exhaustion resolves rather than throwing.** Three
125
+ * consecutive writers between a re-pin and its attempt leave the item in
126
+ * place, release nothing — correctly, a live row names the object — and emit
127
+ * one `warn`. Throwing instead would add a failure mode to an interleaving
128
+ * that succeeds today, which every caller deleting in a `finally` would have
129
+ * to handle.
130
+ * - **The vector is dropped only on a confirmation, and that window is
131
+ * narrowed rather than closed.** Immediately before the backend call — and
132
+ * above the S3 cleanup, so no round trip with its own retries sits inside the
133
+ * window — one strongly-consistent projected read asks whether the key holds
134
+ * a row now, and a row that is there keeps its vector and logs one `info`.
135
+ * That covers both interleavings that would otherwise erase a live item's vector: a
136
+ * put recreating the row this call removed, and the compare-and-swap above
137
+ * resolving with the row untouched. What is left is a put committing between
138
+ * that read and the backend call, two adjacent statements apart. Closing it
139
+ * needs a compare-and-swap **on the vector backend** — delete this vector
140
+ * only if it is still the one written at time T — which the `VectorBackend`
141
+ * contract cannot express and no implementation would be obliged to honour,
142
+ * so `reconcileVectorIndex` stays the named repair for it.
143
+ * - **A deadline cut and a spent budget are one error.** The transaction's
144
+ * budget is additionally bounded by `MAX_WRITE_LIFETIME_MS`, so a caller who
145
+ * configures a long retry policy can see the budget end there rather than at
146
+ * its own last attempt; both arrive as `RETRY_EXHAUSTED` and neither says
147
+ * which bound stopped it.
148
+ * - **The pre-read is a new way for this call to fail.** It issues no read
149
+ * today, so a delete of a key with *no row* can now fail where it always
150
+ * succeeded. Nothing has been written when it does: no row removed, no object
151
+ * released, no vector touched. The error types a caller sees are unchanged —
152
+ * `store.delete` already documents `RETRY_EXHAUSTED` — but "deleting an
153
+ * item that is not there is not an error" now describes the outcome rather
154
+ * than the round trip.
155
+ *
156
+ * Accepts: `address` — parsed; the namespace and key the cleanup is scoped and
157
+ * logged by, and the row's key is derived from it.
158
+ *
159
+ * Returns: nothing. The item is gone, was already gone, or — on
160
+ * compare-and-swap exhaustion — is still there and was left alone.
161
+ *
162
+ * Throws: whatever the pre-read throws; whatever the transaction throws other
163
+ * than a guard rejection, which is this call's own business; and
164
+ * `RETRY_EXHAUSTED` when the budget is spent and a read cannot confirm the
165
+ * row is gone. Three things about that list are worth saying rather than
166
+ * leaving to be inferred. The **pre-read** is why a delete of a key with no row
167
+ * can now fail at all, and nothing has been written when it does. A **guard
168
+ * rejection** is refused rather than raised: the row it names was replaced
169
+ * after this call observed it, so removing it would erase that put and release
170
+ * the object the put uploaded, and re-pinning on the row the rejection carried
171
+ * is strictly safer than either raising or proceeding. And **exhausting** those
172
+ * re-pins throws nothing either — it resolves with the item still there and one
173
+ * `warn`, so a caller that needs the item gone re-runs once the key is
174
+ * quiescent rather than catching anything.
175
+ *
176
+ * Guarantees: the object released is the **last observation's**, on every path
177
+ * that releases at all — the pre-read's when nothing re-pinned, the rejected
178
+ * row's when something did. It is never read back from the response, so by
179
+ * construction the object of a delete whose acknowledgement was lost is not
180
+ * leaked. Nothing is released while the outcome is unknown: only a
181
+ * confirmed absence or a confirmed delete licenses it. And the backend's
182
+ * `delete` is never reached without a confirmation immediately before it, on
183
+ * every path including the one whose key never had a row: one rule with no
184
+ * exception, because an exception on a repair-shaped path is where the erasure
185
+ * comes back unnoticed.
186
+ */
187
+ async function deleteStoreItem(context, address) {
188
+ const key = (0, rows_1.itemRowKey)(address);
189
+ const existing = await (0, rows_1.readExisting)(context, key);
190
+ const released = existing.exists ? await removeObservedRow(context, key, existing) : existing;
191
+ if (released === undefined) {
192
+ context.logger.warn('store.delete: compare-and-swap exhausted; the item was not deleted', {
193
+ namespace: address.namespace,
194
+ key: address.key,
195
+ attempts: idempotent_write_1.OVERWRITE_CAS_MAX_ATTEMPTS,
196
+ });
197
+ }
198
+ await (0, vector_index_1.dropVectorWhenGone)(context, address);
199
+ if (context.offloader && released?.value) {
200
+ await (0, offloader_1.cleanUpS3Orphans)(context.offloader, {
201
+ keys: (0, codec_1.collectS3Keys)([released.value]),
202
+ operation: 'store.delete',
203
+ logger: context.logger,
204
+ scope: [...address.namespace, address.key],
205
+ });
206
+ }
207
+ }
208
+ /**
209
+ * Best-effort delete of the S3 object behind `release`, if it names one.
210
+ *
211
+ * `release` is absent when there is nothing to release, and a row this library
212
+ * did not write can hold `null` there, so it is tested for truthiness. `scope`
213
+ * is passed for a descriptor read back from the row (the superseded value) and
214
+ * omitted for this call's own upload.
215
+ */
216
+ async function cleanUp(context, release, label, scope) {
217
+ if (!context.offloader || !release)
218
+ return;
219
+ await (0, offloader_1.cleanUpS3Orphans)(context.offloader, {
220
+ keys: (0, codec_1.collectS3Keys)([release]),
221
+ operation: label,
222
+ logger: context.logger,
223
+ ...(scope === undefined ? {} : { scope }),
224
+ });
225
+ }
226
+ /**
227
+ * Put the record and clean up whichever side is now dead.
228
+ *
229
+ * The compare-and-swap path runs **only when an offloader is configured**:
230
+ * without one there is no S3 object to orphan, so a plain last-write-wins put
231
+ * stays correct and costs no extra write capacity (DynamoDB charges for a
232
+ * failed conditional write too). With one, the swap is what lets this call
233
+ * delete exactly the payload it superseded rather than a descriptor a racer may
234
+ * already have replaced.
235
+ *
236
+ * Every failure reaching the catch arrives after at least one put was issued —
237
+ * `putWithRevisionSwap` only re-reads from inside its own catch — so none of
238
+ * them proves a non-commit on its own: a put can commit server-side and lose
239
+ * its response, and a `ConditionalCheckFailedException` is as consistent with
240
+ * hitting the row this call just wrote as with a competitor's win. The row is
241
+ * therefore read back (`verifyWriteLanded`) before anything is deleted. Only a
242
+ * confirmed `'not-landed'` deletes this record's own object; a confirmed
243
+ * `'landed'` cleans up the previous object like the success path and swallows
244
+ * the error, and an `'unverified'` read deletes nothing and rethrows — leaking
245
+ * one object at worst rather than stranding a live row pointing at a deleted
246
+ * one. The verification compares the per-call `rev`, so an inline record is
247
+ * verified too: otherwise a lost acknowledgement of an inline overwrite would be
248
+ * reported as a failure while the previous offloaded object was never cleaned.
249
+ *
250
+ * Neither release reads the row again first. The record's object is uploaded
251
+ * under the record's own `rev`, which no other put uses, so no row another put
252
+ * commits names it; and the record names only that object, never the one it
253
+ * superseded.
254
+ *
255
+ * Accepts: `record` — the fully encoded row, its payload already uploaded if it
256
+ * was offloaded. `existing` — what the caller read before encoding.
257
+ *
258
+ * Returns: nothing. The row is committed and exactly one side's object, at
259
+ * most, has been released.
260
+ *
261
+ * Throws: whatever the write throws, unless the verification proves the write
262
+ * landed after all — in which case the error is swallowed and the cleanup runs
263
+ * as on the success path.
264
+ *
265
+ * Guarantees: this record's own object is released only after a read proves
266
+ * the write did not land, and a superseded object only after this record is
267
+ * committed. The failure modes are ordered by which is worse: a leaked object
268
+ * costs storage until the lifecycle rule reclaims it, while a row pointing at a
269
+ * deleted object is unreadable data, so every ambiguous case leaks instead of
270
+ * deletes.
271
+ */
272
+ async function persistRow(context, record, existing) {
273
+ let superseded = existing;
274
+ try {
275
+ if (context.offloader) {
276
+ superseded = await putWithRevisionSwap(context, record, existing);
277
+ }
278
+ else {
279
+ await (0, retry_1.withDynamoDBRetry)((request) => context.client.put({ TableName: context.tableName, Item: record }, request), context.retry);
280
+ }
281
+ }
282
+ catch (error) {
283
+ const verdict = await verifyWriteLanded(context, record);
284
+ if (verdict === 'not-landed')
285
+ await cleanUp(context, record.value, 'store.put');
286
+ if (verdict !== 'landed')
287
+ throw error;
288
+ }
289
+ await cleanUp(context, superseded.value, 'store.put.overwrite', [
290
+ ...record.namespace,
291
+ record.key,
292
+ ]);
293
+ }
294
+ /**
295
+ * Put the record, optionally pinned to the revision the caller observed.
296
+ *
297
+ * The write takes one of two shapes, and which one is decided by the
298
+ * **descriptor** rather than by the adapter. A record whose payload was
299
+ * offloaded goes out as a one-item `TransactWriteItems` under a client request
300
+ * token, so a re-send of a write the service already applied is discarded
301
+ * instead of landing a second time — which, after a concurrent operation has
302
+ * released that row's object, would leave a live row naming nothing. A record
303
+ * whose payload is inline goes out as the plain `PutItem` it has always been,
304
+ * guard fragments and all: it names no object, so its re-land is an ordinary
305
+ * last-write-wins outcome rather than unreadable data, and a transaction would
306
+ * charge twice the write capacity to buy that.
307
+ *
308
+ * The question is the descriptor's because an adapter *with* an offloader
309
+ * configured still writes inline whenever the payload is under its threshold,
310
+ * so asking the adapter would tokenise writes that strand nothing.
311
+ *
312
+ * `observed` absent means no pin at all, which is the unconditional write the
313
+ * exhausted swap below falls back to — and the one a token helps most, since
314
+ * with no condition to turn it away nothing else stops a re-send from landing.
315
+ *
316
+ * Two things do change for a caller on the offloaded path, both priced in the
317
+ * design. The budget is additionally bounded by `MAX_WRITE_LIFETIME_MS`, so a
318
+ * caller who configures an aggressively long retry policy can now see it end
319
+ * there rather than at its own last attempt; at the defaults the whole budget
320
+ * is orders of magnitude shorter and the bound is unreachable. And a
321
+ * transaction conflicts with any concurrent write to the same item, so under
322
+ * heavy contention this put can exhaust its budget where a plain `PutItem`
323
+ * would simply have won the race.
324
+ *
325
+ * That bound does end a long budget early, as above, but it is not there as a
326
+ * retry limit of its own: it is what keeps the budget inside the window the
327
+ * token is honoured for. The token enforces no window of its own, and a
328
+ * re-send arriving after it has closed is a new write that lands over whatever
329
+ * has replaced this row and names an object a concurrent release may already
330
+ * have taken away.
331
+ *
332
+ * The pin decides which half of the token's guarantee applies, and the swap
333
+ * below is written around the answer. An attempt the guard turns away commits
334
+ * nothing, so nothing is cached for its token and a retry would be a fresh
335
+ * evaluation — {@link commitRow}, and the transaction helper it delegates to,
336
+ * state that precondition in full —
337
+ * which is why a loss is
338
+ * answered by re-reading and re-pinning under a new token rather than by
339
+ * re-sending this one. What the token does cover is a
340
+ * *committed* attempt whose acknowledgement was lost: within one budget its
341
+ * re-send is answered from the idempotency cache instead of being turned away
342
+ * by the `rev` it wrote itself, which is the rejection the swap below resolves
343
+ * by re-reading, and which the inline shape can still produce.
344
+ */
345
+ async function put(context, record, observed) {
346
+ const guard = observed ? (0, idempotent_write_1.revisionGuard)(rows_1.REVISION_ATTRIBUTE, observed) : undefined;
347
+ await (0, idempotent_write_1.commitRow)(context, record, record.value, { guard });
348
+ }
349
+ /**
350
+ * Commit `record`, re-reading and retrying while another writer holds the row,
351
+ * and return the state this write actually superseded — the only descriptor
352
+ * safe to delete afterwards.
353
+ *
354
+ * Without the swap both racers read the same previous descriptor, both commit,
355
+ * and both delete it, orphaning the loser's own upload. Retrying against the
356
+ * *re-read* state is what makes each writer supersede exactly one payload.
357
+ *
358
+ * A rejection is not proof a competitor won: `withDynamoDBRetry` retries
359
+ * transient errors, so an attempt can commit server-side, its response can be
360
+ * lost, and the retried put can hit the row it just wrote and fail the same
361
+ * guard — indistinguishable from a competitor's win by the rejection alone.
362
+ * Each attempt's pinned observation is captured in `attempted` before the
363
+ * put, so that when a re-read finds the row already holding *this call's
364
+ * own* `rev`, the swap returns whatever `attempted` held — never this
365
+ * record's own just-committed value, which would strand the live row
366
+ * pointing at a deleted object. That comparison is guarded on `rev` being
367
+ * set: `rev` is optional on the record type, and an unnonced record against a
368
+ * pre-0.9.0 revision-less row would otherwise match `undefined === undefined`
369
+ * and claim a race it never entered.
370
+ *
371
+ * On exhaustion the write proceeds unconditionally and warns. That is
372
+ * deliberate: the fallback is precisely the pre-0.9.0 behaviour — one possible
373
+ * orphan, reclaimed by a lifecycle rule — so pathological contention degrades
374
+ * instead of turning a working put into an error. `createdAt` is refreshed from
375
+ * each re-read so a row created by whoever won keeps its true creation time.
376
+ *
377
+ * Accepts: `record` — the row to commit, carrying this call's own `rev`.
378
+ * `existing` — what the caller read before encoding, used as the first pin; an
379
+ * `exists: false` observation pins "no row", so a creation races correctly too.
380
+ *
381
+ * Returns: the state this write actually superseded — the descriptor safe to
382
+ * delete — which is the last observation the winning put was pinned to, never
383
+ * this record's own value.
384
+ *
385
+ * Throws: whatever the put throws other than a conditional-check failure; those
386
+ * are the swap's own business.
387
+ *
388
+ * Guarantees: at most {@link OVERWRITE_CAS_MAX_ATTEMPTS} conditional puts, and
389
+ * a re-read only when the rejection did not already carry the row that caused
390
+ * it.
391
+ */
392
+ async function putWithRevisionSwap(context, record, existing) {
393
+ let observed = existing;
394
+ for (let attempt = 1; attempt <= idempotent_write_1.OVERWRITE_CAS_MAX_ATTEMPTS; attempt++) {
395
+ const attempted = observed;
396
+ try {
397
+ await put(context, record, attempted);
398
+ return attempted;
399
+ }
400
+ catch (error) {
401
+ const rejection = error;
402
+ if (!(0, idempotent_write_1.isConditionalCheckFailed)(rejection))
403
+ throw rejection;
404
+ // The rejection carries the row that turned it away; the read is spent only when it does not.
405
+ const rejected = (0, idempotent_write_1.rejectedRow)(rejection);
406
+ observed = rejected ? (0, rows_1.existingFrom)(rejected) : await (0, rows_1.readExisting)(context, (0, table_schema_1.rowKeyOf)(record));
407
+ if (record.rev !== undefined && observed.revision === record.rev)
408
+ return attempted;
409
+ // A row that vanished between attempts (a concurrent delete) makes this a fresh creation.
410
+ record.createdAt = observed.exists
411
+ ? (observed.createdAt ?? record.createdAt)
412
+ : record.updatedAt;
413
+ }
414
+ }
415
+ context.logger.warn('store.put: compare-and-swap exhausted; overwriting unconditionally, which can orphan one ' +
416
+ 'S3 object under a concurrent put (reclaimed by ensureS3LifecycleRule)', { namespace: record.namespace, key: record.key, attempts: idempotent_write_1.OVERWRITE_CAS_MAX_ATTEMPTS });
417
+ await put(context, record);
418
+ return observed;
419
+ }
420
+ /**
421
+ * Whether `error` is a spent retry budget.
422
+ *
423
+ * Accepts: any error, and equally anything else a `throw` can produce.
424
+ * Recognised by brand and code: the code is the one thing an error crossing a
425
+ * module or realm boundary can be relied on to keep.
426
+ *
427
+ * Returns: whether the write is ambiguous for the reason retries were spent,
428
+ * which is the only failure a verification read is allowed to resolve.
429
+ *
430
+ * Throws: **nothing**, for any value. A value carrying no such code is not a
431
+ * spent budget, so the caller rethrows it rather than spending a read on it.
432
+ */
433
+ function isRetryExhausted(error) {
434
+ return (0, base_error_1.hasErrorCode)(error, error_code_1.ErrorCode.RETRY_EXHAUSTED);
435
+ }
436
+ /**
437
+ * Read `record`'s row back to establish what an ambiguous write actually did,
438
+ * comparing the row's revision with the one this write carried. Every put
439
+ * stamps a fresh per-call `rev`, so the comparison works for inline and
440
+ * offloaded records alike.
441
+ *
442
+ * Accepts: `record` — the row this call wrote, carrying the `rev` it stamped.
443
+ * A record with no `rev` has nothing to compare and is reported `'not-landed'`
444
+ * without spending a read.
445
+ *
446
+ * Returns: `'landed'`, `'not-landed'` or `'unverified'`; see
447
+ * {@link WriteVerdict} for what each answer licenses the caller to do. Only the
448
+ * `rev` is read: an offloaded record's key ends in that same `rev`, so the row
449
+ * holding a different one never names this write's object, and a cleanup
450
+ * needs nothing more from it.
451
+ *
452
+ * Throws: nothing — a failed verification is `'unverified'`, which is an
453
+ * answer, not an error.
454
+ */
455
+ async function verifyWriteLanded(context, record) {
456
+ const { verdict } = await (0, idempotent_write_1.verifyRow)(context, {
457
+ key: (0, table_schema_1.rowKeyOf)(record),
458
+ kind: 'attribute',
459
+ attribute: rows_1.REVISION_ATTRIBUTE,
460
+ expected: record.rev,
461
+ });
462
+ return verdict;
463
+ }