@farukada/aws-langgraph-dynamodb-ts 0.7.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 (169) hide show
  1. package/README.md +52 -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/internal/item-reader.d.ts +31 -0
  13. package/dist/checkpointer/internal/item-reader.d.ts.map +1 -1
  14. package/dist/checkpointer/internal/item-reader.js +49 -1
  15. package/dist/checkpointer/internal/item-reader.js.map +1 -1
  16. package/dist/checkpointer/internal/item-writer.d.ts +0 -8
  17. package/dist/checkpointer/internal/item-writer.d.ts.map +1 -1
  18. package/dist/checkpointer/internal/item-writer.js +15 -21
  19. package/dist/checkpointer/internal/item-writer.js.map +1 -1
  20. package/dist/checkpointer/internal/keys.d.ts +19 -3
  21. package/dist/checkpointer/internal/keys.d.ts.map +1 -1
  22. package/dist/checkpointer/internal/keys.js +41 -6
  23. package/dist/checkpointer/internal/keys.js.map +1 -1
  24. package/dist/checkpointer/internal/validation.d.ts +8 -4
  25. package/dist/checkpointer/internal/validation.d.ts.map +1 -1
  26. package/dist/checkpointer/internal/validation.js +12 -10
  27. package/dist/checkpointer/internal/validation.js.map +1 -1
  28. package/dist/checkpointer/internal/write-guard.d.ts +21 -0
  29. package/dist/checkpointer/internal/write-guard.d.ts.map +1 -0
  30. package/dist/checkpointer/internal/write-guard.js +48 -0
  31. package/dist/checkpointer/internal/write-guard.js.map +1 -0
  32. package/dist/checkpointer/internal/write-index.d.ts +29 -0
  33. package/dist/checkpointer/internal/write-index.d.ts.map +1 -0
  34. package/dist/checkpointer/internal/write-index.js +38 -0
  35. package/dist/checkpointer/internal/write-index.js.map +1 -0
  36. package/dist/checkpointer/types.d.ts +2 -0
  37. package/dist/checkpointer/types.d.ts.map +1 -1
  38. package/dist/history/actions/add-messages.d.ts.map +1 -1
  39. package/dist/history/actions/add-messages.js +24 -4
  40. package/dist/history/actions/add-messages.js.map +1 -1
  41. package/dist/history/actions/clear.d.ts +4 -6
  42. package/dist/history/actions/clear.d.ts.map +1 -1
  43. package/dist/history/actions/clear.js +18 -33
  44. package/dist/history/actions/clear.js.map +1 -1
  45. package/dist/history/actions/get-messages.d.ts +2 -1
  46. package/dist/history/actions/get-messages.d.ts.map +1 -1
  47. package/dist/history/actions/get-messages.js +28 -2
  48. package/dist/history/actions/get-messages.js.map +1 -1
  49. package/dist/history/actions/list-sessions.d.ts +2 -1
  50. package/dist/history/actions/list-sessions.d.ts.map +1 -1
  51. package/dist/history/actions/list-sessions.js +21 -2
  52. package/dist/history/actions/list-sessions.js.map +1 -1
  53. package/dist/history/actions/reconcile-count.d.ts.map +1 -1
  54. package/dist/history/actions/reconcile-count.js +2 -2
  55. package/dist/history/actions/reconcile-count.js.map +1 -1
  56. package/dist/history/internal/append-saga.d.ts.map +1 -1
  57. package/dist/history/internal/append-saga.js +2 -78
  58. package/dist/history/internal/append-saga.js.map +1 -1
  59. package/dist/history/internal/compensation.d.ts +21 -0
  60. package/dist/history/internal/compensation.d.ts.map +1 -0
  61. package/dist/history/internal/compensation.js +84 -0
  62. package/dist/history/internal/compensation.js.map +1 -0
  63. package/dist/history/internal/keys.d.ts +9 -1
  64. package/dist/history/internal/keys.d.ts.map +1 -1
  65. package/dist/history/internal/keys.js +21 -4
  66. package/dist/history/internal/keys.js.map +1 -1
  67. package/dist/history/internal/message-chunker.d.ts.map +1 -1
  68. package/dist/history/internal/message-chunker.js +13 -5
  69. package/dist/history/internal/message-chunker.js.map +1 -1
  70. package/dist/history/internal/session-count.d.ts +21 -0
  71. package/dist/history/internal/session-count.d.ts.map +1 -1
  72. package/dist/history/internal/session-count.js +51 -0
  73. package/dist/history/internal/session-count.js.map +1 -1
  74. package/dist/history/internal/session-title.d.ts +20 -0
  75. package/dist/history/internal/session-title.d.ts.map +1 -0
  76. package/dist/history/internal/session-title.js +44 -0
  77. package/dist/history/internal/session-title.js.map +1 -0
  78. package/dist/history/internal/setup.d.ts +2 -1
  79. package/dist/history/internal/setup.d.ts.map +1 -1
  80. package/dist/history/internal/setup.js +1 -0
  81. package/dist/history/internal/setup.js.map +1 -1
  82. package/dist/history/internal/title-generator.d.ts +8 -2
  83. package/dist/history/internal/title-generator.d.ts.map +1 -1
  84. package/dist/history/internal/title-generator.js +12 -3
  85. package/dist/history/internal/title-generator.js.map +1 -1
  86. package/dist/history/internal/validation.d.ts +9 -0
  87. package/dist/history/internal/validation.d.ts.map +1 -0
  88. package/dist/history/internal/validation.js +16 -0
  89. package/dist/history/internal/validation.js.map +1 -0
  90. package/dist/history/types.d.ts +12 -0
  91. package/dist/history/types.d.ts.map +1 -1
  92. package/dist/index.d.ts +1 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js.map +1 -1
  95. package/dist/shared/codec/s3/offloader.d.ts +7 -1
  96. package/dist/shared/codec/s3/offloader.d.ts.map +1 -1
  97. package/dist/shared/codec/s3/offloader.js +14 -1
  98. package/dist/shared/codec/s3/offloader.js.map +1 -1
  99. package/dist/shared/dynamodb/partition-delete.d.ts +33 -0
  100. package/dist/shared/dynamodb/partition-delete.d.ts.map +1 -0
  101. package/dist/shared/dynamodb/partition-delete.js +70 -0
  102. package/dist/shared/dynamodb/partition-delete.js.map +1 -0
  103. package/dist/shared/dynamodb/retry-classifier.d.ts.map +1 -1
  104. package/dist/shared/dynamodb/retry-classifier.js +9 -1
  105. package/dist/shared/dynamodb/retry-classifier.js.map +1 -1
  106. package/dist/shared/logging/redaction-walk.d.ts +23 -0
  107. package/dist/shared/logging/redaction-walk.d.ts.map +1 -0
  108. package/dist/shared/logging/redaction-walk.js +92 -0
  109. package/dist/shared/logging/redaction-walk.js.map +1 -0
  110. package/dist/shared/logging/redaction.d.ts +22 -17
  111. package/dist/shared/logging/redaction.d.ts.map +1 -1
  112. package/dist/shared/logging/redaction.js +24 -48
  113. package/dist/shared/logging/redaction.js.map +1 -1
  114. package/dist/shared/logging/secret-patterns.d.ts +41 -0
  115. package/dist/shared/logging/secret-patterns.d.ts.map +1 -0
  116. package/dist/shared/logging/secret-patterns.js +74 -0
  117. package/dist/shared/logging/secret-patterns.js.map +1 -0
  118. package/dist/shared/validation/primitives.d.ts +9 -1
  119. package/dist/shared/validation/primitives.d.ts.map +1 -1
  120. package/dist/shared/validation/primitives.js +13 -0
  121. package/dist/shared/validation/primitives.js.map +1 -1
  122. package/dist/store/actions/get.d.ts.map +1 -1
  123. package/dist/store/actions/get.js +15 -1
  124. package/dist/store/actions/get.js.map +1 -1
  125. package/dist/store/actions/list-namespaces.d.ts.map +1 -1
  126. package/dist/store/actions/list-namespaces.js +1 -0
  127. package/dist/store/actions/list-namespaces.js.map +1 -1
  128. package/dist/store/actions/put.d.ts.map +1 -1
  129. package/dist/store/actions/put.js +20 -2
  130. package/dist/store/actions/put.js.map +1 -1
  131. package/dist/store/actions/search.d.ts.map +1 -1
  132. package/dist/store/actions/search.js +4 -35
  133. package/dist/store/actions/search.js.map +1 -1
  134. package/dist/store/internal/backend-search.d.ts +5 -0
  135. package/dist/store/internal/backend-search.d.ts.map +1 -0
  136. package/dist/store/internal/backend-search.js +67 -0
  137. package/dist/store/internal/backend-search.js.map +1 -0
  138. package/dist/store/internal/filter.d.ts.map +1 -1
  139. package/dist/store/internal/filter.js +26 -5
  140. package/dist/store/internal/filter.js.map +1 -1
  141. package/dist/store/internal/index-reconcile.d.ts.map +1 -1
  142. package/dist/store/internal/index-reconcile.js +33 -3
  143. package/dist/store/internal/index-reconcile.js.map +1 -1
  144. package/dist/store/internal/keys.d.ts +1 -1
  145. package/dist/store/internal/keys.d.ts.map +1 -1
  146. package/dist/store/internal/keys.js +8 -2
  147. package/dist/store/internal/keys.js.map +1 -1
  148. package/dist/store/internal/persist.d.ts.map +1 -1
  149. package/dist/store/internal/persist.js +1 -5
  150. package/dist/store/internal/persist.js.map +1 -1
  151. package/dist/store/internal/search-filter.d.ts +4 -0
  152. package/dist/store/internal/search-filter.d.ts.map +1 -0
  153. package/dist/store/internal/search-filter.js +11 -0
  154. package/dist/store/internal/search-filter.js.map +1 -0
  155. package/dist/store/internal/setup.d.ts +11 -1
  156. package/dist/store/internal/setup.d.ts.map +1 -1
  157. package/dist/store/internal/setup.js +17 -1
  158. package/dist/store/internal/setup.js.map +1 -1
  159. package/dist/store/internal/validation.d.ts +8 -2
  160. package/dist/store/internal/validation.d.ts.map +1 -1
  161. package/dist/store/internal/validation.js +15 -6
  162. package/dist/store/internal/validation.js.map +1 -1
  163. package/dist/store/internal/write-verify.d.ts +12 -0
  164. package/dist/store/internal/write-verify.d.ts.map +1 -1
  165. package/dist/store/internal/write-verify.js +27 -0
  166. package/dist/store/internal/write-verify.js.map +1 -1
  167. package/dist/store/vector-backend.d.ts +17 -0
  168. package/dist/store/vector-backend.d.ts.map +1 -1
  169. package/package.json +1 -1
