@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.
- package/README.md +52 -9
- package/dist/checkpointer/actions/delete-thread.d.ts +3 -4
- package/dist/checkpointer/actions/delete-thread.d.ts.map +1 -1
- package/dist/checkpointer/actions/delete-thread.js +21 -41
- package/dist/checkpointer/actions/delete-thread.js.map +1 -1
- package/dist/checkpointer/actions/list.d.ts.map +1 -1
- package/dist/checkpointer/actions/list.js +31 -4
- package/dist/checkpointer/actions/list.js.map +1 -1
- package/dist/checkpointer/actions/put-writes.d.ts.map +1 -1
- package/dist/checkpointer/actions/put-writes.js +14 -24
- package/dist/checkpointer/actions/put-writes.js.map +1 -1
- package/dist/checkpointer/internal/item-reader.d.ts +31 -0
- package/dist/checkpointer/internal/item-reader.d.ts.map +1 -1
- package/dist/checkpointer/internal/item-reader.js +49 -1
- package/dist/checkpointer/internal/item-reader.js.map +1 -1
- package/dist/checkpointer/internal/item-writer.d.ts +0 -8
- package/dist/checkpointer/internal/item-writer.d.ts.map +1 -1
- package/dist/checkpointer/internal/item-writer.js +15 -21
- package/dist/checkpointer/internal/item-writer.js.map +1 -1
- package/dist/checkpointer/internal/keys.d.ts +19 -3
- package/dist/checkpointer/internal/keys.d.ts.map +1 -1
- package/dist/checkpointer/internal/keys.js +41 -6
- package/dist/checkpointer/internal/keys.js.map +1 -1
- package/dist/checkpointer/internal/validation.d.ts +8 -4
- package/dist/checkpointer/internal/validation.d.ts.map +1 -1
- package/dist/checkpointer/internal/validation.js +12 -10
- package/dist/checkpointer/internal/validation.js.map +1 -1
- package/dist/checkpointer/internal/write-guard.d.ts +21 -0
- package/dist/checkpointer/internal/write-guard.d.ts.map +1 -0
- package/dist/checkpointer/internal/write-guard.js +48 -0
- package/dist/checkpointer/internal/write-guard.js.map +1 -0
- package/dist/checkpointer/internal/write-index.d.ts +29 -0
- package/dist/checkpointer/internal/write-index.d.ts.map +1 -0
- package/dist/checkpointer/internal/write-index.js +38 -0
- package/dist/checkpointer/internal/write-index.js.map +1 -0
- package/dist/checkpointer/types.d.ts +2 -0
- package/dist/checkpointer/types.d.ts.map +1 -1
- package/dist/history/actions/add-messages.d.ts.map +1 -1
- package/dist/history/actions/add-messages.js +24 -4
- package/dist/history/actions/add-messages.js.map +1 -1
- package/dist/history/actions/clear.d.ts +4 -6
- package/dist/history/actions/clear.d.ts.map +1 -1
- package/dist/history/actions/clear.js +18 -33
- package/dist/history/actions/clear.js.map +1 -1
- package/dist/history/actions/get-messages.d.ts +2 -1
- package/dist/history/actions/get-messages.d.ts.map +1 -1
- package/dist/history/actions/get-messages.js +28 -2
- package/dist/history/actions/get-messages.js.map +1 -1
- package/dist/history/actions/list-sessions.d.ts +2 -1
- package/dist/history/actions/list-sessions.d.ts.map +1 -1
- package/dist/history/actions/list-sessions.js +21 -2
- package/dist/history/actions/list-sessions.js.map +1 -1
- package/dist/history/actions/reconcile-count.d.ts.map +1 -1
- package/dist/history/actions/reconcile-count.js +2 -2
- package/dist/history/actions/reconcile-count.js.map +1 -1
- package/dist/history/internal/append-saga.d.ts.map +1 -1
- package/dist/history/internal/append-saga.js +2 -78
- package/dist/history/internal/append-saga.js.map +1 -1
- package/dist/history/internal/compensation.d.ts +21 -0
- package/dist/history/internal/compensation.d.ts.map +1 -0
- package/dist/history/internal/compensation.js +84 -0
- package/dist/history/internal/compensation.js.map +1 -0
- package/dist/history/internal/keys.d.ts +9 -1
- package/dist/history/internal/keys.d.ts.map +1 -1
- package/dist/history/internal/keys.js +21 -4
- package/dist/history/internal/keys.js.map +1 -1
- package/dist/history/internal/message-chunker.d.ts.map +1 -1
- package/dist/history/internal/message-chunker.js +13 -5
- package/dist/history/internal/message-chunker.js.map +1 -1
- package/dist/history/internal/session-count.d.ts +21 -0
- package/dist/history/internal/session-count.d.ts.map +1 -1
- package/dist/history/internal/session-count.js +51 -0
- package/dist/history/internal/session-count.js.map +1 -1
- package/dist/history/internal/session-title.d.ts +20 -0
- package/dist/history/internal/session-title.d.ts.map +1 -0
- package/dist/history/internal/session-title.js +44 -0
- package/dist/history/internal/session-title.js.map +1 -0
- package/dist/history/internal/setup.d.ts +2 -1
- package/dist/history/internal/setup.d.ts.map +1 -1
- package/dist/history/internal/setup.js +1 -0
- package/dist/history/internal/setup.js.map +1 -1
- package/dist/history/internal/title-generator.d.ts +8 -2
- package/dist/history/internal/title-generator.d.ts.map +1 -1
- package/dist/history/internal/title-generator.js +12 -3
- package/dist/history/internal/title-generator.js.map +1 -1
- package/dist/history/internal/validation.d.ts +9 -0
- package/dist/history/internal/validation.d.ts.map +1 -0
- package/dist/history/internal/validation.js +16 -0
- package/dist/history/internal/validation.js.map +1 -0
- package/dist/history/types.d.ts +12 -0
- package/dist/history/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/shared/codec/s3/offloader.d.ts +7 -1
- package/dist/shared/codec/s3/offloader.d.ts.map +1 -1
- package/dist/shared/codec/s3/offloader.js +14 -1
- package/dist/shared/codec/s3/offloader.js.map +1 -1
- package/dist/shared/dynamodb/partition-delete.d.ts +33 -0
- package/dist/shared/dynamodb/partition-delete.d.ts.map +1 -0
- package/dist/shared/dynamodb/partition-delete.js +70 -0
- package/dist/shared/dynamodb/partition-delete.js.map +1 -0
- package/dist/shared/dynamodb/retry-classifier.d.ts.map +1 -1
- package/dist/shared/dynamodb/retry-classifier.js +9 -1
- package/dist/shared/dynamodb/retry-classifier.js.map +1 -1
- package/dist/shared/logging/redaction-walk.d.ts +23 -0
- package/dist/shared/logging/redaction-walk.d.ts.map +1 -0
- package/dist/shared/logging/redaction-walk.js +92 -0
- package/dist/shared/logging/redaction-walk.js.map +1 -0
- package/dist/shared/logging/redaction.d.ts +22 -17
- package/dist/shared/logging/redaction.d.ts.map +1 -1
- package/dist/shared/logging/redaction.js +24 -48
- package/dist/shared/logging/redaction.js.map +1 -1
- package/dist/shared/logging/secret-patterns.d.ts +41 -0
- package/dist/shared/logging/secret-patterns.d.ts.map +1 -0
- package/dist/shared/logging/secret-patterns.js +74 -0
- package/dist/shared/logging/secret-patterns.js.map +1 -0
- package/dist/shared/validation/primitives.d.ts +9 -1
- package/dist/shared/validation/primitives.d.ts.map +1 -1
- package/dist/shared/validation/primitives.js +13 -0
- package/dist/shared/validation/primitives.js.map +1 -1
- package/dist/store/actions/get.d.ts.map +1 -1
- package/dist/store/actions/get.js +15 -1
- package/dist/store/actions/get.js.map +1 -1
- package/dist/store/actions/list-namespaces.d.ts.map +1 -1
- package/dist/store/actions/list-namespaces.js +1 -0
- package/dist/store/actions/list-namespaces.js.map +1 -1
- package/dist/store/actions/put.d.ts.map +1 -1
- package/dist/store/actions/put.js +20 -2
- package/dist/store/actions/put.js.map +1 -1
- package/dist/store/actions/search.d.ts.map +1 -1
- package/dist/store/actions/search.js +4 -35
- package/dist/store/actions/search.js.map +1 -1
- package/dist/store/internal/backend-search.d.ts +5 -0
- package/dist/store/internal/backend-search.d.ts.map +1 -0
- package/dist/store/internal/backend-search.js +67 -0
- package/dist/store/internal/backend-search.js.map +1 -0
- package/dist/store/internal/filter.d.ts.map +1 -1
- package/dist/store/internal/filter.js +26 -5
- package/dist/store/internal/filter.js.map +1 -1
- package/dist/store/internal/index-reconcile.d.ts.map +1 -1
- package/dist/store/internal/index-reconcile.js +33 -3
- package/dist/store/internal/index-reconcile.js.map +1 -1
- package/dist/store/internal/keys.d.ts +1 -1
- package/dist/store/internal/keys.d.ts.map +1 -1
- package/dist/store/internal/keys.js +8 -2
- package/dist/store/internal/keys.js.map +1 -1
- package/dist/store/internal/persist.d.ts.map +1 -1
- package/dist/store/internal/persist.js +1 -5
- package/dist/store/internal/persist.js.map +1 -1
- package/dist/store/internal/search-filter.d.ts +4 -0
- package/dist/store/internal/search-filter.d.ts.map +1 -0
- package/dist/store/internal/search-filter.js +11 -0
- package/dist/store/internal/search-filter.js.map +1 -0
- package/dist/store/internal/setup.d.ts +11 -1
- package/dist/store/internal/setup.d.ts.map +1 -1
- package/dist/store/internal/setup.js +17 -1
- package/dist/store/internal/setup.js.map +1 -1
- package/dist/store/internal/validation.d.ts +8 -2
- package/dist/store/internal/validation.d.ts.map +1 -1
- package/dist/store/internal/validation.js +15 -6
- package/dist/store/internal/validation.js.map +1 -1
- package/dist/store/internal/write-verify.d.ts +12 -0
- package/dist/store/internal/write-verify.d.ts.map +1 -1
- package/dist/store/internal/write-verify.js +27 -0
- package/dist/store/internal/write-verify.js.map +1 -1
- package/dist/store/vector-backend.d.ts +17 -0
- package/dist/store/vector-backend.d.ts.map +1 -1
- 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,
|
|
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":"
|
|
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":"
|
|
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;
|
|
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;
|
|
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,
|
|
4
|
-
*
|
|
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
|
|
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,
|
|
7
|
-
*
|
|
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
|
-
|
|
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
|
|
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"}
|
package/dist/history/types.d.ts
CHANGED
|
@@ -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;
|
|
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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;
|
|
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
|
-
/**
|
|
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;
|
|
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
|
-
/**
|
|
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":";;;AAEA,+CAAoG;AACpG,qCAAiD;AACjD,qCAAuD;AACvD,qCAAyC;AACzC,2CAAkD;AAClD,6CAA4D;AAE5D;;;GAGG;AACH;IACU,aAAa,CAAgC;IAC7C,cAAc,CAAuB;
|
|
1
|
+
{"version":3,"file":"offloader.js","sourceRoot":"","sources":["../../../../src/shared/codec/s3/offloader.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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
|
-
|
|
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();
|