@farukada/aws-langgraph-dynamodb-ts 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +63 -9
  2. package/dist/checkpointer/actions/delete-thread.d.ts +3 -4
  3. package/dist/checkpointer/actions/delete-thread.d.ts.map +1 -1
  4. package/dist/checkpointer/actions/delete-thread.js +21 -41
  5. package/dist/checkpointer/actions/delete-thread.js.map +1 -1
  6. package/dist/checkpointer/actions/list.d.ts.map +1 -1
  7. package/dist/checkpointer/actions/list.js +31 -4
  8. package/dist/checkpointer/actions/list.js.map +1 -1
  9. package/dist/checkpointer/actions/put-writes.d.ts.map +1 -1
  10. package/dist/checkpointer/actions/put-writes.js +14 -24
  11. package/dist/checkpointer/actions/put-writes.js.map +1 -1
  12. package/dist/checkpointer/actions/put.d.ts.map +1 -1
  13. package/dist/checkpointer/actions/put.js +2 -0
  14. package/dist/checkpointer/actions/put.js.map +1 -1
  15. package/dist/checkpointer/internal/item-reader.d.ts +31 -0
  16. package/dist/checkpointer/internal/item-reader.d.ts.map +1 -1
  17. package/dist/checkpointer/internal/item-reader.js +49 -1
  18. package/dist/checkpointer/internal/item-reader.js.map +1 -1
  19. package/dist/checkpointer/internal/item-writer.d.ts +0 -8
  20. package/dist/checkpointer/internal/item-writer.d.ts.map +1 -1
  21. package/dist/checkpointer/internal/item-writer.js +15 -21
  22. package/dist/checkpointer/internal/item-writer.js.map +1 -1
  23. package/dist/checkpointer/internal/keys.d.ts +19 -3
  24. package/dist/checkpointer/internal/keys.d.ts.map +1 -1
  25. package/dist/checkpointer/internal/keys.js +41 -6
  26. package/dist/checkpointer/internal/keys.js.map +1 -1
  27. package/dist/checkpointer/internal/special-write-cleanup.d.ts.map +1 -1
  28. package/dist/checkpointer/internal/special-write-cleanup.js +6 -12
  29. package/dist/checkpointer/internal/special-write-cleanup.js.map +1 -1
  30. package/dist/checkpointer/internal/validation.d.ts +8 -4
  31. package/dist/checkpointer/internal/validation.d.ts.map +1 -1
  32. package/dist/checkpointer/internal/validation.js +12 -10
  33. package/dist/checkpointer/internal/validation.js.map +1 -1
  34. package/dist/checkpointer/internal/write-guard.d.ts +21 -0
  35. package/dist/checkpointer/internal/write-guard.d.ts.map +1 -0
  36. package/dist/checkpointer/internal/write-guard.js +48 -0
  37. package/dist/checkpointer/internal/write-guard.js.map +1 -0
  38. package/dist/checkpointer/internal/write-index.d.ts +29 -0
  39. package/dist/checkpointer/internal/write-index.d.ts.map +1 -0
  40. package/dist/checkpointer/internal/write-index.js +38 -0
  41. package/dist/checkpointer/internal/write-index.js.map +1 -0
  42. package/dist/checkpointer/types.d.ts +2 -0
  43. package/dist/checkpointer/types.d.ts.map +1 -1
  44. package/dist/history/actions/add-messages.d.ts.map +1 -1
  45. package/dist/history/actions/add-messages.js +24 -4
  46. package/dist/history/actions/add-messages.js.map +1 -1
  47. package/dist/history/actions/clear.d.ts +4 -6
  48. package/dist/history/actions/clear.d.ts.map +1 -1
  49. package/dist/history/actions/clear.js +18 -33
  50. package/dist/history/actions/clear.js.map +1 -1
  51. package/dist/history/actions/get-messages.d.ts +2 -1
  52. package/dist/history/actions/get-messages.d.ts.map +1 -1
  53. package/dist/history/actions/get-messages.js +28 -2
  54. package/dist/history/actions/get-messages.js.map +1 -1
  55. package/dist/history/actions/list-sessions.d.ts +2 -1
  56. package/dist/history/actions/list-sessions.d.ts.map +1 -1
  57. package/dist/history/actions/list-sessions.js +21 -2
  58. package/dist/history/actions/list-sessions.js.map +1 -1
  59. package/dist/history/actions/reconcile-count.d.ts.map +1 -1
  60. package/dist/history/actions/reconcile-count.js +2 -2
  61. package/dist/history/actions/reconcile-count.js.map +1 -1
  62. package/dist/history/internal/append-saga.d.ts.map +1 -1
  63. package/dist/history/internal/append-saga.js +2 -78
  64. package/dist/history/internal/append-saga.js.map +1 -1
  65. package/dist/history/internal/compensation.d.ts +21 -0
  66. package/dist/history/internal/compensation.d.ts.map +1 -0
  67. package/dist/history/internal/compensation.js +84 -0
  68. package/dist/history/internal/compensation.js.map +1 -0
  69. package/dist/history/internal/keys.d.ts +10 -2
  70. package/dist/history/internal/keys.d.ts.map +1 -1
  71. package/dist/history/internal/keys.js +32 -5
  72. package/dist/history/internal/keys.js.map +1 -1
  73. package/dist/history/internal/message-chunker.d.ts.map +1 -1
  74. package/dist/history/internal/message-chunker.js +13 -5
  75. package/dist/history/internal/message-chunker.js.map +1 -1
  76. package/dist/history/internal/session-count.d.ts +21 -0
  77. package/dist/history/internal/session-count.d.ts.map +1 -1
  78. package/dist/history/internal/session-count.js +51 -0
  79. package/dist/history/internal/session-count.js.map +1 -1
  80. package/dist/history/internal/session-title.d.ts +20 -0
  81. package/dist/history/internal/session-title.d.ts.map +1 -0
  82. package/dist/history/internal/session-title.js +44 -0
  83. package/dist/history/internal/session-title.js.map +1 -0
  84. package/dist/history/internal/setup.d.ts +2 -1
  85. package/dist/history/internal/setup.d.ts.map +1 -1
  86. package/dist/history/internal/setup.js +1 -0
  87. package/dist/history/internal/setup.js.map +1 -1
  88. package/dist/history/internal/title-generator.d.ts +8 -2
  89. package/dist/history/internal/title-generator.d.ts.map +1 -1
  90. package/dist/history/internal/title-generator.js +12 -3
  91. package/dist/history/internal/title-generator.js.map +1 -1
  92. package/dist/history/internal/validation.d.ts +9 -0
  93. package/dist/history/internal/validation.d.ts.map +1 -0
  94. package/dist/history/internal/validation.js +16 -0
  95. package/dist/history/internal/validation.js.map +1 -0
  96. package/dist/history/types.d.ts +12 -0
  97. package/dist/history/types.d.ts.map +1 -1
  98. package/dist/index.d.ts +1 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js.map +1 -1
  101. package/dist/shared/codec/s3/offloader.d.ts +7 -1
  102. package/dist/shared/codec/s3/offloader.d.ts.map +1 -1
  103. package/dist/shared/codec/s3/offloader.js +14 -1
  104. package/dist/shared/codec/s3/offloader.js.map +1 -1
  105. package/dist/shared/dynamodb/batch-write.d.ts.map +1 -1
  106. package/dist/shared/dynamodb/batch-write.js +8 -6
  107. package/dist/shared/dynamodb/batch-write.js.map +1 -1
  108. package/dist/shared/dynamodb/drain-unprocessed.d.ts +5 -1
  109. package/dist/shared/dynamodb/drain-unprocessed.d.ts.map +1 -1
  110. package/dist/shared/dynamodb/drain-unprocessed.js +20 -11
  111. package/dist/shared/dynamodb/drain-unprocessed.js.map +1 -1
  112. package/dist/shared/dynamodb/partition-delete.d.ts +33 -0
  113. package/dist/shared/dynamodb/partition-delete.d.ts.map +1 -0
  114. package/dist/shared/dynamodb/partition-delete.js +70 -0
  115. package/dist/shared/dynamodb/partition-delete.js.map +1 -0
  116. package/dist/shared/dynamodb/retry-classifier.d.ts.map +1 -1
  117. package/dist/shared/dynamodb/retry-classifier.js +9 -1
  118. package/dist/shared/dynamodb/retry-classifier.js.map +1 -1
  119. package/dist/shared/errors/errors.d.ts +5 -2
  120. package/dist/shared/errors/errors.d.ts.map +1 -1
  121. package/dist/shared/errors/errors.js +6 -3
  122. package/dist/shared/errors/errors.js.map +1 -1
  123. package/dist/shared/logging/redaction-walk.d.ts +23 -0
  124. package/dist/shared/logging/redaction-walk.d.ts.map +1 -0
  125. package/dist/shared/logging/redaction-walk.js +92 -0
  126. package/dist/shared/logging/redaction-walk.js.map +1 -0
  127. package/dist/shared/logging/redaction.d.ts +22 -10
  128. package/dist/shared/logging/redaction.d.ts.map +1 -1
  129. package/dist/shared/logging/redaction.js +24 -36
  130. package/dist/shared/logging/redaction.js.map +1 -1
  131. package/dist/shared/logging/secret-patterns.d.ts +41 -0
  132. package/dist/shared/logging/secret-patterns.d.ts.map +1 -0
  133. package/dist/shared/logging/secret-patterns.js +74 -0
  134. package/dist/shared/logging/secret-patterns.js.map +1 -0
  135. package/dist/shared/validation/primitives.d.ts +9 -1
  136. package/dist/shared/validation/primitives.d.ts.map +1 -1
  137. package/dist/shared/validation/primitives.js +13 -0
  138. package/dist/shared/validation/primitives.js.map +1 -1
  139. package/dist/store/actions/get.d.ts.map +1 -1
  140. package/dist/store/actions/get.js +15 -1
  141. package/dist/store/actions/get.js.map +1 -1
  142. package/dist/store/actions/list-namespaces.d.ts.map +1 -1
  143. package/dist/store/actions/list-namespaces.js +1 -0
  144. package/dist/store/actions/list-namespaces.js.map +1 -1
  145. package/dist/store/actions/put.d.ts.map +1 -1
  146. package/dist/store/actions/put.js +20 -2
  147. package/dist/store/actions/put.js.map +1 -1
  148. package/dist/store/actions/search.d.ts.map +1 -1
  149. package/dist/store/actions/search.js +4 -35
  150. package/dist/store/actions/search.js.map +1 -1
  151. package/dist/store/internal/backend-search.d.ts +5 -0
  152. package/dist/store/internal/backend-search.d.ts.map +1 -0
  153. package/dist/store/internal/backend-search.js +67 -0
  154. package/dist/store/internal/backend-search.js.map +1 -0
  155. package/dist/store/internal/filter.d.ts.map +1 -1
  156. package/dist/store/internal/filter.js +26 -5
  157. package/dist/store/internal/filter.js.map +1 -1
  158. package/dist/store/internal/index-reconcile.d.ts.map +1 -1
  159. package/dist/store/internal/index-reconcile.js +33 -3
  160. package/dist/store/internal/index-reconcile.js.map +1 -1
  161. package/dist/store/internal/keys.d.ts +1 -1
  162. package/dist/store/internal/keys.d.ts.map +1 -1
  163. package/dist/store/internal/keys.js +8 -2
  164. package/dist/store/internal/keys.js.map +1 -1
  165. package/dist/store/internal/persist.d.ts.map +1 -1
  166. package/dist/store/internal/persist.js +1 -5
  167. package/dist/store/internal/persist.js.map +1 -1
  168. package/dist/store/internal/search-filter.d.ts +4 -0
  169. package/dist/store/internal/search-filter.d.ts.map +1 -0
  170. package/dist/store/internal/search-filter.js +11 -0
  171. package/dist/store/internal/search-filter.js.map +1 -0
  172. package/dist/store/internal/setup.d.ts +11 -1
  173. package/dist/store/internal/setup.d.ts.map +1 -1
  174. package/dist/store/internal/setup.js +17 -1
  175. package/dist/store/internal/setup.js.map +1 -1
  176. package/dist/store/internal/validation.d.ts +8 -2
  177. package/dist/store/internal/validation.d.ts.map +1 -1
  178. package/dist/store/internal/validation.js +15 -6
  179. package/dist/store/internal/validation.js.map +1 -1
  180. package/dist/store/internal/write-verify.d.ts +12 -0
  181. package/dist/store/internal/write-verify.d.ts.map +1 -1
  182. package/dist/store/internal/write-verify.js +27 -0
  183. package/dist/store/internal/write-verify.js.map +1 -1
  184. package/dist/store/vector-backend.d.ts +17 -0
  185. package/dist/store/vector-backend.d.ts.map +1 -1
  186. package/package.json +1 -1