@@ -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":";;;AAEA,+CAAoG;AACpG,qCAAiD;AACjD,qCAAuD;AACvD,qCAAyC;AACzC,2CAAkD;AAClD,6CAA4D;AAE5D;;;GAGG;AACH;IACU,aAAa,CAAgC;IAC7C,cAAc,CAAuB;IACrC,SAAS,GAAG,KAAK,CAAC;IACT,UAAU,CAAS;IACnB,SAAS,CAAS;IAClB,cAAc,CAAS;IACvB,GAAG,CAAS;IACZ,WAAW,CAAU;IACrB,MAAM,CAAkB;IAEzC,YAAY,MAAuB;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,iCAAqB,CAAC;QAC3D,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,sCAA0B,CAAC;QAC1E,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,oBAAoB,IAAI,0BAAc,CAAC;QACzD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACxC,CAAC;IAEO,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC;YAC3C,IAAI,CAAC,aAAa,GAAG,CACnB,IAAI,CAAC,MAAM,CAAC,cAAc;gBACxB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;gBACzE,CAAC,CAAC,IAAA,8BAAqB,EAAC,GAAG,CAAC,CAC/B,CAAC,IAAI,CACJ,CAAC,MAAM,EAAE,EAAE;gBACT,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;gBAC7B;;;mBAGG;gBACH,IAAI,IAAI,CAAC,SAAS;oBAAE,MAAM,CAAC,OAAO,EAAE,CAAC;gBACrC,OAAO,MAAM,CAAC;YAChB,CAAC,EACD,CAAC,KAAY,EAAE,EAAE;gBACf,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBAC/B,MAAM,KAAK,CAAC;YACd,CAAC,CACF,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,8DAA8D;IAC9D,aAAa,CAAC,IAAgB;QAC5B,OAAO,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,cAAc,CAAC;IAC5C,CAAC;IAED,gDAAgD;IAChD,QAAQ,CAAC,KAAwB;QAC/B,OAAO,IAAA,mBAAU,EAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,iCAAiC;IACjC,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,oDAAoD;IACpD,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,IAAgB;QACxC,MAAM,IAAA,yBAAY,EAAC,MAAM,IAAI,CAAC,SAAS,EAAE,EAAE;YACzC,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,GAAG;YACH,IAAI;YACJ,oBAAoB,EAAE,IAAI,CAAC,GAAG;YAC9B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;QACH,OAAO,GAAG,CAAC;IACb,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,OAAO,IAAA,2BAAc,EAAC,MAAM,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACtE,CAAC;IAED,+DAA+D;IAC/D,KAAK,CAAC,WAAW,CAAC,IAAc;QAC9B,OAAO,IAAA,sBAAa,EAAC,MAAM,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,iFAAiF;IACjF,KAAK,CAAC,mBAAmB,CAAC,OAAe;QACvC,OAAO,IAAA,+BAAmB,EAAC,MAAM,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/F,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACL,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ import type { DynamoDBDocument, QueryCommandInput } from '@aws-sdk/lib-dynamodb';
2
+ import type { PayloadDescriptor } from '../codec/codec';
3
+ import type { S3Offloader } from '../codec/s3/offloader';
4
+ import type { Logger } from '../logging/logger';
5
+ import type { DocItem } from './types';
6
+ /** Collaborators and per-adapter policy for one partition-wide delete. */
7
+ export interface PartitionDeleteOptions {
8
+ client: DynamoDBDocument;
9
+ tableName: string;
10
+ params: QueryCommandInput;
11
+ logger: Logger;
12
+ offloader?: S3Offloader;
13
+ /** Label for log lines and S3-cleanup diagnostics, e.g. `deleteThread`. */
14
+ operation: string;
15
+ /**
16
+ * True when a sort key belongs to the calling adapter. A partition query
17
+ * carries no sort-key condition, so without this a shared-table partition
18
+ * holding a foreign row would have that row deleted too.
19
+ */
20
+ ownsSortKey: (sortKey: string) => boolean;
21
+ /** The offloaded payload descriptors a row references, if any. */
22
+ descriptorsOf: (row: DocItem) => (PayloadDescriptor | undefined)[];
23
+ }
24
+ /**
25
+ * Delete every row in a partition that belongs to the calling adapter,
26
+ * best-effort deleting any offloaded S3 objects. Streams the partition with
27
+ * unbounded pagination and flushes in batches, so a partition of any size is
28
+ * deleted to completion with bounded memory — never silently truncated at the
29
+ * in-memory page caps, and never discarding already-flushed progress if a
30
+ * later batch fails. Returns the number of rows deleted.
31
+ */
32
+ export declare function deletePartitionRows(options: PartitionDeleteOptions): Promise<number>;
33
+ //# sourceMappingURL=partition-delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partition-delete.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/partition-delete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,kEAAkE;IAClE,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,iBAAiB,GAAG,SAAS,CAAC,EAAE,CAAC;CACpE;AA2DD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B1F"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deletePartitionRows = deletePartitionRows;
4
+ const descriptor_keys_1 = require("../codec/descriptor-keys");
5
+ const orphans_1 = require("../codec/s3/orphans");
6
+ const constants_1 = require("../constants");
7
+ const errors_1 = require("../errors/errors");
8
+ const batch_write_1 = require("./batch-write");
9
+ const paginate_1 = require("./paginate");
10
+ /** Delete the buffered keys, best-effort clean their S3 objects, then clear it. */
11
+ async function flushBuffer(options, buffer, progress) {
12
+ if (buffer.keys.length === 0)
13
+ return;
14
+ const chunks = Math.ceil(buffer.keys.length / constants_1.BATCH_WRITE_MAX);
15
+ try {
16
+ await (0, batch_write_1.batchWriteAll)(options.client, options.tableName, buffer.keys.map((Key) => ({ DeleteRequest: { Key } })));
17
+ }
18
+ catch (error) {
19
+ /** batchWriteAll's only throw is a BatchWriteAllIncompleteError (see batch-write.ts). */
20
+ const failure = error;
21
+ throw new errors_1.BatchWriteAllIncompleteError(progress.succeededChunks + failure.succeededChunks, progress.totalChunks + failure.totalChunks, failure.failedChunks, progress.writes + failure.succeededCount);
22
+ }
23
+ progress.writes += buffer.keys.length;
24
+ progress.succeededChunks += chunks;
25
+ progress.totalChunks += chunks;
26
+ if (options.offloader) {
27
+ await (0, orphans_1.cleanUpS3Orphans)(options.offloader, (0, descriptor_keys_1.collectS3Keys)(buffer.descriptors), options.operation, options.logger);
28
+ }
29
+ buffer.keys = [];
30
+ buffer.descriptors = [];
31
+ }
32
+ /**
33
+ * Delete every row in a partition that belongs to the calling adapter,
34
+ * best-effort deleting any offloaded S3 objects. Streams the partition with
35
+ * unbounded pagination and flushes in batches, so a partition of any size is
36
+ * deleted to completion with bounded memory — never silently truncated at the
37
+ * in-memory page caps, and never discarding already-flushed progress if a
38
+ * later batch fails. Returns the number of rows deleted.
39
+ */
40
+ async function deletePartitionRows(options) {
41
+ const buffer = { keys: [], descriptors: [] };
42
+ const progress = { writes: 0, succeededChunks: 0, totalChunks: 0 };
43
+ let skipped = 0;
44
+ const pages = (0, paginate_1.paginateQuery)({
45
+ client: options.client,
46
+ params: options.params,
47
+ maxItems: Number.POSITIVE_INFINITY,
48
+ maxIterations: Number.POSITIVE_INFINITY,
49
+ });
50
+ for await (const row of pages) {
51
+ if (!options.ownsSortKey(row.SK)) {
52
+ skipped += 1;
53
+ options.logger.warn(`${options.operation}: left a foreign row in place`, {
54
+ sortKey: row.SK,
55
+ });
56
+ continue;
57
+ }
58
+ buffer.keys.push({ PK: row.PK, SK: row.SK });
59
+ for (const descriptor of options.descriptorsOf(row)) {
60
+ if (descriptor)
61
+ buffer.descriptors.push(descriptor);
62
+ }
63
+ if (buffer.keys.length >= constants_1.BATCH_WRITE_MAX)
64
+ await flushBuffer(options, buffer, progress);
65
+ }
66
+ await flushBuffer(options, buffer, progress);
67
+ options.logger.info(`${options.operation}: deleted rows`, { deleted: progress.writes, skipped });
68
+ return progress.writes;
69
+ }
70
+ //# sourceMappingURL=partition-delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partition-delete.js","sourceRoot":"","sources":["../../../src/shared/dynamodb/partition-delete.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"retry-classifier.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/retry-classifier.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAiBrD,CAAC;AAmDF,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAK1F"}
1
+ {"version":3,"file":"retry-classifier.d.ts","sourceRoot":"","sources":["../../../src/shared/dynamodb/retry-classifier.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAiBrD,CAAC;AA6DF,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAK1F"}
@@ -47,7 +47,15 @@ function transactionCancellationRetryable(error) {
47
47
  const reasons = (0, cancellation_1.getCancellationReasons)(error);
48
48
  if (!reasons)
49
49
  return undefined;
50
- return reasons.every((reason) => reason.Code === undefined || TRANSIENT_CANCELLATION_REASONS.includes(reason.Code));
50
+ /**
51
+ * `length > 0` is load-bearing: `.every()` is vacuously true on an empty
52
+ * array, which would make a reason-less cancellation retryable — the exact
53
+ * opposite of what this function documents. AWS populates one reason per
54
+ * `TransactItems` entry, so an empty array should not occur; if it ever
55
+ * does, the conservative answer is not to retry.
56
+ */
57
+ return (reasons.length > 0 &&
58
+ reasons.every((reason) => reason.Code === undefined || TRANSIENT_CANCELLATION_REASONS.includes(reason.Code)));
51
59
  }
52
60
  function collectSignals(error) {
53
61
  const seen = new WeakSet();