@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,588 @@
1
+ "use strict";
2
+ /**
3
+ * Hides how one `putWrites` call's rows commit, and which uploads each outcome
4
+ * releases.
5
+ *
6
+ * A positional write is first-write-wins: a retried task must not overwrite
7
+ * what its first run committed, and a rejection is the expected outcome of a
8
+ * retry, not a failure. A special channel's write overwrites, as every reference
9
+ * checkpointer does, under a compare-and-swap on the row's `writeGroup` so two
10
+ * concurrent calls cannot both release the same superseded payload. Around both,
11
+ * an upload is released only when a read, or the row a rejection returned,
12
+ * proves no live row names it — never on an outcome nothing confirmed.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.commitPendingWrites = commitPendingWrites;
16
+ exports.writeSpecialRow = writeSpecialRow;
17
+ exports.specialRowProbe = specialRowProbe;
18
+ exports.readSpecialRow = readSpecialRow;
19
+ exports.verifyAfterFailure = verifyAfterFailure;
20
+ exports.writeSpecialRowsWithCleanup = writeSpecialRowsWithCleanup;
21
+ exports.writeRegularRows = writeRegularRows;
22
+ exports.reportGuardRejection = reportGuardRejection;
23
+ exports.rejectionProvesForeignRow = rejectionProvesForeignRow;
24
+ const codec_1 = require("../../shared/codec/codec");
25
+ const offloader_1 = require("../../shared/codec/s3/offloader");
26
+ const idempotent_write_1 = require("../../shared/dynamodb/idempotent-write");
27
+ const retry_1 = require("../../shared/dynamodb/retry");
28
+ const table_schema_1 = require("../../shared/dynamodb/table-schema");
29
+ const truncate_1 = require("../../shared/logging/truncate");
30
+ const rows_1 = require("./rows");
31
+ /**
32
+ * Commit one call's pending-write rows, then release the uploads the outcome
33
+ * proves dead.
34
+ *
35
+ * Accepts: `batch` — the call's thread, its encoded rows (positional and
36
+ * special together, in any order), and its signal.
37
+ *
38
+ * Returns: nothing, once every write has settled and the cleanup has run.
39
+ *
40
+ * Throws: the first genuine write failure, after every write has settled and
41
+ * the cleanup has run. A first-write-wins rejection is not a failure.
42
+ */
43
+ async function commitPendingWrites(context, batch) {
44
+ const special = batch.items.filter((item) => item.index < 0);
45
+ const regular = batch.items.filter((item) => item.index >= 0);
46
+ const [specialError, regularOutcome] = await Promise.all([
47
+ writeSpecialRowsWithCleanup(context, batch.threadId, special, batch.signal),
48
+ writeRegularRows(context, regular, batch.signal),
49
+ ]);
50
+ await releaseDeadUploads(context, regularOutcome.deadUploads);
51
+ const firstError = specialError ?? regularOutcome.error;
52
+ if (firstError)
53
+ throw firstError;
54
+ }
55
+ /**
56
+ * Best-effort delete the offloaded objects of uploads this call's rows do not
57
+ * reference, if an offloader is configured. Each key ends in this call's own
58
+ * `writeGroup`, so a row another call wrote in its place never names it.
59
+ */
60
+ async function releaseDeadUploads(context, dead) {
61
+ if (!context.offloader)
62
+ return;
63
+ await (0, offloader_1.cleanUpS3Orphans)(context.offloader, {
64
+ keys: (0, codec_1.collectS3Keys)(dead.map((item) => item.value)),
65
+ operation: 'putWrites',
66
+ logger: context.logger,
67
+ });
68
+ }
69
+ /**
70
+ * Commit one special row, optionally pinned to the `writeGroup` the caller
71
+ * observed.
72
+ *
73
+ * The write takes one of two shapes, and which one is decided by the
74
+ * **descriptor** rather than by the adapter. An item whose payload was
75
+ * offloaded goes out as a one-item `TransactWriteItems` under a client request
76
+ * token, so a re-send of a write the service already applied is discarded
77
+ * instead of landing a second time — which, after a concurrent call has
78
+ * released that row's object, would leave a live row naming nothing. An item
79
+ * whose payload is inline goes out as the plain `PutItem` it has always been,
80
+ * guard fragments and all: it names no object, so its re-land is an ordinary
81
+ * last-write-wins outcome rather than unreadable data, and a transaction would
82
+ * charge twice the write capacity to buy that.
83
+ *
84
+ * The question is the descriptor's because this path runs whenever an offloader
85
+ * is *configured*, and such an adapter still writes inline whenever the payload
86
+ * is under its threshold — so asking the adapter would tokenise writes that
87
+ * strand nothing.
88
+ *
89
+ * `guard` absent means no pin at all, which is the unconditional overwrite the
90
+ * exhausted compare-and-swap below falls back to.
91
+ *
92
+ * Both callers arrive here and the token is worth different things to each. On
93
+ * a pinned attempt the condition already turns a re-send away, so what the
94
+ * token adds is narrower: inside one budget, a re-send of an attempt that
95
+ * *committed* and lost its acknowledgement is answered from the idempotency
96
+ * cache rather than colliding with the `writeGroup` it wrote itself — the
97
+ * collision {@link verifyAfterFailure} otherwise has to spend a read to
98
+ * resolve. On the unconditional overwrite below there is no condition at all,
99
+ * so the token is the only thing standing between a lost acknowledgement and a
100
+ * second landing.
101
+ *
102
+ * A rejection buys nothing either way, and the loop above is built on that: a
103
+ * cancelled attempt commits nothing, so nothing is cached for its token and a
104
+ * retry would be a fresh evaluation — see {@link commitRow}, and the
105
+ * transaction helper it delegates to, for that precondition stated in full.
106
+ * It is why a lost compare-and-swap re-reads and re-pins rather than
107
+ * re-sending, and why each re-pin calls this function afresh for a new token.
108
+ * The deadline inside the helper is what holds each budget within the window
109
+ * the token is honoured for; the token enforces no window itself.
110
+ */
111
+ async function commitSpecialRow(context, item, guard, signal) {
112
+ await (0, idempotent_write_1.commitRow)(context, item, item.value, { guard, signal });
113
+ }
114
+ /**
115
+ * Retry a conditional put up to {@link OVERWRITE_CAS_MAX_ATTEMPTS} times,
116
+ * re-reading the row each time a racer's write invalidates the pinned
117
+ * `writeGroup`. Extracted from {@link writeSpecialRow} to keep both
118
+ * functions under the repo's block-nesting limit.
119
+ *
120
+ * A rejection is not proof a competitor won: `withDynamoDBRetry` retries
121
+ * transient errors, so an attempt can commit server-side, its response can be
122
+ * lost, and the retried put can hit the row it just wrote and fail the same
123
+ * guard — indistinguishable from a competitor's win by the rejection alone.
124
+ * Each attempt's pinned observation is captured in `attempted` before the
125
+ * put, so that when {@link verifyAfterFailure} finds the row already holding
126
+ * *this item's own* `writeGroup`, the outcome reports having superseded
127
+ * whatever `attempted` held — never the item's own just-committed payload,
128
+ * which would strand the live row pointing at a deleted object.
129
+ *
130
+ * Only a rejection whose re-read proves some *other* writer holds the row is
131
+ * retried; every other failure is already settled by the verification.
132
+ *
133
+ * Each iteration calls {@link commitSpecialRow} afresh, so an offloaded item's
134
+ * re-pin draws a new request token. That is required rather than merely tidy:
135
+ * the re-pinned request carries a different `ConditionExpression`, and the same
136
+ * token presented with changed parameters inside the service's window is
137
+ * refused outright.
138
+ */
139
+ async function attemptCasWrites(context, item, initial, signal) {
140
+ let observed = initial;
141
+ for (let attempt = 1; attempt <= idempotent_write_1.OVERWRITE_CAS_MAX_ATTEMPTS; attempt++) {
142
+ const attempted = observed;
143
+ try {
144
+ await commitSpecialRow(context, item, (0, idempotent_write_1.revisionGuard)(rows_1.WRITE_GROUP_ATTRIBUTE, attempted), signal);
145
+ return { done: true, outcome: { committed: true, superseded: attempted.value } };
146
+ }
147
+ catch (error) {
148
+ const verified = await verifyAfterFailure(context, item, attempted, error);
149
+ if (!verified.observed || !(0, idempotent_write_1.isConditionalCheckFailed)(error)) {
150
+ return { done: true, outcome: verified.outcome };
151
+ }
152
+ observed = verified.observed;
153
+ }
154
+ }
155
+ return { done: false, observed };
156
+ }
157
+ /**
158
+ * Overwrite the row unconditionally once the compare-and-swap budget is spent,
159
+ * verifying rather than assuming if that write fails too.
160
+ *
161
+ * This is the call a request token helps most, and the reason it is worth
162
+ * carrying one here at all. Every other write on this path is pinned, so a
163
+ * re-send that arrives after the first attempt already committed is turned away
164
+ * by its own guard; this one has no condition, so nothing but the token stops
165
+ * it landing a second time — over whatever a competitor wrote in between, and
166
+ * over a row whose object a concurrent cleanup has since released. It still
167
+ * takes the shape {@link commitSpecialRow} gives it, so an inline payload is
168
+ * written exactly as before.
169
+ */
170
+ async function overwriteUnconditionally(context, item, observed, signal) {
171
+ try {
172
+ await commitSpecialRow(context, item, undefined, signal);
173
+ return { committed: true, superseded: observed.value };
174
+ }
175
+ catch (error) {
176
+ return (await verifyAfterFailure(context, item, observed, error)).outcome;
177
+ }
178
+ }
179
+ /**
180
+ * The plain put used without an offloader: no object exists to orphan, so no
181
+ * swap and no read. A failure is reported as not committed without verifying,
182
+ * which stays truthful because there is no upload for the caller to keep.
183
+ *
184
+ * It stays a plain put whatever the descriptor says. A row read back from a
185
+ * table an offloading adapter wrote can name an object, but this adapter cannot
186
+ * have uploaded it, so there is nothing here for a token to protect and no
187
+ * reason to pay a transaction's write capacity.
188
+ */
189
+ async function writeWithoutOffloader(context, item, signal) {
190
+ try {
191
+ await (0, retry_1.withDynamoDBRetry)((request) => context.client.put({ TableName: context.tableName, Item: item }, request), (0, retry_1.retryFor)(context, signal));
192
+ return { committed: true };
193
+ }
194
+ catch (error) {
195
+ return { committed: false, error: error };
196
+ }
197
+ }
198
+ /**
199
+ * Overwrite one special row, pinned to the `writeGroup` this call observed, and
200
+ * report the descriptor it superseded.
201
+ *
202
+ * Overwriting is correct for special channels — every reference implementation
203
+ * does it — but two concurrent calls to the same channel both read the same
204
+ * previous descriptor and both delete it, orphaning the loser's upload. Pinning
205
+ * the observed `writeGroup` and re-reading on rejection makes each call
206
+ * supersede exactly one payload.
207
+ *
208
+ * `BatchWriteItem` cannot carry conditions, which is why this path issues
209
+ * individual puts; a call holds at most one row per special channel, so that is
210
+ * four writes at worst.
211
+ *
212
+ * The compare-and-swap runs only when an offloader is configured — matching
213
+ * `store/internal/item-write.ts` — because without one there is no S3 object to
214
+ * orphan, so a plain unconditional put stays correct and costs no extra
215
+ * ConsistentRead or write capacity (see {@link writeWithoutOffloader}).
216
+ *
217
+ * A failure of the first read, before any put, is no verdict read from the row,
218
+ * and this call releases its own upload only on one. It is therefore reported
219
+ * the way every unverified outcome is: `committed: true` with the error, so the
220
+ * caller keeps the upload and leaves it to the lifecycle rule.
221
+ *
222
+ * Accepts: `item` — one special-channel row, carrying this call's `writeGroup`.
223
+ * `signal` — aborts the attempts.
224
+ *
225
+ * Returns: whether this item's upload must be kept (see
226
+ * {@link SpecialWriteOutcome}), the descriptor it superseded when the write
227
+ * committed, and the failure when there was one.
228
+ *
229
+ * Throws: nothing. The caller runs this concurrently with the regular writes
230
+ * under `Promise.all`, whose own cleanup depends on every branch resolving
231
+ * rather than short-circuiting.
232
+ *
233
+ * Guarantees: each call supersedes exactly one payload, so two concurrent calls
234
+ * to the same channel cannot both delete the same object and orphan the loser's
235
+ * upload.
236
+ */
237
+ async function writeSpecialRow(context, item, signal) {
238
+ if (!context.offloader)
239
+ return writeWithoutOffloader(context, item, signal);
240
+ try {
241
+ const initial = await readSpecialRow(context, item);
242
+ const attempt = await attemptCasWrites(context, item, initial, signal);
243
+ if (attempt.done)
244
+ return attempt.outcome;
245
+ context.logger.warn('putWrites: special-write compare-and-swap exhausted; overwriting unconditionally, which ' +
246
+ 'can orphan one S3 object under a concurrent call (reclaimed by ensureS3LifecycleRule)', { sortKey: item.SK, channel: item.channel, attempts: idempotent_write_1.OVERWRITE_CAS_MAX_ATTEMPTS });
247
+ return await overwriteUnconditionally(context, item, attempt.observed, signal);
248
+ }
249
+ catch (error) {
250
+ // The attempts settle every put they issue, so what reaches here is the
251
+ // initial read, before any put, or the warning. Neither is a verdict read
252
+ // from the row, and this call releases its own upload only on one, so it is
253
+ // reported the way every unverified outcome is: kept, for the lifecycle rule.
254
+ return { committed: true, error: error };
255
+ }
256
+ }
257
+ /**
258
+ * The probe that recognises `item`'s own write on its row.
259
+ *
260
+ * Accepts: `item` — the row this call tried to write, carrying its own
261
+ * `writeGroup`.
262
+ *
263
+ * Returns: the probe, which projects the guard attribute and the descriptor —
264
+ * the descriptor because a caller that has to re-pin a compare-and-swap needs
265
+ * the value it lost to, not just the fact that it lost.
266
+ *
267
+ * Throws: nothing.
268
+ */
269
+ function specialRowProbe(item) {
270
+ return {
271
+ key: (0, table_schema_1.rowKeyOf)(item),
272
+ kind: 'attribute',
273
+ attribute: rows_1.WRITE_GROUP_ATTRIBUTE,
274
+ expected: item.writeGroup,
275
+ also: ['value'],
276
+ };
277
+ }
278
+ /** A read row, in the shape the compare-and-swap pins its next attempt to. */
279
+ function stateOf(row) {
280
+ if (!row)
281
+ return { exists: false };
282
+ return {
283
+ exists: true,
284
+ value: row.value,
285
+ revision: row[rows_1.WRITE_GROUP_ATTRIBUTE],
286
+ };
287
+ }
288
+ /**
289
+ * Read a special row's current descriptor and the writeGroup guarding it.
290
+ *
291
+ * Accepts: `item` — the row to read, by its key.
292
+ *
293
+ * Returns: the row's state, with `exists: false` when there is none — which is
294
+ * what a first writer pins its compare-and-swap to.
295
+ *
296
+ * Throws: whatever the read throws. Deliberately not swallowed: the caller
297
+ * reports that failure with its own cause rather than guessing at the row's
298
+ * state, which is why this is separate from {@link verifyAfterFailure}.
299
+ */
300
+ async function readSpecialRow(context, item) {
301
+ return stateOf(await (0, idempotent_write_1.readRow)(context, specialRowProbe(item)));
302
+ }
303
+ /**
304
+ * Read the row back after a put failed, and report what that failure actually
305
+ * did — never assuming it did nothing.
306
+ *
307
+ * A guard rejection already carries the row that turned it away (see
308
+ * `rejectedRow`), so the strongly-consistent read is spent only for a failure
309
+ * that does not: a lost response, or a rejection whose row vanished since.
310
+ *
311
+ * Three answers are possible:
312
+ * - the row holds this item's own `writeGroup`: the write landed, and the
313
+ * descriptor this attempt pinned is the dead one.
314
+ * - the row holds some other group: the write is confirmed not to be what is
315
+ * live, so this item's own upload is dead — its key ends in this call's own
316
+ * group, which the row another writer wrote does not name. `observed` is
317
+ * returned so a rejected compare-and-swap can re-pin and try again.
318
+ * - the read itself fails: nothing is confirmed, so the outcome still reports a
319
+ * commit and keeps the originating error. That leaks one S3 object at worst
320
+ * (reclaimed by `ensureS3LifecycleRule`) where the alternative strands a live
321
+ * row — the same trade `store/internal/item-write.ts` makes.
322
+ *
323
+ * Accepts: `attempted` — the state this attempt pinned, whose descriptor is the
324
+ * one superseded if the write did land. `error` — the failure being explained.
325
+ *
326
+ * Returns: the outcome, and the row's observed state when another writer holds
327
+ * it, so a rejected compare-and-swap can re-pin and try again.
328
+ *
329
+ * Throws: nothing. It exists to turn a failure into a decision.
330
+ *
331
+ * Guarantees: a guard rejection already carries the row that turned it away, so
332
+ * the strongly-consistent read is spent only for a failure that does not — a
333
+ * lost response, or a rejection whose row vanished since.
334
+ */
335
+ async function verifyAfterFailure(context, item, attempted, error) {
336
+ const probe = specialRowProbe(item);
337
+ const rejected = (0, idempotent_write_1.isConditionalCheckFailed)(error) ? (0, idempotent_write_1.rejectedRow)(error) : undefined;
338
+ const { verdict, row } = rejected
339
+ ? { verdict: (0, idempotent_write_1.verdictFor)(probe, rejected), row: rejected }
340
+ : await (0, idempotent_write_1.verifyRow)(context, probe);
341
+ if (verdict === 'landed')
342
+ return { outcome: { committed: true, superseded: attempted.value } };
343
+ if (verdict === 'unverified')
344
+ return { outcome: { committed: true, error } };
345
+ return { outcome: { committed: false, error }, observed: stateOf(row) };
346
+ }
347
+ /**
348
+ * Best-effort delete the S3 objects backing `descriptors`, if offloading is on.
349
+ * An absent entry is skipped, and so is a `null` one, which a row this library
350
+ * did not write can hold. `scope` is given for descriptors read back from rows
351
+ * (the superseded values) and omitted for this call's own uploads.
352
+ */
353
+ async function deleteDescriptors(context, descriptors, label, scope) {
354
+ if (!context.offloader)
355
+ return;
356
+ await (0, offloader_1.cleanUpS3Orphans)(context.offloader, {
357
+ keys: (0, codec_1.collectS3Keys)(descriptors.filter((ref) => Boolean(ref))),
358
+ operation: label,
359
+ logger: context.logger,
360
+ ...(scope === undefined ? {} : { scope }),
361
+ });
362
+ }
363
+ /**
364
+ * Write special (negative-index) rows, then clean up the correct side of each.
365
+ *
366
+ * Overwrite is correct here, matching every reference checkpointer. Each item
367
+ * is written with a compare-and-swap on its row's `writeGroup` (see
368
+ * {@link writeSpecialRow}) so a concurrent call to the same special channel
369
+ * cannot make both callers delete the same superseded object and orphan one
370
+ * upload. A committed item cleans up the payload it actually superseded, and an
371
+ * item confirmed never to have committed cleans up its own new upload. Neither
372
+ * reads the row again first: every call uploads under its own `writeGroup`, so
373
+ * a row another call writes never names this item's upload, and this item's
374
+ * row names only that upload, never the payload it superseded.
375
+ *
376
+ * "Confirmed" is load-bearing, and {@link writeSpecialRow} is what earns it:
377
+ * an ambiguous failure, or a first read of the row that failed, is reported as
378
+ * committed unless a read proves otherwise. Deleting on *unknown* would strand
379
+ * a live row pointing at a deleted object; leaking one object instead is
380
+ * recoverable.
381
+ *
382
+ * Accepts: `items` — this call's special-channel rows; empty writes nothing.
383
+ * `threadId` — the caller's, which scopes every object this cleanup may delete.
384
+ *
385
+ * Returns: the first failure, or undefined when every item committed.
386
+ *
387
+ * Throws: nothing — a failure is reported via the return value, because the
388
+ * caller runs this concurrently with `writeRegularRows` under `Promise.all`,
389
+ * whose own cleanup depends on every branch resolving rather than
390
+ * short-circuiting.
391
+ *
392
+ * Guarantees: a superseded payload is released only once the item that
393
+ * superseded it committed, and an item's own upload only once a read, or the
394
+ * row returned with its rejected write, shows the row holding another call's
395
+ * write or no row at all.
396
+ */
397
+ async function writeSpecialRowsWithCleanup(context, threadId, items, signal) {
398
+ if (items.length === 0)
399
+ return undefined;
400
+ const outcomes = await Promise.all(items.map(async (item) => [
401
+ item,
402
+ await writeSpecialRow(context, item, signal),
403
+ ]));
404
+ await deleteDescriptors(context, outcomes.filter(([, o]) => o.committed).map(([, o]) => o.superseded), 'putWrites.special.previous', [threadId]);
405
+ await deleteDescriptors(context, outcomes.filter(([, o]) => !o.committed).map(([item]) => item.value), 'putWrites.special.newUpload');
406
+ return outcomes.find(([, o]) => o.error)?.[1].error;
407
+ }
408
+ /**
409
+ * First-write-wins, with the row that turned the write away attached to the
410
+ * rejection, so a losing call can tell a duplicate of its own from one another
411
+ * call committed without spending a read.
412
+ */
413
+ const FIRST_WRITE_WINS = {
414
+ ConditionExpression: `attribute_not_exists(${table_schema_1.PARTITION_KEY_ATTRIBUTE})`,
415
+ ReturnValuesOnConditionCheckFailure: 'ALL_OLD',
416
+ };
417
+ /**
418
+ * Commit one regular row under {@link FIRST_WRITE_WINS}.
419
+ *
420
+ * The write takes one of two shapes, and which one is decided by the
421
+ * **descriptor** rather than by the adapter. An item whose payload was
422
+ * offloaded goes out as a one-item `TransactWriteItems` under a client request
423
+ * token, so a re-send of a write the service already applied is discarded
424
+ * instead of landing a second time — which, after the row and its object have
425
+ * been removed by something else, would put back a row naming an object nobody
426
+ * will write again. **That "something else" is not the losing call here**: a
427
+ * regular write only ever releases its own upload, and nothing supersedes a
428
+ * regular-write row. It is a concurrent `deleteThread`, or a `ttl` sweep
429
+ * followed by the S3 lifecycle rule — which is what the re-land test models. An item
430
+ * whose payload is inline goes out as the plain `PutItem` it has always been,
431
+ * guard fragments and all: it names no object, so its re-land is an ordinary
432
+ * first-write-wins outcome rather than unreadable data, and a transaction would
433
+ * charge twice the write capacity to buy that.
434
+ *
435
+ * The question is the descriptor's because an adapter *with* an offloader
436
+ * configured still writes inline whenever the payload is under its threshold,
437
+ * so asking the adapter would tokenise a fan-out of small writes that strand
438
+ * nothing — the very workload this path exists to keep cheap.
439
+ *
440
+ * One item per transaction, never several: a transaction cancels whole, so
441
+ * batching would let one duplicate write — the expected outcome of a retry
442
+ * under first-write-wins — turn away every neighbour it travelled with.
443
+ *
444
+ * What {@link FIRST_WRITE_WINS} changes about the token. It is a condition, so
445
+ * an attempt it turns away commits nothing, DynamoDB caches nothing for that
446
+ * attempt's token, and the retry is a fresh evaluation of first-write-wins
447
+ * against the table as it stands then — the token carries none of it forward,
448
+ * and {@link commitRow}, with the transaction helper it delegates to, is where
449
+ * that precondition is stated in full. What the token does carry is the
450
+ * other half: inside one budget, a re-send of an attempt that *committed* and
451
+ * lost its acknowledgement is answered from the idempotency cache instead of
452
+ * colliding with the row it wrote itself. That collision is the rejection
453
+ * {@link rejectionProvesForeignRow} exists to disbelieve, and on the inline
454
+ * shape it is still live, because a `PutItem` has no token to be answered
455
+ * from.
456
+ *
457
+ * The deadline inside the helper is what keeps the budget within the window
458
+ * the token is honoured for; the token enforces no window of its own. Past it
459
+ * a re-send is a new write, and a new write here is this row put back after a
460
+ * concurrent `deleteThread` released its object, or after a ttl sweep and the
461
+ * lifecycle rule did.
462
+ */
463
+ async function commitWriteRow(context, item, signal) {
464
+ await (0, idempotent_write_1.commitRow)(context, item, item.value, { guard: FIRST_WRITE_WINS, signal });
465
+ }
466
+ /**
467
+ * Resolve a non-guard failure by reading the row back. Without an offloader
468
+ * there is no object to protect, so the write is simply reported as not landed
469
+ * and the caller's cleanup is a no-op. The row holding this call's own
470
+ * `writeGroup` means the put landed and only its response was lost.
471
+ */
472
+ async function verifyFailure(context, item) {
473
+ if (!context.offloader)
474
+ return 'not-landed';
475
+ const { verdict } = await (0, idempotent_write_1.verifyRow)(context, specialRowProbe(item));
476
+ return verdict;
477
+ }
478
+ /**
479
+ * Write regular rows with a first-write-wins guard. Every write fully settles
480
+ * (`Promise.allSettled`) before this resolves and never rejects; a genuine
481
+ * failure is reported via `error`, not thrown. The fan-out is one call per
482
+ * item whichever shape {@link commitWriteRow} gives that item's write.
483
+ *
484
+ * A failure is not proof of a non-commit: `withDynamoDBRetry` re-issues a put
485
+ * whose response was lost, and the re-issues can time out at the transport, so
486
+ * the budget is spent on a `RETRY_EXHAUSTED` error while the row is live.
487
+ * Treating that as "never reached DynamoDB" deleted the object the live row
488
+ * pointed at, making the checkpoint's pending writes unreadable forever. Each
489
+ * such failure is therefore verified against the row before it is classified,
490
+ * and a committed one is not an error at all.
491
+ *
492
+ * Accepts: `items` — this call's regular write rows; empty writes nothing.
493
+ * `signal` — aborts the puts.
494
+ *
495
+ * Returns: which items are known not to have committed — whose own uploads are
496
+ * therefore dead — and the first genuine failure, if any.
497
+ *
498
+ * Throws: nothing. Every put settles before this resolves, because the caller
499
+ * runs it beside the special writes under `Promise.all` and its cleanup depends
500
+ * on every branch resolving rather than short-circuiting.
501
+ *
502
+ * Guarantees: first-write-wins. A rejection means the row is already held, which
503
+ * is the expected outcome of a retry, not a failure.
504
+ */
505
+ async function writeRegularRows(context, items, signal) {
506
+ const results = await Promise.allSettled(items.map((item) => commitWriteRow(context, item, signal)));
507
+ const outcome = { deadUploads: [] };
508
+ for (const [index, result] of results.entries()) {
509
+ if (result.status === 'fulfilled')
510
+ continue;
511
+ const item = items[index];
512
+ const reason = result.reason;
513
+ if ((0, idempotent_write_1.isConditionalCheckFailed)(reason)) {
514
+ reportGuardRejection(context, item, reason);
515
+ if (rejectionProvesForeignRow(item, reason))
516
+ outcome.deadUploads.push(item);
517
+ continue;
518
+ }
519
+ const verdict = await verifyFailure(context, item);
520
+ if (verdict === 'landed')
521
+ continue;
522
+ if (verdict === 'not-landed')
523
+ outcome.deadUploads.push(item);
524
+ outcome.error = outcome.error ?? reason;
525
+ }
526
+ return outcome;
527
+ }
528
+ /**
529
+ * The channel recorded on the row that turned a write away, or undefined when
530
+ * the service returned no attributes (`ReturnValuesOnConditionCheckFailure:
531
+ * 'ALL_OLD'` attaches the existing item to the exception at no extra round trip).
532
+ */
533
+ function rejectedChannel(error) {
534
+ return (0, idempotent_write_1.rejectedRow)(error)?.channel;
535
+ }
536
+ /**
537
+ * Report a guard rejection. Sort keys carry their channel, so a rejection
538
+ * normally means this exact (task, channel, occurrence) row is already
539
+ * committed — a genuine duplicate, and the expected outcome of a retry. A row
540
+ * held by a *different* channel is not something this adapter can produce, so
541
+ * it is reported at `warn`: the write was not persisted and something else
542
+ * wrote to this key space.
543
+ *
544
+ * Accepts: `error` — the rejection, which carries the row that caused it when
545
+ * the service returned attributes. No attributes means the two cases cannot be
546
+ * told apart, and the ordinary duplicate is the one assumed: warning on every
547
+ * unattributed rejection would cry wolf on the expected outcome of a retry.
548
+ *
549
+ * Returns: nothing. A rejection is not a failure here — first-write-wins means
550
+ * losing is a normal outcome — so it is reported, not thrown.
551
+ *
552
+ * Throws: nothing.
553
+ */
554
+ function reportGuardRejection(context, item, error) {
555
+ const found = rejectedChannel(error);
556
+ if (found !== undefined && found !== item.channel) {
557
+ context.logger.warn('putWrites: write row held by an unexpected channel; write not persisted', {
558
+ sortKey: item.SK,
559
+ expected: item.channel,
560
+ found: (0, truncate_1.truncateForLog)(found),
561
+ });
562
+ return;
563
+ }
564
+ context.logger.debug('putWrites: skipped a write already committed for this task and channel', {
565
+ sortKey: item.SK,
566
+ channel: item.channel,
567
+ });
568
+ }
569
+ /**
570
+ * Whether the rejection's returned row provably belongs to another `putWrites`
571
+ * call.
572
+ *
573
+ * Accepts: `error` — the rejection. `item` — the row this call tried to write,
574
+ * carrying its own `writeGroup`.
575
+ *
576
+ * Returns: whether the row that won carries a *different* group, which is the
577
+ * only evidence that this call's own upload is dead and safe to delete. A
578
+ * retried put whose response was lost can be rejected by the row it wrote
579
+ * itself, so an equal group — or no attributes at all — proves nothing and is
580
+ * answered `false`: the object is then left to the lifecycle rule rather than
581
+ * deleted out from under a live row.
582
+ *
583
+ * Throws: nothing.
584
+ */
585
+ function rejectionProvesForeignRow(item, error) {
586
+ const group = (0, idempotent_write_1.rejectedRow)(error)?.writeGroup;
587
+ return group !== undefined && group !== item.writeGroup;
588
+ }