@@ -11,11 +11,19 @@ const codec_1 = require("../../shared/codec/codec");
11
11
  * overshoot the transaction byte limit.
12
12
  */
13
13
  const ITEM_OVERHEAD_BYTES = 256;
14
+ /**
15
+ * Byte length of a string as DynamoDB stores it. `String.length` counts UTF-16
16
+ * code units, which understates every non-ASCII character — the wrong
17
+ * direction for an estimate documented to sit at or above the real size.
18
+ */
19
+ function utf8Bytes(value) {
20
+ return Buffer.byteLength(value, 'utf8');
21
+ }
14
22
  function descriptorBytes(descriptor) {
15
23
  const body = descriptor.location === codec_1.PayloadLocation.INLINE
16
24
  ? descriptor.bytes.length
17
- : descriptor.s3Key.length;
18
- return body + descriptor.serdeType.length;
25
+ : utf8Bytes(descriptor.s3Key);
26
+ return body + utf8Bytes(descriptor.serdeType);
19
27
  }
20
28
  /**
21
29
  * Conservatively estimate a message item's stored size, so chunks can stay under
@@ -23,9 +31,9 @@ function descriptorBytes(descriptor) {
23
31
  * on the safe side of the real marshalled size.
24
32
  */
25
33
  function estimateItemBytes(item) {
26
- return (item.PK.length +
27
- item.SK.length +
28
- item.sessionId.length +
34
+ return (utf8Bytes(item.PK) +
35
+ utf8Bytes(item.SK) +
36
+ utf8Bytes(item.sessionId) +
29
37
  descriptorBytes(item.message) +
30
38
  ITEM_OVERHEAD_BYTES);
31
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"message-chunker.js","sourceRoot":"","sources":["../../../src/history/internal/message-chunker.ts"],"names":[],"mappings":";;;;AAAA,oDAAmF;AAGnF;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,SAAS,eAAe,CAAC,UAA6B;IACpD,MAAM,IAAI,GACR,UAAU,CAAC,QAAQ,KAAK,uBAAe,CAAC,MAAM;QAC5C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM;QACzB,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;IAC9B,OAAO,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,2BAAkC,IAAqB;IACrD,OAAO,CACL,IAAI,CAAC,EAAE,CAAC,MAAM;QACd,IAAI,CAAC,EAAE,CAAC,MAAM;QACd,IAAI,CAAC,SAAS,CAAC,MAAM;QACrB,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7B,mBAAmB,CACpB,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAClB,KAAa,EACb,KAAa,EACb,IAAY,EACZ,GAAW,EACX,QAAgB;IAEhB,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,qBACE,KAAwB,EACxB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,MAAM,GAAwB,EAAE,CAAC;IACvC,IAAI,OAAO,GAAsB,EAAE,CAAC;IACpC,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;YACxE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrB,OAAO,GAAG,EAAE,CAAC;YACb,YAAY,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,YAAY,IAAI,IAAI,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"message-chunker.js","sourceRoot":"","sources":["../../../src/history/internal/message-chunker.ts"],"names":[],"mappings":";;;;AAAA,oDAAmF;AAGnF;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC;;;;GAIG;AACH,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,eAAe,CAAC,UAA6B;IACpD,MAAM,IAAI,GACR,UAAU,CAAC,QAAQ,KAAK,uBAAe,CAAC,MAAM;QAC5C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM;QACzB,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,2BAAkC,IAAqB;IACrD,OAAO,CACL,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;QACzB,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7B,mBAAmB,CACpB,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAClB,KAAa,EACb,KAAa,EACb,IAAY,EACZ,GAAW,EACX,QAAgB;IAEhB,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,qBACE,KAAwB,EACxB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,MAAM,GAAwB,EAAE,CAAC;IACvC,IAAI,OAAO,GAAsB,EAAE,CAAC;IACpC,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;YACxE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrB,OAAO,GAAG,EAAE,CAAC;YACb,YAAY,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,YAAY,IAAI,IAAI,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -17,4 +17,25 @@ import type { HistoryContext } from './setup';
17
17
  * "TTL expiry" section.
18
18
  */
19
19
  export declare function revertSessionCount(context: HistoryContext, sessionId: string, delta: number): Promise<void>;
20
+ /**
21
+ * Undo a rolled-back append's effect on the session row.
22
+ *
23
+ * When this call is the one that created the row — `createdAt` still equals
24
+ * this call's timestamp, and the only messages counted on it are the ones
25
+ * being reverted — the whole row is deleted. Without that, a failed first
26
+ * append left a "ghost session": `title`, `createdAt` and `sessionId` are all
27
+ * written via `if_not_exists`, so they were never reverted and never set
28
+ * again, leaving `listSessions()` reporting a session with `messageCount: 0`
29
+ * whose title still held up to 80 characters of a message the caller was told
30
+ * had not persisted, with no API to clear it.
31
+ *
32
+ * Both conditions are load-bearing. `createdAt = :now` establishes that this
33
+ * call created the row; `messageCount = :total` establishes that nothing else
34
+ * has added to it since. A concurrent append to the same brand-new session
35
+ * fails the count check, because deleting the row would destroy that caller's
36
+ * committed messages — so it falls through to the plain decrement, and then
37
+ * strips just the title this call contributed, which is the only part of the
38
+ * row still carrying rolled-back message content.
39
+ */
40
+ export declare function revertSessionCreation(context: HistoryContext, sessionId: string, total: number, createdAt: string, title?: string): Promise<void>;
20
41
  //# sourceMappingURL=session-count.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-count.d.ts","sourceRoot":"","sources":["../../../src/history/internal/session-count.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAe9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAiBf"}
1
+ {"version":3,"file":"session-count.d.ts","sourceRoot":"","sources":["../../../src/history/internal/session-count.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAe9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAwBf"}
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.revertSessionCount = revertSessionCount;
4
+ exports.revertSessionCreation = revertSessionCreation;
4
5
  const node_crypto_1 = require("node:crypto");
5
6
  const cancellation_1 = require("../../shared/dynamodb/cancellation");
6
7
  const retry_1 = require("../../shared/dynamodb/retry");
7
8
  const keys_1 = require("./keys");
9
+ const session_title_1 = require("./session-title");
8
10
  /**
9
11
  * True when a TransactWriteItems cancellation was caused by a
10
12
  * ConditionalCheckFailed reason. Named distinctly from
@@ -55,4 +57,53 @@ async function revertSessionCount(context, sessionId, delta) {
55
57
  throw error;
56
58
  }
57
59
  }
60
+ /**
61
+ * Undo a rolled-back append's effect on the session row.
62
+ *
63
+ * When this call is the one that created the row — `createdAt` still equals
64
+ * this call's timestamp, and the only messages counted on it are the ones
65
+ * being reverted — the whole row is deleted. Without that, a failed first
66
+ * append left a "ghost session": `title`, `createdAt` and `sessionId` are all
67
+ * written via `if_not_exists`, so they were never reverted and never set
68
+ * again, leaving `listSessions()` reporting a session with `messageCount: 0`
69
+ * whose title still held up to 80 characters of a message the caller was told
70
+ * had not persisted, with no API to clear it.
71
+ *
72
+ * Both conditions are load-bearing. `createdAt = :now` establishes that this
73
+ * call created the row; `messageCount = :total` establishes that nothing else
74
+ * has added to it since. A concurrent append to the same brand-new session
75
+ * fails the count check, because deleting the row would destroy that caller's
76
+ * committed messages — so it falls through to the plain decrement, and then
77
+ * strips just the title this call contributed, which is the only part of the
78
+ * row still carrying rolled-back message content.
79
+ */
80
+ async function revertSessionCreation(context, sessionId, total, createdAt, title) {
81
+ if (total === 0)
82
+ return;
83
+ const input = {
84
+ TransactItems: [
85
+ {
86
+ Delete: {
87
+ TableName: context.tableName,
88
+ Key: { PK: (0, keys_1.sessionPartition)(sessionId), SK: keys_1.SESSION_SORT_KEY },
89
+ ConditionExpression: '#count = :total AND #c = :now',
90
+ ExpressionAttributeNames: { '#count': 'messageCount', '#c': 'createdAt' },
91
+ ExpressionAttributeValues: { ':total': total, ':now': createdAt },
92
+ },
93
+ },
94
+ ],
95
+ ClientRequestToken: (0, node_crypto_1.randomUUID)(),
96
+ };
97
+ try {
98
+ await (0, retry_1.withDynamoDBRetry)(() => context.client.transactWrite(input));
99
+ return;
100
+ }
101
+ catch (error) {
102
+ if (!isCancelledByCondition(error))
103
+ throw error;
104
+ }
105
+ await revertSessionCount(context, sessionId, total);
106
+ if (title !== undefined)
107
+ await (0, session_title_1.removeRolledBackTitle)(context, sessionId, createdAt, title);
108
+ }
58
109
  //# sourceMappingURL=session-count.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-count.js","sourceRoot":"","sources":["../../../src/history/internal/session-count.ts"],"names":[],"mappings":";;;AAAA,6CAAyC;AAEzC,qEAA4E;AAC5E,uDAAgE;AAChE,iCAA4D;AAG5D;;;;;;;GAOG;AACH,SAAS,sBAAsB,CAAC,KAAY;IAC1C,MAAM,OAAO,GAAG,IAAA,qCAAsB,EAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,wBAAwB,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,6BACV,OAAuB,EACvB,SAAiB,EACjB,KAAa;IAEb,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO;IACxB,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,GAAG,EAAE,EAAE,EAAE,EAAE,IAAA,uBAAgB,EAAC,SAAS,CAAC,EAAE,EAAE,EAAE,uBAAgB,EAAE;QAC9D,gBAAgB,EAAE,iBAAiB;QACnC,mBAAmB,EAAE,sBAAsB;QAC3C,wBAAwB,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE;QACtD,yBAAyB,EAAE,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE;KAC9C,CAAC;IACF,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,IAAA,wBAAU,GAAE,EAAE,CAAC;IACxF,IAAI,CAAC;QACH,MAAM,IAAA,yBAAiB,EAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,sBAAsB,CAAC,KAAc,CAAC;YAAE,OAAO;QACnD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"session-count.js","sourceRoot":"","sources":["../../../src/history/internal/session-count.ts"],"names":[],"mappings":";;;;AAAA,6CAAyC;AAEzC,qEAA4E;AAC5E,uDAAgE;AAChE,iCAA4D;AAC5D,mDAAwD;AAGxD;;;;;;;GAOG;AACH,SAAS,sBAAsB,CAAC,KAAY;IAC1C,MAAM,OAAO,GAAG,IAAA,qCAAsB,EAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,wBAAwB,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,6BACV,OAAuB,EACvB,SAAiB,EACjB,KAAa;IAEb,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO;IACxB,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,GAAG,EAAE,EAAE,EAAE,EAAE,IAAA,uBAAgB,EAAC,SAAS,CAAC,EAAE,EAAE,EAAE,uBAAgB,EAAE;QAC9D,gBAAgB,EAAE,iBAAiB;QACnC,mBAAmB,EAAE,sBAAsB;QAC3C,wBAAwB,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE;QACtD,yBAAyB,EAAE,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE;KAC9C,CAAC;IACF,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,IAAA,wBAAU,GAAE,EAAE,CAAC;IACxF,IAAI,CAAC;QACH,MAAM,IAAA,yBAAiB,EAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,sBAAsB,CAAC,KAAc,CAAC;YAAE,OAAO;QACnD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACI,KAAK,gCACV,OAAuB,EACvB,SAAiB,EACjB,KAAa,EACb,SAAiB,EACjB,KAAc;IAEd,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO;IACxB,MAAM,KAAK,GAAG;QACZ,aAAa,EAAE;YACb;gBACE,MAAM,EAAE;oBACN,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,GAAG,EAAE,EAAE,EAAE,EAAE,IAAA,uBAAgB,EAAC,SAAS,CAAC,EAAE,EAAE,EAAE,uBAAgB,EAAE;oBAC9D,mBAAmB,EAAE,+BAA+B;oBACpD,wBAAwB,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE;oBACzE,yBAAyB,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE;iBAClE;aACF;SACF;QACD,kBAAkB,EAAE,IAAA,wBAAU,GAAE;KACjC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,IAAA,yBAAiB,EAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,sBAAsB,CAAC,KAAc,CAAC;YAAE,MAAM,KAAK,CAAC;IAC3D,CAAC;IACD,MAAM,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACpD,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAA,qCAAqB,EAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAC7F,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { HistoryContext } from './setup';
2
+ /**
3
+ * Strip a title this call contributed to a session row it created, when the
4
+ * row itself could not be deleted because a concurrent append has since added
5
+ * messages to it.
6
+ *
7
+ * Without this, that narrow window reopens exactly the leak C4 closes: the
8
+ * title is derived from the first human message of an append the caller was
9
+ * told had failed, and `if_not_exists` means nothing ever overwrites it — so
10
+ * a row that now belongs to a different caller keeps up to 80 characters of
11
+ * rolled-back message content.
12
+ *
13
+ * Both guards are load-bearing. `createdAt = :now` establishes that this call
14
+ * created the row, and `title = :title` that the title on it is still the one
15
+ * this call wrote — so a pre-existing title, or one a concurrent caller won
16
+ * the `if_not_exists` race for, is never removed. A condition rejection means
17
+ * exactly that and is not an error; anything else is.
18
+ */
19
+ export declare function removeRolledBackTitle(context: HistoryContext, sessionId: string, createdAt: string, title: string): Promise<void>;
20
+ //# sourceMappingURL=session-title.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-title.d.ts","sourceRoot":"","sources":["../../../src/history/internal/session-title.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAO9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeRolledBackTitle = removeRolledBackTitle;
4
+ const retry_1 = require("../../shared/dynamodb/retry");
5
+ const keys_1 = require("./keys");
6
+ /** True when a plain UpdateItem was turned away by its ConditionExpression. */
7
+ function isConditionRejected(error) {
8
+ return error.name === 'ConditionalCheckFailedException';
9
+ }
10
+ /**
11
+ * Strip a title this call contributed to a session row it created, when the
12
+ * row itself could not be deleted because a concurrent append has since added
13
+ * messages to it.
14
+ *
15
+ * Without this, that narrow window reopens exactly the leak C4 closes: the
16
+ * title is derived from the first human message of an append the caller was
17
+ * told had failed, and `if_not_exists` means nothing ever overwrites it — so
18
+ * a row that now belongs to a different caller keeps up to 80 characters of
19
+ * rolled-back message content.
20
+ *
21
+ * Both guards are load-bearing. `createdAt = :now` establishes that this call
22
+ * created the row, and `title = :title` that the title on it is still the one
23
+ * this call wrote — so a pre-existing title, or one a concurrent caller won
24
+ * the `if_not_exists` race for, is never removed. A condition rejection means
25
+ * exactly that and is not an error; anything else is.
26
+ */
27
+ async function removeRolledBackTitle(context, sessionId, createdAt, title) {
28
+ try {
29
+ await (0, retry_1.withDynamoDBRetry)(() => context.client.update({
30
+ TableName: context.tableName,
31
+ Key: { PK: (0, keys_1.sessionPartition)(sessionId), SK: keys_1.SESSION_SORT_KEY },
32
+ UpdateExpression: 'REMOVE #title',
33
+ ConditionExpression: '#c = :now AND #title = :title',
34
+ ExpressionAttributeNames: { '#title': 'title', '#c': 'createdAt' },
35
+ ExpressionAttributeValues: { ':now': createdAt, ':title': title },
36
+ }));
37
+ }
38
+ catch (error) {
39
+ if (isConditionRejected(error))
40
+ return;
41
+ throw error;
42
+ }
43
+ }
44
+ //# sourceMappingURL=session-title.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-title.js","sourceRoot":"","sources":["../../../src/history/internal/session-title.ts"],"names":[],"mappings":";;;AAAA,uDAAgE;AAChE,iCAA4D;AAG5D,+EAA+E;AAC/E,SAAS,mBAAmB,CAAC,KAAY;IACvC,OAAO,KAAK,CAAC,IAAI,KAAK,iCAAiC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,gCACV,OAAuB,EACvB,SAAiB,EACjB,SAAiB,EACjB,KAAa;IAEb,IAAI,CAAC;QACH,MAAM,IAAA,yBAAiB,EAAC,GAAG,EAAE,CAC3B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,GAAG,EAAE,EAAE,EAAE,EAAE,IAAA,uBAAgB,EAAC,SAAS,CAAC,EAAE,EAAE,EAAE,uBAAgB,EAAE;YAC9D,gBAAgB,EAAE,eAAe;YACjC,mBAAmB,EAAE,+BAA+B;YACpD,wBAAwB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;YAClE,yBAAyB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE;SAClE,CAAC,CACH,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,mBAAmB,CAAC,KAAc,CAAC;YAAE,OAAO;QAChD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -5,7 +5,7 @@ import type { CompressionConfig } from '../../shared/codec/compression';
5
5
  import { S3Offloader } from '../../shared/codec/s3/offloader';
6
6
  import { type Logger } from '../../shared/logging/logger';
7
7
  import type { TtlOption } from '../../shared/validation/ttl';
8
- import type { DynamoDBChatMessageHistoryOptions } from '../types';
8
+ import type { CorruptMessagePolicy, DynamoDBChatMessageHistoryOptions } from '../types';
9
9
  /** Resolved collaborators shared by every chat-history action. */
10
10
  export interface HistoryContext {
11
11
  client: DynamoDBDocument;
@@ -16,6 +16,7 @@ export interface HistoryContext {
16
16
  ttl?: TtlOption;
17
17
  logger: Logger;
18
18
  ulid: () => string;
19
+ onCorruptMessage: CorruptMessagePolicy;
19
20
  }
20
21
  /** Result of wiring up a chat-history adapter from its options. */
21
22
  export interface HistorySetup {
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/history/internal/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAG9D,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,6BAA6B,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,UAAU,CAAC;AAElE,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,OAAO,EAAE,iCAAiC,GAAG,YAAY,CAsBrF"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/history/internal/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAG9D,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,6BAA6B,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iCAAiC,EAAE,MAAM,UAAU,CAAC;AAExF,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,MAAM,CAAC;IACnB,gBAAgB,EAAE,oBAAoB,CAAC;CACxC;AAED,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,OAAO,EAAE,iCAAiC,GAAG,YAAY,CAuBrF"}
@@ -26,6 +26,7 @@ function setUpHistory(options) {
26
26
  ttl: options.ttl,
27
27
  logger: (0, logger_1.resolveLogger)(options.logger),
28
28
  ulid: (0, ulid_1.createUlidFactory)(),
29
+ onCorruptMessage: options.onCorruptMessage ?? 'skip',
29
30
  },
30
31
  ddbClient: resolved.ddbClient,
31
32
  ownsClient: resolved.ownsClient,
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/history/internal/setup.ts"],"names":[],"mappings":";;;AAKA,8DAA2D;AAC3D,yDAAuE;AACvE,+DAA8D;AAC9D,sDAA+D;AAC/D,yDAAqE;AACrE,wDAAyE;AACzE,4CAAsD;AAuBtD,gFAAgF;AAChF,sBAA6B,OAA0C;IACrE,MAAM,QAAQ,GAAG,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAChD,OAAO;QACL,OAAO,EAAE;YACP,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,uBAAU;YAClC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,OAAO,CAAC,EAAE;gBACnB,CAAC,CAAC,IAAI,uBAAW,CAAC;oBACd,GAAG,OAAO,CAAC,EAAE;oBACb,SAAS,EACP,OAAO,CAAC,EAAE,CAAC,SAAS,IAAI,IAAA,gCAAuB,EAAC,iCAAqB,EAAE,SAAS,CAAC;iBACpF,CAAC;gBACJ,CAAC,CAAC,SAAS;YACb,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,IAAA,sBAAa,EAAC,OAAO,CAAC,MAAM,CAAC;YACrC,IAAI,EAAE,IAAA,wBAAiB,GAAE;SAC1B;QACD,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/history/internal/setup.ts"],"names":[],"mappings":";;;AAKA,8DAA2D;AAC3D,yDAAuE;AACvE,+DAA8D;AAC9D,sDAA+D;AAC/D,yDAAqE;AACrE,wDAAyE;AACzE,4CAAsD;AAwBtD,gFAAgF;AAChF,sBAA6B,OAA0C;IACrE,MAAM,QAAQ,GAAG,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAChD,OAAO;QACL,OAAO,EAAE;YACP,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,uBAAU;YAClC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,OAAO,CAAC,EAAE;gBACnB,CAAC,CAAC,IAAI,uBAAW,CAAC;oBACd,GAAG,OAAO,CAAC,EAAE;oBACb,SAAS,EACP,OAAO,CAAC,EAAE,CAAC,SAAS,IAAI,IAAA,gCAAuB,EAAC,iCAAqB,EAAE,SAAS,CAAC;iBACpF,CAAC;gBACJ,CAAC,CAAC,SAAS;YACb,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,IAAA,sBAAa,EAAC,OAAO,CAAC,MAAM,CAAC;YACrC,IAAI,EAAE,IAAA,wBAAiB,GAAE;YACzB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,MAAM;SACrD;QACD,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAC;AACJ,CAAC"}
@@ -1,7 +1,13 @@
1
1
  import type { StoredMessage } from '@langchain/core/messages';
2
2
  /**
3
- * Derive a session title from the first human message's text content, truncated
4
- * to {@link MAX_TITLE_LENGTH}. Returns undefined when there is no usable text.
3
+ * Derive a session title from the first human message's text content, at most
4
+ * {@link MAX_TITLE_LENGTH} characters including the ellipsis. Returns undefined
5
+ * when there is no usable text.
6
+ *
7
+ * Truncation counts *code points*, not UTF-16 code units: slicing by index
8
+ * could cut a surrogate pair in half, leaving a lone surrogate that no longer
9
+ * round-trips through UTF-8. The ellipsis is also counted against the maximum
10
+ * rather than appended past it.
5
11
  */
6
12
  export declare function deriveTitle(messages: StoredMessage[]): string | undefined;
7
13
  //# sourceMappingURL=title-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"title-generator.d.ts","sourceRoot":"","sources":["../../../src/history/internal/title-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,GAAG,SAAS,CAKzE"}
1
+ {"version":3,"file":"title-generator.d.ts","sourceRoot":"","sources":["../../../src/history/internal/title-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,GAAG,SAAS,CAOzE"}
@@ -3,14 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deriveTitle = deriveTitle;
4
4
  const MAX_TITLE_LENGTH = 80;
5
5
  /**
6
- * Derive a session title from the first human message's text content, truncated
7
- * to {@link MAX_TITLE_LENGTH}. Returns undefined when there is no usable text.
6
+ * Derive a session title from the first human message's text content, at most
7
+ * {@link MAX_TITLE_LENGTH} characters including the ellipsis. Returns undefined
8
+ * when there is no usable text.
9
+ *
10
+ * Truncation counts *code points*, not UTF-16 code units: slicing by index
11
+ * could cut a surrogate pair in half, leaving a lone surrogate that no longer
12
+ * round-trips through UTF-8. The ellipsis is also counted against the maximum
13
+ * rather than appended past it.
8
14
  */
9
15
  function deriveTitle(messages) {
10
16
  const firstHuman = messages.find((message) => message.type === 'human');
11
17
  const content = firstHuman?.data.content;
12
18
  if (typeof content !== 'string' || content.length === 0)
13
19
  return undefined;
14
- return content.length > MAX_TITLE_LENGTH ? `${content.slice(0, MAX_TITLE_LENGTH)}…` : content;
20
+ const codePoints = [...content];
21
+ if (codePoints.length <= MAX_TITLE_LENGTH)
22
+ return content;
23
+ return `${codePoints.slice(0, MAX_TITLE_LENGTH - 1).join('')}…`;
15
24
  }
16
25
  //# sourceMappingURL=title-generator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"title-generator.js","sourceRoot":"","sources":["../../../src/history/internal/title-generator.ts"],"names":[],"mappings":";;;AAEA,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B;;;GAGG;AACH,qBAA4B,QAAyB;IACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC;IACzC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1E,OAAO,OAAO,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AAChG,CAAC"}
1
+ {"version":3,"file":"title-generator.js","sourceRoot":"","sources":["../../../src/history/internal/title-generator.ts"],"names":[],"mappings":";;;AAEA,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B;;;;;;;;;GASG;AACH,qBAA4B,QAAyB;IACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC;IACzC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1E,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;IAChC,IAAI,UAAU,CAAC,MAAM,IAAI,gBAAgB;QAAE,OAAO,OAAO,CAAC;IAC1D,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AAClE,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Validate a session id is a non-empty, separator- and control-char-free
3
+ * string. Applied on every entry point, not just the write path: a bad value
4
+ * used to reach DynamoDB and surface as a raw AWS SDK exception on reads,
5
+ * while the identical value threw this library's typed `ValidationError` on a
6
+ * write.
7
+ */
8
+ export declare function validateSessionId(sessionId: string): void;
9
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/history/internal/validation.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEzD"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateSessionId = validateSessionId;
4
+ const primitives_1 = require("../../shared/validation/primitives");
5
+ const keys_1 = require("./keys");
6
+ /**
7
+ * Validate a session id is a non-empty, separator- and control-char-free
8
+ * string. Applied on every entry point, not just the write path: a bad value
9
+ * used to reach DynamoDB and surface as a raw AWS SDK exception on reads,
10
+ * while the identical value threw this library's typed `ValidationError` on a
11
+ * write.
12
+ */
13
+ function validateSessionId(sessionId) {
14
+ (0, primitives_1.validateIdentifier)(sessionId, keys_1.SORT_KEY_SEPARATOR, 'sessionId');
15
+ }
16
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/history/internal/validation.ts"],"names":[],"mappings":";;;AAAA,mEAAwE;AACxE,iCAA4C;AAE5C;;;;;;GAMG;AACH,2BAAkC,SAAiB;IACjD,IAAA,+BAAkB,EAAC,SAAS,EAAE,yBAAkB,EAAE,WAAW,CAAC,CAAC;AACjE,CAAC"}
@@ -5,7 +5,19 @@ import type { BaseAdapterOptions, CodecOptions } from '../shared/options';
5
5
  export type DynamoDBChatMessageHistoryOptions = BaseAdapterOptions & CodecOptions & {
6
6
  /** Optional serializer override (defaults to the JSON serializer). */
7
7
  serde?: SerializerProtocol;
8
+ /**
9
+ * What `getMessages` does when a stored message cannot be decoded — a
10
+ * decompression-guard trip, an unsupported `serdeType` after a config
11
+ * change, or genuinely corrupted bytes. `'skip'` (the default) drops the
12
+ * item, logs it at `error` with its sort key so an operator can locate
13
+ * it, and returns the rest; `'throw'` fails the whole read, which is
14
+ * all-or-nothing but leaves the session unreadable until the bad row is
15
+ * removed out of band.
16
+ */
17
+ onCorruptMessage?: CorruptMessagePolicy;
8
18
  };
19
+ /** How `getMessages` handles an item it cannot decode. */
20
+ export type CorruptMessagePolicy = 'skip' | 'throw';
9
21
  /** Summary of a stored chat session. */
10
22
  export interface SessionMetadata {
11
23
  sessionId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1E,sDAAsD;AACtD,MAAM,MAAM,iCAAiC,GAAG,kBAAkB,GAChE,YAAY,GAAG;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B,CAAC;AAEJ,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1E,sDAAsD;AACtD,MAAM,MAAM,iCAAiC,GAAG,kBAAkB,GAChE,YAAY,GAAG;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;CACzC,CAAC;AAEJ,0DAA0D;AAC1D,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export type { VectorReconcileResult } from './store/actions/reconcile-vector-ind
6
6
  export type { VectorBackend, VectorMatch, VectorRef } from './store/vector-backend';
7
7
  export { DynamoDBChatMessageHistory } from './history/chat-message-history';
8
8
  export { DynamoDBSessionChatMessageHistory } from './history/session-adapter';
9
- export type { DynamoDBChatMessageHistoryOptions, SessionMetadata } from './history/types';
9
+ export type { CorruptMessagePolicy, DynamoDBChatMessageHistoryOptions, SessionMetadata, } from './history/types';
10
10
  export { DynamoDBFactory } from './factory/factory';
11
11
  export type { CreateAllOptions, CreatedAdapters, FactoryBaseOptions } from './factory/factory';
12
12
  export { DynamoDbLangGraphError } from './shared/errors/base-error';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AACpF,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,2BAA2B,CAAC;AAC9E,YAAY,EAAE,iCAAiC,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE/F,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EACL,UAAU,EACV,4BAA4B,EAC5B,yBAAyB,EACzB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEzE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AACpF,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,2BAA2B,CAAC;AAC9E,YAAY,EACV,oBAAoB,EACpB,iCAAiC,EACjC,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE/F,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EACL,UAAU,EACV,4BAA4B,EAC5B,yBAAyB,EACzB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEzE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8CAAqD;AAA5C,sGAAA,aAAa,OAAA;AAEtB,uCAA8C;AAArC,sGAAA,aAAa,OAAA;AAItB,uEAA4E;AAAnE,kIAAA,0BAA0B,OAAA;AACnC,6DAA8E;AAArE,oIAAA,iCAAiC,OAAA;AAE1C,6CAAoD;AAA3C,0GAAA,eAAe,OAAA;AAGxB,yDAAoE;AAA3D,oHAAA,sBAAsB,OAAA;AAE/B,yDAAuD;AAA9C,uGAAA,SAAS,OAAA;AAClB,iDASgC;AAR9B,oGAAA,UAAU,OAAA;AACV,sHAAA,4BAA4B,OAAA;AAC5B,mHAAA,yBAAyB,OAAA;AACzB,iHAAA,uBAAuB,OAAA;AACvB,uGAAA,aAAa,OAAA;AACb,8GAAA,oBAAoB,OAAA;AACpB,6GAAA,mBAAmB,OAAA;AACnB,yGAAA,eAAe,OAAA;AAIjB,wDAAyE;AAAhE,yGAAA,YAAY,OAAA;AAAE,0GAAA,aAAa,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8CAAqD;AAA5C,sGAAA,aAAa,OAAA;AAEtB,uCAA8C;AAArC,sGAAA,aAAa,OAAA;AAItB,uEAA4E;AAAnE,kIAAA,0BAA0B,OAAA;AACnC,6DAA8E;AAArE,oIAAA,iCAAiC,OAAA;AAM1C,6CAAoD;AAA3C,0GAAA,eAAe,OAAA;AAGxB,yDAAoE;AAA3D,oHAAA,sBAAsB,OAAA;AAE/B,yDAAuD;AAA9C,uGAAA,SAAS,OAAA;AAClB,iDASgC;AAR9B,oGAAA,UAAU,OAAA;AACV,sHAAA,4BAA4B,OAAA;AAC5B,mHAAA,yBAAyB,OAAA;AACzB,iHAAA,uBAAuB,OAAA;AACvB,uGAAA,aAAa,OAAA;AACb,8GAAA,oBAAoB,OAAA;AACpB,6GAAA,mBAAmB,OAAA;AACnB,yGAAA,eAAe,OAAA;AAIjB,wDAAyE;AAAhE,yGAAA,YAAY,OAAA;AAAE,0GAAA,aAAa,OAAA"}
@@ -6,6 +6,7 @@ import { S3OffloadConfig } from './config';
6
6
  export declare class S3Offloader {
7
7
  private clientPromise;
8
8
  private resolvedClient;
9
+ private destroyed;
9
10
  private readonly bucketName;
10
11
  private readonly keyPrefix;
11
12
  private readonly thresholdBytes;
@@ -28,7 +29,12 @@ export declare class S3Offloader {
28
29
  deleteBatch(keys: string[]): Promise<string[]>;
29
30
  /** Ensure a `${ttlDays}`-day expiration lifecycle rule exists for the prefix. */
30
31
  ensureLifecycleRule(ttlDays: number): Promise<void>;
31
- /** Release the underlying S3 client, if one was created. */
32
+ /**
33
+ * Release the underlying S3 client. Safe at any point in the client's
34
+ * lifecycle: called before construction starts it does nothing, called
35
+ * mid-construction it marks the offloader destroyed so the client is
36
+ * released the moment it resolves, and called after it releases it directly.
37
+ */
32
38
  destroy(): void;
33
39
  }
34
40
  //# sourceMappingURL=offloader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"offloader.d.ts","sourceRoot":"","sources":["../../../../src/shared/codec/s3/offloader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,eAAe,EAAE,MAAM,UAAU,CAAC;AAKvD;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,YAAY,MAAM,EAAE,eAAe,EAOlC;IAED,OAAO,CAAC,SAAS;IAqBjB,8DAA8D;IAC9D,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAEvC;IAED,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEzC;IAED,iCAAiC;IACjC,YAAY,IAAI,MAAM,CAErB;IAED,oDAAoD;IAC9C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAS3D;IAED,6CAA6C;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAE/C;IAED,+DAA+D;IACzD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnD;IAED,iFAAiF;IAC3E,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExD;IAED,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAEd;CACF"}
1
+ {"version":3,"file":"offloader.d.ts","sourceRoot":"","sources":["../../../../src/shared/codec/s3/offloader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,eAAe,EAAE,MAAM,UAAU,CAAC;AAKvD;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,YAAY,MAAM,EAAE,eAAe,EAOlC;IAED,OAAO,CAAC,SAAS;IA0BjB,8DAA8D;IAC9D,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAEvC;IAED,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEzC;IAED,iCAAiC;IACjC,YAAY,IAAI,MAAM,CAErB;IAED,oDAAoD;IAC9C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAS3D;IAED,6CAA6C;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAE/C;IAED,+DAA+D;IACzD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnD;IAED,iFAAiF;IAC3E,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExD;IAED;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAGd;CACF"}
@@ -14,6 +14,7 @@ const read_write_1 = require("./read-write");
14
14
  class S3Offloader {
15
15
  clientPromise;
16
16
  resolvedClient;
17
+ destroyed = false;
17
18
  bucketName;
18
19
  keyPrefix;
19
20
  thresholdBytes;
@@ -35,6 +36,12 @@ class S3Offloader {
35
36
  ? Promise.resolve(this.config.createS3Client({ maxAttempts: 1, ...cfg }))
36
37
  : (0, client_1.createDefaultS3Client)(cfg)).then((client) => {
37
38
  this.resolvedClient = client;
39
+ /**
40
+ * `destroy()` may have run during this construction, when there was
41
+ * no client yet to release. Release it now instead of leaking it.
42
+ */
43
+ if (this.destroyed)
44
+ client.destroy();
38
45
  return client;
39
46
  }, (error) => {
40
47
  this.clientPromise = undefined;
@@ -78,8 +85,14 @@ class S3Offloader {
78
85
  async ensureLifecycleRule(ttlDays) {
79
86
  return (0, lifecycle_1.ensureLifecycleRule)(await this.getClient(), this.bucketName, this.keyPrefix, ttlDays);
80
87
  }
81
- /** Release the underlying S3 client, if one was created. */
88
+ /**
89
+ * Release the underlying S3 client. Safe at any point in the client's
90
+ * lifecycle: called before construction starts it does nothing, called
91
+ * mid-construction it marks the offloader destroyed so the client is
92
+ * released the moment it resolves, and called after it releases it directly.
93
+ */
82
94
  destroy() {
95
+ this.destroyed = true;
83
96
  this.resolvedClient?.destroy();
84
97
  }
85
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"offloader.js","sourceRoot":"","sources":["../../../../src/shared/codec/s3/offloader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"offloader.js","sourceRoot":"","sources":["../../../../src/shared/codec/s3/offloader.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"batch-write.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/batch-write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAI9D,OAAO,EAAE,YAAY,EAA0B,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO5C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAyBf"}
1
+ {"version":3,"file":"batch-write.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/batch-write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAI9D,OAAO,EAAE,YAAY,EAA0B,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAgCf"}
@@ -4,10 +4,6 @@ exports.batchWriteAll = batchWriteAll;
4
4
  const constants_1 = require("../constants");
5
5
  const errors_1 = require("../errors/errors");
6
6
  const drain_unprocessed_1 = require("./drain-unprocessed");
7
- /** True when `error` is a {@link BatchWriteIncompleteError} — checked by name, not `instanceof`. */
8
- function isBatchWriteIncomplete(error) {
9
- return error.name === 'BatchWriteIncompleteError';
10
- }
11
7
  /**
12
8
  * Write an arbitrary number of requests, chunked into batches of 25 (the
13
9
  * BatchWriteItem limit). Every chunk is attempted regardless of an earlier
@@ -39,10 +35,16 @@ async function batchWriteAll(client, tableName, requests, options = {}) {
39
35
  succeededCount += chunk.length;
40
36
  }
41
37
  catch (error) {
38
+ /**
39
+ * drainUnprocessedWrites has exactly three throw sites and every one
40
+ * constructs a BatchWriteIncompleteError with an accurate
41
+ * succeededCount — asserted, not name-checked, since the false case is
42
+ * unreachable and this project enforces 100% branch coverage with no
43
+ * exceptions (see drain-unprocessed.ts).
44
+ */
42
45
  const err = error;
43
46
  failedChunks.push(err);
44
- if (isBatchWriteIncomplete(err))
45
- succeededCount += err.succeededCount;
47
+ succeededCount += err.succeededCount;
46
48
  }
47
49
  }
48
50
  if (failedChunks.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"batch-write.js","sourceRoot":"","sources":["../../../src/shared/dynamodb/batch-write.ts"],"names":[],"mappings":";;;AAEA,4CAA+C;AAC/C,6CAA2F;AAC3F,2DAA2E;AAG3E,oGAAoG;AACpG,SAAS,sBAAsB,CAAC,KAAY;IAC1C,OAAO,KAAK,CAAC,IAAI,KAAK,2BAA2B,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACI,KAAK,wBACV,MAAwB,EACxB,SAAiB,EACjB,QAAwB,EACxB,OAAO,GAAiB,EAAE;IAE1B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,2BAAe,CAAC,CAAC;IACjE,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,YAAY,GAAY,EAAE,CAAC;IACjC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,2BAAe,EAAE,CAAC;QACzE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,2BAAe,CAAC,CAAC;QAC/D,IAAI,CAAC;YACH,MAAM,IAAA,0CAAsB,EAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAChE,eAAe,IAAI,CAAC,CAAC;YACrB,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAc,CAAC;YAC3B,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,sBAAsB,CAAC,GAAG,CAAC;gBAAE,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC;QACxE,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,qCAA4B,CACpC,eAAe,EACf,WAAW,EACX,YAAY,EACZ,cAAc,CACf,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"batch-write.js","sourceRoot":"","sources":["../../../src/shared/dynamodb/batch-write.ts"],"names":[],"mappings":";;;AAEA,4CAA+C;AAC/C,6CAA2F;AAC3F,2DAA2E;AAG3E;;;;;;;;;;;;;;;;;GAiBG;AACI,KAAK,wBACV,MAAwB,EACxB,SAAiB,EACjB,QAAwB,EACxB,OAAO,GAAiB,EAAE;IAE1B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,2BAAe,CAAC,CAAC;IACjE,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,YAAY,GAAY,EAAE,CAAC;IACjC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,2BAAe,EAAE,CAAC;QACzE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,2BAAe,CAAC,CAAC;QAC/D,IAAI,CAAC;YACH,MAAM,IAAA,0CAAsB,EAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAChE,eAAe,IAAI,CAAC,CAAC;YACrB,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf;;;;;;eAMG;YACH,MAAM,GAAG,GAAG,KAAkC,CAAC;YAC/C,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC;QACvC,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,qCAA4B,CACpC,eAAe,EACf,WAAW,EACX,YAAY,EACZ,cAAc,CACf,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -9,7 +9,11 @@ export interface DrainOptions {
9
9
  /**
10
10
  * Submit `requests` via BatchWriteItem and re-submit UnprocessedItems with
11
11
  * full-jitter backoff until the batch drains. Throws
12
- * {@link BatchWriteIncompleteError} if it cannot drain within the retry budget.
12
+ * {@link BatchWriteIncompleteError} if it cannot drain within the retry budget,
13
+ * or if a round's write call or backoff wait throws outright (SDK failure, or
14
+ * the caller's signal aborting) — in every case `succeededCount` reflects
15
+ * every earlier round's confirmed persists, and the triggering error is
16
+ * attached as `cause`.
13
17
  */
14
18
  export declare function drainUnprocessedWrites(client: DynamoDBDocument, tableName: string, requests: WriteRequest[], options?: DrainOptions): Promise<void>;
15
19
  //# sourceMappingURL=drain-unprocessed.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"drain-unprocessed.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/drain-unprocessed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAM9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAsBf"}
1
+ {"version":3,"file":"drain-unprocessed.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/drain-unprocessed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAM9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CA8Bf"}