@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,546 @@
1
+ "use strict";
2
+ /**
3
+ * Hides the vector backend as a copy of the items' embeddings.
4
+ *
5
+ * When a store is given a `VectorBackend`, every item's embedding is kept there
6
+ * as well as the item in the table, and the table is the truth. When the copy
7
+ * is written (after the row commits), when an entry is dropped (only once a
8
+ * fresh read finds the row gone), how a backend's answer is resolved back to
9
+ * the canonical items and in which direction its scores run, and how the copy
10
+ * is repaired against the table are decided here, and nothing else calls the
11
+ * backend.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.hasVectorBackend = hasVectorBackend;
15
+ exports.itemVector = itemVector;
16
+ exports.syncItemVector = syncItemVector;
17
+ exports.dropVectorWhenGone = dropVectorWhenGone;
18
+ exports.collectReconcileTargets = collectReconcileTargets;
19
+ exports.pushEmbeddings = pushEmbeddings;
20
+ exports.selectOrphans = selectOrphans;
21
+ exports.pruneOrphans = pruneOrphans;
22
+ exports.reconcileVectors = reconcileVectors;
23
+ exports.searchViaBackend = searchViaBackend;
24
+ exports.toRelevanceScores = toRelevanceScores;
25
+ const clock_1 = require("../../shared/clock");
26
+ const concurrency_1 = require("../../shared/concurrency");
27
+ const idempotent_write_1 = require("../../shared/dynamodb/idempotent-write");
28
+ const paginate_1 = require("../../shared/dynamodb/paginate");
29
+ const retry_1 = require("../../shared/dynamodb/retry");
30
+ const table_schema_1 = require("../../shared/dynamodb/table-schema");
31
+ const base_error_1 = require("../../shared/errors/base-error");
32
+ const errors_1 = require("../../shared/errors/errors");
33
+ const truncate_1 = require("../../shared/logging/truncate");
34
+ const filter_1 = require("./filter");
35
+ const get_item_1 = require("./get-item");
36
+ const parse_1 = require("./parse");
37
+ const rows_1 = require("./rows");
38
+ const semantic_search_1 = require("./semantic-search");
39
+ /**
40
+ * Whether the store keeps a vector copy.
41
+ *
42
+ * Accepts: `context` — the store's.
43
+ *
44
+ * Returns: `true`, narrowing `context`, when both `index` and `vectorBackend`
45
+ * are configured.
46
+ *
47
+ * Throws: nothing.
48
+ */
49
+ function hasVectorBackend(context) {
50
+ return context.index !== undefined && context.vectorBackend !== undefined;
51
+ }
52
+ /**
53
+ * The one vector a put gives the backend for its item.
54
+ *
55
+ * Accepts: `op` — the parsed put. Its `index` is `false` to embed nothing, a
56
+ * field list to embed those fields, absent to embed the configured ones.
57
+ *
58
+ * Returns: the joined embedding, or `undefined` when the store keeps no vector
59
+ * copy, the put indexes nothing, or the value has no text to embed.
60
+ *
61
+ * Throws: `VALIDATION` naming `index.dims` when the model returns a vector of
62
+ * another length; whatever `embedDocuments` throws.
63
+ */
64
+ async function itemVector(context, op) {
65
+ if (!context.vectorBackend || op.index === false)
66
+ return undefined;
67
+ return (0, semantic_search_1.embedValue)(context, op.value, op.index);
68
+ }
69
+ /**
70
+ * Write an item's entry in the vector copy after its row has committed: the
71
+ * vector when there is one, a delete when there is none. Best-effort sync of
72
+ * one item's embedding to the vector backend after the canonical DynamoDB
73
+ * write has already succeeded.
74
+ *
75
+ * Accepts: `address` — the item's. `embedding` — from {@link itemVector}:
76
+ * present upserts it; absent deletes any vector the backend still holds, which
77
+ * is what a re-put with no indexable text, an `index: false` put and a delete
78
+ * all mean.
79
+ *
80
+ * Returns: nothing, in both the synced and the failed case; without a backend,
81
+ * nothing is done.
82
+ *
83
+ * Throws: nothing. The canonical item is already committed, so failing here
84
+ * would report a put that in fact succeeded; the drift is logged at `warn` and
85
+ * `reconcileVectorIndex` repairs it.
86
+ */
87
+ async function syncItemVector(context, address, embedding) {
88
+ const backend = context.vectorBackend;
89
+ if (backend === undefined)
90
+ return;
91
+ try {
92
+ if (embedding)
93
+ await backend.upsert(address.namespace, address.key, embedding);
94
+ else
95
+ await backend.delete(address.namespace, address.key);
96
+ }
97
+ catch (error) {
98
+ // The name, not the message: a backend's error text is not an identifier.
99
+ // Bounded all the same — the name is the backend's own and nothing this
100
+ // package ran checked its length, and `message` is bounded where
101
+ // `redactedMessage` relays it, so relaying the name whole would split what
102
+ // is one value. The literal does not name a method, because both
103
+ // `store.put` and `store.delete` reach here and reporting a failed delete
104
+ // as a failed put sends an operator to the wrong call site; `operation`
105
+ // carries which one.
106
+ context.logger.warn('store vector-index sync failed; reconcileVectorIndex will repair', {
107
+ namespace: address.namespace,
108
+ key: address.key,
109
+ operation: embedding ? 'upsert' : 'delete',
110
+ reason: (0, truncate_1.truncateForLog)((0, base_error_1.failureLabel)(error)),
111
+ });
112
+ }
113
+ }
114
+ /**
115
+ * Drop the item's vector, but only on a fresh read that finds no row at the
116
+ * key.
117
+ *
118
+ * The question is deliberately **not** "did this call remove the row" — that
119
+ * one is true in exactly the interleaving that goes wrong. It is "does the key
120
+ * hold a row *now*", which a racing put that recreated it and a
121
+ * compare-and-swap that left it alone both answer the same way, and which costs
122
+ * a point read of this library's own table rather than anything the backend has
123
+ * to offer. The reconciler asks the same question before pruning a vector, so
124
+ * the delete path and the reconciler are equally careful.
125
+ *
126
+ * A read that itself fails answers "not confirmed" and keeps the vector: a
127
+ * stale vector for a deleted item, which `reconcileVectorIndex` removes, rather
128
+ * than a missing one for a live item, which is the defect this exists for.
129
+ *
130
+ * Accepts: `address` — the deleted item's; the row read is derived from it.
131
+ *
132
+ * Returns: nothing; without a backend, nothing is read or dropped. A row still
133
+ * at the key keeps its vector and logs one `info`.
134
+ *
135
+ * Throws: nothing the backend throws (see {@link syncItemVector}); whatever the
136
+ * confirmation read throws that `isRowAbsent` does not answer as "not
137
+ * confirmed".
138
+ */
139
+ async function dropVectorWhenGone(context, address) {
140
+ if (context.vectorBackend === undefined)
141
+ return;
142
+ const key = (0, rows_1.itemRowKey)(address);
143
+ if (!(await (0, idempotent_write_1.isRowAbsent)(context, key))) {
144
+ context.logger.info('store.delete: kept a vector whose item was not confirmed gone', {
145
+ namespace: address.namespace,
146
+ key: address.key,
147
+ });
148
+ return;
149
+ }
150
+ await syncItemVector(context, address, undefined);
151
+ }
152
+ /** Stable, collision-free identity for a (namespace, key) pair. */
153
+ function refIdentity(namespace, key) {
154
+ return JSON.stringify([...namespace, key]);
155
+ }
156
+ /** Decode the buffered rows with the same bounded concurrency the search path uses. */
157
+ async function drainPending(context, pending, live, signal) {
158
+ if (pending.length === 0)
159
+ return;
160
+ const batch = pending.splice(0, pending.length);
161
+ const items = await (0, concurrency_1.mapWithConcurrency)(batch, context.readConcurrency ?? concurrency_1.DEFAULT_READ_CONCURRENCY, (record) => (0, rows_1.readStoreItem)(context, record, signal));
162
+ batch.forEach((record, index) => {
163
+ live.push({
164
+ namespace: record.namespace,
165
+ key: record.key,
166
+ value: items[index].value,
167
+ });
168
+ });
169
+ }
170
+ /**
171
+ * Enumerate the live (unexpired) items under `prefix` and recompute their
172
+ * embeddings.
173
+ *
174
+ * Accepts: `prefix` — at least one element, since the enumeration is one
175
+ * partition's Query; reconciling is always scoped. `signal` — aborts between
176
+ * pages.
177
+ *
178
+ * Returns: one target per live item, each with the embedding the item's current
179
+ * value produces — `undefined` when it yields no indexable text, which is the
180
+ * evidence that lets {@link pruneOrphans} drop a vector that has gone stale.
181
+ *
182
+ * Throws: whatever the reads, the decodes and the embeddings model throw; a
183
+ * failed embedding rejects the whole reconcile, because a skipped item would
184
+ * leave the live set and {@link selectOrphans} would prune its still-valid
185
+ * vector. `RESULT_TRUNCATED` when `maxScanItems` is reached while rows
186
+ * remain — reconciling from a partial view would prune live vectors.
187
+ *
188
+ * Guarantees: rows are decoded in bounded batches, so a namespace of offloaded
189
+ * items costs neither one round-trip at a time nor every payload in memory at
190
+ * once.
191
+ */
192
+ async function collectReconcileTargets(context, prefix, signal) {
193
+ const now = (0, clock_1.nowSeconds)();
194
+ const live = [];
195
+ const pending = [];
196
+ const batchLimit = context.readConcurrency ?? concurrency_1.DEFAULT_READ_CONCURRENCY;
197
+ const source = (0, paginate_1.paginateQuery)({
198
+ retry: (0, retry_1.retryFor)(context, signal),
199
+ signal,
200
+ client: context.client,
201
+ params: (0, table_schema_1.withoutExpired)((0, rows_1.scopedQuery)(context.tableName, prefix), now),
202
+ maxItems: context.maxScanItems,
203
+ });
204
+ for await (const raw of source) {
205
+ const record = (0, rows_1.parseWholeStoreRow)(raw);
206
+ if (!record) {
207
+ context.logger.warn('reconcileVectorIndex: skipped a row that is not a store item', {
208
+ sortKey: (0, truncate_1.truncateForLog)(raw.SK),
209
+ });
210
+ continue;
211
+ }
212
+ if ((0, table_schema_1.isExpiredRow)(record, now) || !(0, rows_1.namespaceMatchesPrefix)(record.namespace, prefix))
213
+ continue;
214
+ pending.push(record);
215
+ if (pending.length >= batchLimit)
216
+ await drainPending(context, pending, live, signal);
217
+ }
218
+ await drainPending(context, pending, live, signal);
219
+ const embeddings = await (0, semantic_search_1.embedValues)(context, live.map((entry) => entry.value));
220
+ return live.map((entry, i) => ({
221
+ namespace: entry.namespace,
222
+ key: entry.key,
223
+ embedding: embeddings[i],
224
+ }));
225
+ }
226
+ /**
227
+ * Re-push every live embedding to the backend.
228
+ *
229
+ * Accepts: `targets` — a target with no embedding is not pushed; its vector is
230
+ * {@link pruneOrphans}' business, not an upsert of nothing.
231
+ *
232
+ * Returns: how many vectors were upserted.
233
+ *
234
+ * Throws: whatever the backend throws. The upserts are issued one at a time on
235
+ * purpose: this is a bulk repair against a third-party index, and the run has
236
+ * no latency budget worth a thundering herd.
237
+ */
238
+ async function pushEmbeddings(backend, targets) {
239
+ let upserted = 0;
240
+ for (const target of targets) {
241
+ if (!target.embedding)
242
+ continue;
243
+ await backend.upsert(target.namespace, target.key, target.embedding);
244
+ upserted += 1;
245
+ }
246
+ return upserted;
247
+ }
248
+ /**
249
+ * Refs the backend holds that the live set does not account for.
250
+ *
251
+ * Accepts: `backendRefs` — whatever the backend lists under the prefix.
252
+ * `live` — the snapshot; a target with no embedding does not account for a
253
+ * vector, since its item no longer produces one.
254
+ *
255
+ * Returns: the candidates to prune — candidates, not conclusions: the snapshot
256
+ * and the backend listing are not one point in time (see {@link pruneOrphans}).
257
+ *
258
+ * Throws: nothing.
259
+ */
260
+ function selectOrphans(backendRefs, live) {
261
+ const liveKeys = new Set(live
262
+ .filter((target) => target.embedding !== undefined)
263
+ .map((target) => refIdentity(target.namespace, target.key)));
264
+ return backendRefs.filter((ref) => !liveKeys.has(refIdentity(ref.namespace, ref.key)));
265
+ }
266
+ /**
267
+ * True when a candidate's canonical item is confirmed absent right now. The
268
+ * live-set snapshot and this read are not one point in time, so an item
269
+ * written between them looks orphaned even though it is live — and deleting
270
+ * its vector would silently drop a just-written item out of semantic search.
271
+ */
272
+ async function confirmedGone(context, ref) {
273
+ return (0, idempotent_write_1.isRowAbsent)(context, (0, rows_1.itemRowKey)(ref));
274
+ }
275
+ /**
276
+ * Delete backend vectors with no canonical item.
277
+ *
278
+ * Accepts: `live` — the snapshot {@link collectReconcileTargets} took.
279
+ * `backend.listKeys` — optional; a backend that cannot enumerate its own keys
280
+ * cannot be pruned, which is reported rather than silently skipped.
281
+ *
282
+ * Returns: how many vectors were deleted.
283
+ *
284
+ * Throws: whatever the backend and the confirmation read throw.
285
+ *
286
+ * Guarantees: a vector is deleted only on evidence that its item is gone — the
287
+ * snapshot saw the item and it yields no embedding, or a fresh
288
+ * strongly-consistent read finds no row at all. An item written between the
289
+ * snapshot and the listing looks orphaned and is kept, so reconciling never
290
+ * drops a just-written item out of semantic search.
291
+ */
292
+ async function pruneOrphans(context, backend, prefix, live) {
293
+ if (!backend.listKeys) {
294
+ context.logger.info('reconcileVectorIndex prune skipped: backend has no listKeys', {
295
+ prefix: (0, truncate_1.truncateLabelsForLog)(prefix),
296
+ });
297
+ return 0;
298
+ }
299
+ const candidates = selectOrphans(await backend.listKeys(prefix), live);
300
+ // Every item the snapshot actually saw, embedded or not. A candidate in here
301
+ // is prunable on the evidence already gathered — its item exists but yields
302
+ // no embedding (its indexable text became empty), so its vector really is
303
+ // stale. Only a candidate the snapshot never saw at all is ambiguous.
304
+ const observed = new Set(live.map((target) => refIdentity(target.namespace, target.key)));
305
+ let pruned = 0;
306
+ for (const ref of candidates) {
307
+ const seen = observed.has(refIdentity(ref.namespace, ref.key));
308
+ if (!seen && !(await confirmedGone(context, ref))) {
309
+ // The ref is a consumer backend's answer, bounded by nothing this package ran.
310
+ context.logger.info('reconcileVectorIndex: kept a vector whose item reappeared', {
311
+ namespace: (0, truncate_1.truncateLabelsForLog)(ref.namespace),
312
+ key: (0, truncate_1.truncateForLog)(ref.key),
313
+ });
314
+ continue;
315
+ }
316
+ await backend.delete(ref.namespace, ref.key);
317
+ pruned += 1;
318
+ }
319
+ return pruned;
320
+ }
321
+ /**
322
+ * Repair the vector copy against the items under a prefix: re-push every live
323
+ * embedding, then prune entries whose item is confirmed gone.
324
+ *
325
+ * Accepts: `prefix` — parsed. `signal` — cancels the table read.
326
+ *
327
+ * Returns: how many entries were upserted and pruned.
328
+ *
329
+ * Throws: whatever the table read, the embeddings model or the backend throws.
330
+ */
331
+ async function reconcileVectors(context, prefix, signal) {
332
+ const targets = await collectReconcileTargets(context, prefix, signal);
333
+ const upserted = await pushEmbeddings(context.vectorBackend, targets);
334
+ const pruned = await pruneOrphans(context, context.vectorBackend, prefix, targets);
335
+ return { upserted, pruned };
336
+ }
337
+ /**
338
+ * Warn when a backend's own ordering disagrees with its scores. A backend
339
+ * returning a raw distance still hands back nearest-first, so the order looks
340
+ * right while every score means the opposite of what {@link VectorMatch.score}
341
+ * promises — ascending scores are that exact signature. Results are never
342
+ * reordered on this basis: a correctly-scored backend's order is authoritative.
343
+ */
344
+ function warnOnNonDescendingScores(context, matches, namespacePrefix) {
345
+ const descending = matches.every((match, position) => position === 0 || matches[position - 1].score >= match.score);
346
+ if (descending)
347
+ return;
348
+ context.logger.warn('search: vectorBackend returned ascending scores; VectorMatch.score must be a relevance ' +
349
+ '(higher is better), not a distance — results are forwarded in the order the backend gave', { namespacePrefix: (0, truncate_1.truncateLabelsForLog)(namespacePrefix) });
350
+ }
351
+ /**
352
+ * The address a backend match names, parsed, or `undefined` — logged — when it
353
+ * names one this store cannot form. A backend returning a namespace element
354
+ * that holds the reserved separator would otherwise turn a whole search into a
355
+ * `VALIDATION` error over one bad key. The address is checked here rather than
356
+ * read back off the error `getItem` raises: the read raises a `VALIDATION` error
357
+ * of its own for a payload it cannot honour — an offloaded row read with no
358
+ * `s3` configured, a descriptor that is not one, an `s3Key` outside the row's
359
+ * path — and those are reads that did not happen, not items that are not
360
+ * there, so telling them apart by code alone dropped them as well.
361
+ *
362
+ * The line quotes the address the backend gave, bounded: this fires in the
363
+ * branch where `parseStoreAddress` refused it, one line per bad match, and
364
+ * nothing this package ran bounded either the labels or how many of them there
365
+ * are. The `reason` goes through the same cap, though it is the only one of
366
+ * these that cannot exceed it: what this `catch` binds is always
367
+ * `parseStoreAddress`'s own `VALIDATION` error, whose code is a literal of this
368
+ * package's. It is cut anyway so the rule reads the same at every site that
369
+ * names a failure — a name and a message are the two halves of what the
370
+ * failure was, and `message` is bounded where `redactedMessage` relays it —
371
+ * and so that a later refusal thrown from somewhere else does not arrive
372
+ * unbounded because this one site was reasoned about individually.
373
+ */
374
+ function addressOf(context, match) {
375
+ try {
376
+ return (0, parse_1.parseStoreAddress)(match.namespace, match.key);
377
+ }
378
+ catch (error) {
379
+ context.logger.warn('search: skipped an unusable vectorBackend match', {
380
+ namespace: (0, truncate_1.truncateLabelsForLog)(match.namespace),
381
+ key: (0, truncate_1.truncateForLog)(match.key),
382
+ reason: (0, truncate_1.truncateForLog)((0, base_error_1.failureLabel)(error)),
383
+ });
384
+ return undefined;
385
+ }
386
+ }
387
+ /**
388
+ * Read the canonical item a backend match points at, or `null` when the match
389
+ * names an address this store cannot form (see {@link addressOf}).
390
+ *
391
+ * Every failure of the read itself reaches the caller. A throttled or cancelled
392
+ * read says nothing about whether the item is there, so treating it as an
393
+ * absent match handed back a page silently one item short, with only a `warn`
394
+ * the default logger never prints to say so — while the in-DynamoDB path fails
395
+ * the same search outright.
396
+ */
397
+ async function fetchMatch(context, match, signal) {
398
+ const address = addressOf(context, match);
399
+ if (address === undefined)
400
+ return null;
401
+ return (0, get_item_1.getItem)(context, address, signal);
402
+ }
403
+ /** Stable, collision-free identity for a match, so one call reads each item once. */
404
+ function matchIdentity(match) {
405
+ return JSON.stringify([match.namespace, match.key]);
406
+ }
407
+ /**
408
+ * Read the canonical item behind every match this call has not read yet, into
409
+ * `fetched`.
410
+ *
411
+ * Each round asks the backend for a larger `topK`, and the answer *contains*
412
+ * the previous round's matches, so re-reading them cost one DynamoDB read — and
413
+ * one S3 download for an offloaded item — per match per round. Remembering the
414
+ * reads bounds a whole search at one read per distinct match. The same map also
415
+ * covers a backend that returns one key twice in a single round.
416
+ *
417
+ * What a caller trades for it: an item changed between two rounds is answered
418
+ * from the first read. A search is not a transaction and the rounds are
419
+ * milliseconds apart, so the alternative — re-reading to catch a write that may
420
+ * as well have landed a moment later — buys nothing.
421
+ */
422
+ async function fetchUnseen(context, scoped, fetched, signal) {
423
+ const unseen = new Map();
424
+ for (const match of scoped) {
425
+ const identity = matchIdentity(match);
426
+ if (!fetched.has(identity))
427
+ unseen.set(identity, match);
428
+ }
429
+ const pending = [...unseen.values()];
430
+ const items = await (0, concurrency_1.mapWithConcurrency)(pending, context.readConcurrency ?? concurrency_1.DEFAULT_READ_CONCURRENCY, (match) => fetchMatch(context, match, signal));
431
+ pending.forEach((match, index) => fetched.set(matchIdentity(match), items[index]));
432
+ }
433
+ /**
434
+ * Rank a search through a configured vector backend.
435
+ *
436
+ * Accepts: `context` — the store's, with the backend searched and the index
437
+ * whose embeddings model embeds the query. `search.query` — non-empty; the
438
+ * caller checks that before choosing this path. `search.offset`/`search.limit`
439
+ * — the page, whose end (`offset + limit`) must fit within
440
+ * `maxSearchCandidates`, since that many matches have to be fetched to fill it.
441
+ * `search.filter` — applied to the canonical item, not to whatever the backend
442
+ * stored, so a filter is never answered from a stale vector.
443
+ *
444
+ * Returns: the page's items in the backend's order, each carrying the relevance
445
+ * score for its vector. Fewer than `limit` items means the backend has no more
446
+ * matches under the prefix, not that the page was cut short.
447
+ *
448
+ * Throws: `VALIDATION` naming `index.dims` when the query embeds to a
449
+ * different width than the index declares, and naming `maxSearchCandidates`
450
+ * either for a page larger than the cap or when the filter leaves the page short
451
+ * at the cap — the same answer the in-DynamoDB ranker gives, rather than a
452
+ * silently short page. Whatever a canonical read throws — a read that did not
453
+ * happen is not an item that is not there — since a match this store cannot
454
+ * address is dropped before its read rather than caught after it (see
455
+ * {@link addressOf}). Whatever the embeddings model and the backend throw.
456
+ *
457
+ * Guarantees: DynamoDB stays canonical. A match whose item has since been
458
+ * deleted or lies outside the prefix is dropped and the search asks the backend
459
+ * for more, so a stale or over-broad index costs results only in latency. A
460
+ * match whose read *fails* is not dropped: the page a caller receives is never
461
+ * shorter than the matches that exist, which is what the in-DynamoDB path
462
+ * already promises. Items are fetched with the same bounded concurrency as the
463
+ * in-DynamoDB path, and each distinct match is read once for the whole call
464
+ * however many rounds it takes (see {@link fetchUnseen}).
465
+ */
466
+ async function searchViaBackend(context, search, signal) {
467
+ const backend = context.vectorBackend;
468
+ const index = context.index;
469
+ const { offset, limit } = search;
470
+ const queryVector = await index.embeddings.embedQuery(search.query);
471
+ (0, semantic_search_1.assertVectorDims)(index, queryVector, 'query');
472
+ const need = offset + limit;
473
+ if (need > context.maxSearchCandidates) {
474
+ throw (0, errors_1.validationError)(`Requested page (offset ${offset} + limit ${limit} = ${need}) exceeds maxSearchCandidates ` +
475
+ `(${context.maxSearchCandidates}); narrow the page or raise maxSearchCandidates`, 'maxSearchCandidates');
476
+ }
477
+ let topK = Math.min(need, context.maxSearchCandidates);
478
+ let results;
479
+ const fetched = new Map();
480
+ for (;;) {
481
+ const matches = toRelevanceScores(await backend.query(search.namespacePrefix, queryVector, topK), context.vectorScoreDirection);
482
+ warnOnNonDescendingScores(context, matches, search.namespacePrefix);
483
+ const scoped = matches.filter((match) => (0, rows_1.namespaceMatchesPrefix)(match.namespace, search.namespacePrefix));
484
+ await fetchUnseen(context, scoped, fetched, signal);
485
+ results = [];
486
+ for (const match of scoped) {
487
+ const item = fetched.get(matchIdentity(match));
488
+ if (item && (0, filter_1.passesFilter)(item, search.filter))
489
+ results.push({ ...item, score: match.score });
490
+ }
491
+ if (results.length >= need || matches.length < topK)
492
+ break;
493
+ if (topK >= context.maxSearchCandidates) {
494
+ // The backend still holds matches, but the filter left the page short at the cap: the same answer the in-DB ranker gives, not a silently short page.
495
+ throw (0, errors_1.validationError)(`Semantic search collected ${results.length} of ${need} matches within maxSearchCandidates ` +
496
+ `(${context.maxSearchCandidates}); narrow the filter or raise maxSearchCandidates`, 'maxSearchCandidates');
497
+ }
498
+ topK = Math.min(topK * 2, context.maxSearchCandidates);
499
+ }
500
+ return results;
501
+ }
502
+ /**
503
+ * Normalise a backend's matches to the relevance direction upstream
504
+ * `SearchItem.score` documents — "higher scores indicate better matches",
505
+ * typically a cosine similarity between -1 and 1.
506
+ *
507
+ * A distance is converted by **negation** rather than `1 / (1 + d)`: negation
508
+ * is monotone over the whole real line, needs no non-negativity precondition,
509
+ * and is exactly invertible, so the original distance is simply `-score`. A
510
+ * reciprocal would silently imply a different `(0, 1]` scale and is undefined
511
+ * at `d === -1`. Negative scores are already in range for this contract, so
512
+ * nothing is lost by producing them.
513
+ *
514
+ * Results are re-sorted after conversion so a backend that returns its matches
515
+ * in some other order still ranks correctly. Anything that is not `'distance'`
516
+ * is returned untouched — its own order stays authoritative, exactly as before.
517
+ *
518
+ * The test is for `'distance'` rather than against `'relevance'` on purpose:
519
+ * converting is the destructive branch, so only the exact value that asks for
520
+ * it may reach it. Testing the other way round made every unrecognised
521
+ * string — `'Distance'`, a typo, a value read from a config file — reverse the
522
+ * ranking silently, with no error and no warning (the ascending-score warning
523
+ * lives downstream of this conversion, so it could never fire). `setUpStore`
524
+ * rejects such a value outright; this keeps the failure harmless for any
525
+ * caller that reaches the function some other way.
526
+ *
527
+ * Accepts: `matches` — in any order, including empty. `direction` — only the
528
+ * exact string `'distance'` converts; every other value, recognised or not,
529
+ * passes the matches through untouched.
530
+ *
531
+ * Returns: matches whose `score` follows the relevance direction upstream
532
+ * documents, highest first. Converting re-sorts, so a backend that returned its
533
+ * matches in some other order still ranks correctly.
534
+ *
535
+ * Throws: nothing.
536
+ *
537
+ * Guarantees: the conversion is exactly invertible — the original distance is
538
+ * `-score` — so nothing about the backend's answer is lost.
539
+ */
540
+ function toRelevanceScores(matches, direction) {
541
+ if (direction !== 'distance')
542
+ return matches;
543
+ return matches
544
+ .map((match) => ({ ...match, score: -match.score }))
545
+ .sort((left, right) => right.score - left.score);
546
+ }