@farukada/aws-langgraph-dynamodb-ts 1.0.0-rc.1 → 1.0.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 +1820 -290
- package/dist/cjs/backfill/backfill.d.ts +171 -0
- package/dist/cjs/backfill/backfill.js +177 -0
- package/dist/cjs/checkpointer/actions/delete-thread.d.ts +50 -0
- package/dist/cjs/checkpointer/actions/delete-thread.js +26 -0
- package/dist/cjs/checkpointer/actions/get-tuple.d.ts +36 -0
- package/dist/cjs/checkpointer/actions/get-tuple.js +22 -0
- package/dist/cjs/checkpointer/actions/list.d.ts +55 -0
- package/dist/cjs/checkpointer/actions/list.js +70 -0
- package/dist/cjs/checkpointer/actions/put-writes.d.ts +49 -0
- package/dist/cjs/checkpointer/actions/put-writes.js +21 -0
- package/dist/cjs/checkpointer/actions/put.d.ts +95 -0
- package/dist/cjs/checkpointer/actions/put.js +79 -0
- package/dist/cjs/checkpointer/internal/delta-history.d.ts +124 -0
- package/dist/cjs/checkpointer/internal/delta-history.js +131 -0
- package/dist/cjs/checkpointer/internal/listing.d.ts +149 -0
- package/dist/cjs/checkpointer/internal/listing.js +104 -0
- package/dist/cjs/checkpointer/internal/parse.d.ts +298 -0
- package/dist/cjs/checkpointer/internal/parse.js +184 -0
- package/dist/cjs/checkpointer/internal/pending-writes.d.ts +314 -0
- package/dist/cjs/checkpointer/internal/pending-writes.js +241 -0
- package/dist/cjs/checkpointer/internal/read.d.ts +135 -0
- package/dist/cjs/checkpointer/internal/read.js +132 -0
- package/dist/cjs/checkpointer/internal/rows.d.ts +644 -0
- package/dist/cjs/checkpointer/internal/rows.js +356 -0
- package/dist/cjs/checkpointer/internal/setup.d.ts +47 -0
- package/dist/cjs/checkpointer/internal/setup.js +25 -0
- package/dist/cjs/checkpointer/saver.d.ts +306 -0
- package/dist/cjs/checkpointer/saver.js +56 -0
- package/dist/cjs/checkpointer/types.d.ts +51 -0
- package/dist/cjs/factory/factory.d.ts +154 -0
- package/dist/cjs/factory/factory.js +137 -0
- package/dist/{factory → cjs/factory}/types.d.ts +33 -14
- package/dist/cjs/history/actions/add-messages.d.ts +51 -0
- package/dist/cjs/history/actions/add-messages.js +17 -0
- package/dist/cjs/history/actions/clear.d.ts +52 -0
- package/dist/cjs/history/actions/clear.js +29 -0
- package/dist/cjs/history/actions/get-messages.d.ts +60 -0
- package/dist/cjs/history/actions/get-messages.js +58 -0
- package/dist/cjs/history/actions/list-sessions.d.ts +55 -0
- package/dist/cjs/history/actions/list-sessions.js +67 -0
- package/dist/cjs/history/actions/reconcile-count.d.ts +49 -0
- package/dist/cjs/history/actions/reconcile-count.js +8 -0
- package/dist/cjs/history/chat-message-history.d.ts +267 -0
- package/dist/cjs/history/chat-message-history.js +61 -0
- package/dist/cjs/history/internal/append.d.ts +244 -0
- package/dist/cjs/history/internal/append.js +267 -0
- package/dist/cjs/history/internal/message-read.d.ts +84 -0
- package/dist/cjs/history/internal/message-read.js +93 -0
- package/dist/cjs/history/internal/parse.d.ts +153 -0
- package/dist/cjs/history/internal/parse.js +113 -0
- package/dist/cjs/history/internal/rows.d.ts +196 -0
- package/dist/cjs/history/internal/rows.js +96 -0
- package/dist/cjs/history/internal/session.d.ts +350 -0
- package/dist/cjs/history/internal/session.js +296 -0
- package/dist/cjs/history/internal/setup.d.ts +64 -0
- package/dist/cjs/history/internal/setup.js +60 -0
- package/dist/cjs/history/session-adapter.d.ts +112 -0
- package/dist/cjs/history/session-adapter.js +38 -0
- package/dist/cjs/history/types.d.ts +102 -0
- package/dist/cjs/index.d.ts +53 -0
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/shared/adapter.d.ts +146 -0
- package/dist/cjs/shared/adapter.js +70 -0
- package/dist/cjs/shared/clock.d.ts +52 -0
- package/dist/cjs/shared/clock.js +14 -0
- package/dist/cjs/shared/codec/codec.d.ts +336 -0
- package/dist/cjs/shared/codec/codec.js +162 -0
- package/dist/cjs/shared/codec/compression.d.ts +66 -0
- package/dist/cjs/shared/codec/compression.js +45 -0
- package/dist/cjs/shared/codec/json-serde.d.ts +80 -0
- package/dist/cjs/shared/codec/json-serde.js +58 -0
- package/dist/{shared → cjs/shared}/codec/s3/client-types.d.ts +22 -2
- package/dist/{shared → cjs/shared}/codec/s3/client-types.js +0 -1
- package/dist/cjs/shared/codec/s3/client.d.ts +63 -0
- package/dist/cjs/shared/codec/s3/client.js +78 -0
- package/dist/cjs/shared/codec/s3/config.d.ts +260 -0
- package/dist/cjs/shared/codec/s3/config.js +92 -0
- package/dist/cjs/shared/codec/s3/lifecycle.d.ts +220 -0
- package/dist/cjs/shared/codec/s3/lifecycle.js +223 -0
- package/dist/cjs/shared/codec/s3/offloader.d.ts +428 -0
- package/dist/cjs/shared/codec/s3/offloader.js +289 -0
- package/dist/cjs/shared/concurrency.d.ts +43 -0
- package/dist/{shared → cjs/shared}/concurrency.js +10 -9
- package/dist/cjs/shared/dynamodb/abort.d.ts +47 -0
- package/dist/cjs/shared/dynamodb/abort.js +16 -0
- package/dist/cjs/shared/dynamodb/batch-write.d.ts +86 -0
- package/dist/cjs/shared/dynamodb/batch-write.js +79 -0
- package/dist/cjs/shared/dynamodb/cancellation.d.ts +124 -0
- package/dist/cjs/shared/dynamodb/cancellation.js +37 -0
- package/dist/cjs/shared/dynamodb/client.d.ts +177 -0
- package/dist/{shared → cjs/shared}/dynamodb/client.js +12 -14
- package/dist/cjs/shared/dynamodb/idempotent-write.d.ts +596 -0
- package/dist/cjs/shared/dynamodb/idempotent-write.js +173 -0
- package/dist/cjs/shared/dynamodb/paginate.d.ts +111 -0
- package/dist/cjs/shared/dynamodb/paginate.js +90 -0
- package/dist/cjs/shared/dynamodb/partition-delete.d.ts +204 -0
- package/dist/cjs/shared/dynamodb/partition-delete.js +177 -0
- package/dist/cjs/shared/dynamodb/recency-index.d.ts +243 -0
- package/dist/cjs/shared/dynamodb/recency-index.js +146 -0
- package/dist/cjs/shared/dynamodb/retry.d.ts +317 -0
- package/dist/cjs/shared/dynamodb/retry.js +193 -0
- package/dist/cjs/shared/dynamodb/row-size.d.ts +33 -0
- package/dist/cjs/shared/dynamodb/row-size.js +30 -0
- package/dist/cjs/shared/dynamodb/table-schema.d.ts +199 -0
- package/dist/cjs/shared/dynamodb/table-schema.js +52 -0
- package/dist/cjs/shared/errors/base-error.d.ts +231 -0
- package/dist/cjs/shared/errors/base-error.js +73 -0
- package/dist/cjs/shared/errors/boundary.d.ts +86 -0
- package/dist/cjs/shared/errors/boundary.js +61 -0
- package/dist/cjs/shared/errors/classify.d.ts +206 -0
- package/dist/cjs/shared/errors/classify.js +232 -0
- package/dist/cjs/shared/errors/error-code.d.ts +95 -0
- package/dist/{shared → cjs/shared}/errors/error-code.js +12 -2
- package/dist/cjs/shared/errors/errors.d.ts +233 -0
- package/dist/cjs/shared/errors/errors.js +123 -0
- package/dist/cjs/shared/logging/logger.d.ts +80 -0
- package/dist/cjs/shared/logging/logger.js +30 -0
- package/dist/cjs/shared/logging/redaction.d.ts +123 -0
- package/dist/cjs/shared/logging/redaction.js +145 -0
- package/dist/cjs/shared/logging/secret-patterns.d.ts +227 -0
- package/dist/cjs/shared/logging/secret-patterns.js +93 -0
- package/dist/cjs/shared/logging/truncate.d.ts +197 -0
- package/dist/cjs/shared/logging/truncate.js +31 -0
- package/dist/cjs/shared/options.d.ts +100 -0
- package/dist/cjs/shared/ulid.d.ts +80 -0
- package/dist/{shared → cjs/shared}/ulid.js +7 -21
- package/dist/cjs/shared/validation/collaborators.d.ts +160 -0
- package/dist/cjs/shared/validation/collaborators.js +79 -0
- package/dist/cjs/shared/validation/option-shape.d.ts +91 -0
- package/dist/cjs/shared/validation/option-shape.js +31 -0
- package/dist/cjs/shared/validation/options.d.ts +145 -0
- package/dist/cjs/shared/validation/options.js +166 -0
- package/dist/cjs/shared/validation/primitives.d.ts +292 -0
- package/dist/cjs/shared/validation/primitives.js +114 -0
- package/dist/cjs/shared/validation/ttl.d.ts +94 -0
- package/dist/cjs/shared/validation/ttl.js +52 -0
- package/dist/cjs/store/actions/list-namespaces.d.ts +79 -0
- package/dist/cjs/store/actions/list-namespaces.js +92 -0
- package/dist/cjs/store/actions/put.d.ts +43 -0
- package/dist/cjs/store/actions/put.js +49 -0
- package/dist/cjs/store/actions/reconcile-vector-index.d.ts +38 -0
- package/dist/cjs/store/actions/reconcile-vector-index.js +13 -0
- package/dist/cjs/store/actions/search.d.ts +38 -0
- package/dist/cjs/store/actions/search.js +26 -0
- package/dist/cjs/store/internal/batch-plan.d.ts +56 -0
- package/dist/cjs/store/internal/batch-plan.js +32 -0
- package/dist/cjs/store/internal/filter.d.ts +43 -0
- package/dist/cjs/store/internal/filter.js +64 -0
- package/dist/cjs/store/internal/get-item.d.ts +77 -0
- package/dist/cjs/store/internal/get-item.js +58 -0
- package/dist/cjs/store/internal/item-write.d.ts +270 -0
- package/dist/cjs/store/internal/item-write.js +181 -0
- package/dist/cjs/store/internal/parse.d.ts +230 -0
- package/dist/cjs/store/internal/parse.js +180 -0
- package/dist/cjs/store/internal/rows.d.ts +359 -0
- package/dist/cjs/store/internal/rows.js +166 -0
- package/dist/cjs/store/internal/semantic-search.d.ts +168 -0
- package/dist/{store/internal/text-path.js → cjs/store/internal/semantic-search.js} +92 -28
- package/dist/cjs/store/internal/setup.d.ts +96 -0
- package/dist/cjs/store/internal/setup.js +103 -0
- package/dist/cjs/store/internal/table-search.d.ts +100 -0
- package/dist/cjs/store/internal/table-search.js +123 -0
- package/dist/cjs/store/internal/vector-index.d.ts +258 -0
- package/dist/cjs/store/internal/vector-index.js +269 -0
- package/dist/cjs/store/store.d.ts +329 -0
- package/dist/cjs/store/store.js +97 -0
- package/dist/cjs/store/types.d.ts +111 -0
- package/dist/cjs/store/vector-backend.d.ts +104 -0
- package/dist/cjs/store/vector-backend.js +4 -0
- package/dist/esm/backfill/backfill.d.ts +171 -0
- package/dist/esm/backfill/backfill.js +170 -0
- package/dist/esm/checkpointer/actions/delete-thread.d.ts +50 -0
- package/dist/esm/checkpointer/actions/delete-thread.js +23 -0
- package/dist/esm/checkpointer/actions/get-tuple.d.ts +36 -0
- package/dist/esm/checkpointer/actions/get-tuple.js +19 -0
- package/dist/esm/checkpointer/actions/list.d.ts +55 -0
- package/dist/esm/checkpointer/actions/list.js +67 -0
- package/dist/esm/checkpointer/actions/put-writes.d.ts +49 -0
- package/dist/esm/checkpointer/actions/put-writes.js +18 -0
- package/dist/esm/checkpointer/actions/put.d.ts +95 -0
- package/dist/esm/checkpointer/actions/put.js +75 -0
- package/dist/esm/checkpointer/internal/delta-history.d.ts +124 -0
- package/dist/esm/checkpointer/internal/delta-history.js +126 -0
- package/dist/esm/checkpointer/internal/listing.d.ts +149 -0
- package/dist/esm/checkpointer/internal/listing.js +95 -0
- package/dist/esm/checkpointer/internal/parse.d.ts +298 -0
- package/dist/esm/checkpointer/internal/parse.js +169 -0
- package/dist/esm/checkpointer/internal/pending-writes.d.ts +314 -0
- package/dist/esm/checkpointer/internal/pending-writes.js +229 -0
- package/dist/esm/checkpointer/internal/read.d.ts +135 -0
- package/dist/esm/checkpointer/internal/read.js +125 -0
- package/dist/esm/checkpointer/internal/rows.d.ts +644 -0
- package/dist/esm/checkpointer/internal/rows.js +323 -0
- package/dist/esm/checkpointer/internal/setup.d.ts +47 -0
- package/dist/esm/checkpointer/internal/setup.js +21 -0
- package/dist/esm/checkpointer/saver.d.ts +306 -0
- package/dist/esm/checkpointer/saver.js +52 -0
- package/dist/esm/checkpointer/types.d.ts +51 -0
- package/dist/esm/checkpointer/types.js +1 -0
- package/dist/esm/factory/factory.d.ts +154 -0
- package/dist/esm/factory/factory.js +133 -0
- package/dist/esm/factory/types.d.ts +76 -0
- package/dist/esm/factory/types.js +1 -0
- package/dist/esm/history/actions/add-messages.d.ts +51 -0
- package/dist/esm/history/actions/add-messages.js +14 -0
- package/dist/esm/history/actions/clear.d.ts +52 -0
- package/dist/esm/history/actions/clear.js +26 -0
- package/dist/esm/history/actions/get-messages.d.ts +60 -0
- package/dist/esm/history/actions/get-messages.js +55 -0
- package/dist/esm/history/actions/list-sessions.d.ts +55 -0
- package/dist/esm/history/actions/list-sessions.js +64 -0
- package/dist/esm/history/actions/reconcile-count.d.ts +49 -0
- package/dist/esm/history/actions/reconcile-count.js +5 -0
- package/dist/esm/history/chat-message-history.d.ts +267 -0
- package/dist/esm/history/chat-message-history.js +57 -0
- package/dist/esm/history/internal/append.d.ts +244 -0
- package/dist/esm/history/internal/append.js +259 -0
- package/dist/esm/history/internal/message-read.d.ts +84 -0
- package/dist/esm/history/internal/message-read.js +89 -0
- package/dist/esm/history/internal/parse.d.ts +153 -0
- package/dist/esm/history/internal/parse.js +105 -0
- package/dist/esm/history/internal/rows.d.ts +196 -0
- package/dist/esm/history/internal/rows.js +83 -0
- package/dist/esm/history/internal/session.d.ts +350 -0
- package/dist/esm/history/internal/session.js +285 -0
- package/dist/esm/history/internal/setup.d.ts +64 -0
- package/dist/esm/history/internal/setup.js +56 -0
- package/dist/esm/history/session-adapter.d.ts +112 -0
- package/dist/esm/history/session-adapter.js +34 -0
- package/dist/esm/history/types.d.ts +102 -0
- package/dist/esm/history/types.js +1 -0
- package/dist/esm/index.d.ts +53 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/shared/adapter.d.ts +146 -0
- package/dist/esm/shared/adapter.js +65 -0
- package/dist/esm/shared/clock.d.ts +52 -0
- package/dist/esm/shared/clock.js +9 -0
- package/dist/esm/shared/codec/codec.d.ts +336 -0
- package/dist/esm/shared/codec/codec.js +150 -0
- package/dist/esm/shared/codec/compression.d.ts +66 -0
- package/dist/esm/shared/codec/compression.js +40 -0
- package/dist/esm/shared/codec/json-serde.d.ts +80 -0
- package/dist/esm/shared/codec/json-serde.js +54 -0
- package/dist/esm/shared/codec/s3/client-types.d.ts +54 -0
- package/dist/esm/shared/codec/s3/client-types.js +3 -0
- package/dist/esm/shared/codec/s3/client.d.ts +63 -0
- package/dist/esm/shared/codec/s3/client.js +40 -0
- package/dist/esm/shared/codec/s3/config.d.ts +260 -0
- package/dist/esm/shared/codec/s3/config.js +79 -0
- package/dist/esm/shared/codec/s3/lifecycle.d.ts +220 -0
- package/dist/esm/shared/codec/s3/lifecycle.js +214 -0
- package/dist/esm/shared/codec/s3/offloader.d.ts +428 -0
- package/dist/esm/shared/codec/s3/offloader.js +278 -0
- package/dist/esm/shared/concurrency.d.ts +43 -0
- package/dist/esm/shared/concurrency.js +27 -0
- package/dist/esm/shared/dynamodb/abort.d.ts +47 -0
- package/dist/esm/shared/dynamodb/abort.js +12 -0
- package/dist/esm/shared/dynamodb/batch-write.d.ts +86 -0
- package/dist/esm/shared/dynamodb/batch-write.js +74 -0
- package/dist/esm/shared/dynamodb/cancellation.d.ts +124 -0
- package/dist/esm/shared/dynamodb/cancellation.js +30 -0
- package/dist/esm/shared/dynamodb/client.d.ts +177 -0
- package/dist/esm/shared/dynamodb/client.js +35 -0
- package/dist/esm/shared/dynamodb/idempotent-write.d.ts +596 -0
- package/dist/esm/shared/dynamodb/idempotent-write.js +153 -0
- package/dist/esm/shared/dynamodb/paginate.d.ts +111 -0
- package/dist/esm/shared/dynamodb/paginate.js +84 -0
- package/dist/esm/shared/dynamodb/partition-delete.d.ts +204 -0
- package/dist/esm/shared/dynamodb/partition-delete.js +171 -0
- package/dist/esm/shared/dynamodb/recency-index.d.ts +243 -0
- package/dist/esm/shared/dynamodb/recency-index.js +136 -0
- package/dist/esm/shared/dynamodb/retry.d.ts +317 -0
- package/dist/esm/shared/dynamodb/retry.js +180 -0
- package/dist/esm/shared/dynamodb/row-size.d.ts +33 -0
- package/dist/esm/shared/dynamodb/row-size.js +26 -0
- package/dist/esm/shared/dynamodb/table-schema.d.ts +199 -0
- package/dist/esm/shared/dynamodb/table-schema.js +43 -0
- package/dist/esm/shared/errors/base-error.d.ts +231 -0
- package/dist/esm/shared/errors/base-error.js +64 -0
- package/dist/esm/shared/errors/boundary.d.ts +86 -0
- package/dist/esm/shared/errors/boundary.js +54 -0
- package/dist/esm/shared/errors/classify.d.ts +206 -0
- package/dist/esm/shared/errors/classify.js +220 -0
- package/dist/esm/shared/errors/error-code.d.ts +95 -0
- package/dist/esm/shared/errors/error-code.js +24 -0
- package/dist/esm/shared/errors/errors.d.ts +233 -0
- package/dist/esm/shared/errors/errors.js +110 -0
- package/dist/esm/shared/logging/logger.d.ts +80 -0
- package/dist/esm/shared/logging/logger.js +25 -0
- package/dist/esm/shared/logging/redaction.d.ts +123 -0
- package/dist/esm/shared/logging/redaction.js +140 -0
- package/dist/esm/shared/logging/secret-patterns.d.ts +227 -0
- package/dist/esm/shared/logging/secret-patterns.js +83 -0
- package/dist/esm/shared/logging/truncate.d.ts +197 -0
- package/dist/esm/shared/logging/truncate.js +25 -0
- package/dist/esm/shared/options.d.ts +100 -0
- package/dist/esm/shared/options.js +1 -0
- package/dist/esm/shared/ulid.d.ts +80 -0
- package/dist/esm/shared/ulid.js +77 -0
- package/dist/esm/shared/validation/collaborators.d.ts +160 -0
- package/dist/esm/shared/validation/collaborators.js +70 -0
- package/dist/esm/shared/validation/option-shape.d.ts +91 -0
- package/dist/esm/shared/validation/option-shape.js +24 -0
- package/dist/esm/shared/validation/options.d.ts +145 -0
- package/dist/esm/shared/validation/options.js +156 -0
- package/dist/esm/shared/validation/primitives.d.ts +292 -0
- package/dist/esm/shared/validation/primitives.js +100 -0
- package/dist/esm/shared/validation/ttl.d.ts +94 -0
- package/dist/esm/shared/validation/ttl.js +46 -0
- package/dist/esm/store/actions/list-namespaces.d.ts +79 -0
- package/dist/esm/store/actions/list-namespaces.js +86 -0
- package/dist/esm/store/actions/put.d.ts +43 -0
- package/dist/esm/store/actions/put.js +46 -0
- package/dist/esm/store/actions/reconcile-vector-index.d.ts +38 -0
- package/dist/esm/store/actions/reconcile-vector-index.js +10 -0
- package/dist/esm/store/actions/search.d.ts +38 -0
- package/dist/esm/store/actions/search.js +23 -0
- package/dist/esm/store/internal/batch-plan.d.ts +56 -0
- package/dist/esm/store/internal/batch-plan.js +28 -0
- package/dist/esm/store/internal/filter.d.ts +43 -0
- package/dist/esm/store/internal/filter.js +60 -0
- package/dist/esm/store/internal/get-item.d.ts +77 -0
- package/dist/esm/store/internal/get-item.js +54 -0
- package/dist/esm/store/internal/item-write.d.ts +270 -0
- package/dist/esm/store/internal/item-write.js +173 -0
- package/dist/esm/store/internal/parse.d.ts +230 -0
- package/dist/esm/store/internal/parse.js +169 -0
- package/dist/esm/store/internal/rows.d.ts +359 -0
- package/dist/esm/store/internal/rows.js +147 -0
- package/dist/esm/store/internal/semantic-search.d.ts +168 -0
- package/dist/esm/store/internal/semantic-search.js +200 -0
- package/dist/esm/store/internal/setup.d.ts +96 -0
- package/dist/esm/store/internal/setup.js +98 -0
- package/dist/esm/store/internal/table-search.d.ts +100 -0
- package/dist/esm/store/internal/table-search.js +119 -0
- package/dist/esm/store/internal/vector-index.d.ts +258 -0
- package/dist/esm/store/internal/vector-index.js +256 -0
- package/dist/esm/store/store.d.ts +329 -0
- package/dist/esm/store/store.js +93 -0
- package/dist/esm/store/types.d.ts +111 -0
- package/dist/esm/store/types.js +1 -0
- package/dist/esm/store/vector-backend.d.ts +104 -0
- package/dist/esm/store/vector-backend.js +1 -0
- package/package.json +68 -46
- package/dist/checkpointer/actions/delete-thread.d.ts +0 -10
- package/dist/checkpointer/actions/delete-thread.js +0 -38
- package/dist/checkpointer/actions/get-tuple.d.ts +0 -11
- package/dist/checkpointer/actions/get-tuple.js +0 -25
- package/dist/checkpointer/actions/list.d.ts +0 -20
- package/dist/checkpointer/actions/list.js +0 -113
- package/dist/checkpointer/actions/put-writes.d.ts +0 -15
- package/dist/checkpointer/actions/put-writes.js +0 -62
- package/dist/checkpointer/actions/put.d.ts +0 -17
- package/dist/checkpointer/actions/put.js +0 -73
- package/dist/checkpointer/internal/assemble.d.ts +0 -17
- package/dist/checkpointer/internal/assemble.js +0 -38
- package/dist/checkpointer/internal/checkpoint-write-verify.d.ts +0 -24
- package/dist/checkpointer/internal/checkpoint-write-verify.js +0 -67
- package/dist/checkpointer/internal/configurable.d.ts +0 -12
- package/dist/checkpointer/internal/configurable.js +0 -24
- package/dist/checkpointer/internal/fetch.d.ts +0 -19
- package/dist/checkpointer/internal/fetch.js +0 -88
- package/dist/checkpointer/internal/filter-match.d.ts +0 -13
- package/dist/checkpointer/internal/filter-match.js +0 -15
- package/dist/checkpointer/internal/item-reader.d.ts +0 -66
- package/dist/checkpointer/internal/item-reader.js +0 -113
- package/dist/checkpointer/internal/item-writer.d.ts +0 -35
- package/dist/checkpointer/internal/item-writer.js +0 -107
- package/dist/checkpointer/internal/keys.d.ts +0 -41
- package/dist/checkpointer/internal/keys.js +0 -117
- package/dist/checkpointer/internal/list-scope.d.ts +0 -61
- package/dist/checkpointer/internal/list-scope.js +0 -108
- package/dist/checkpointer/internal/pending-sends.d.ts +0 -13
- package/dist/checkpointer/internal/pending-sends.js +0 -29
- package/dist/checkpointer/internal/query.d.ts +0 -21
- package/dist/checkpointer/internal/query.js +0 -42
- package/dist/checkpointer/internal/regular-write.d.ts +0 -28
- package/dist/checkpointer/internal/regular-write.js +0 -66
- package/dist/checkpointer/internal/setup.d.ts +0 -33
- package/dist/checkpointer/internal/setup.js +0 -38
- package/dist/checkpointer/internal/special-write-cas.d.ts +0 -29
- package/dist/checkpointer/internal/special-write-cas.js +0 -104
- package/dist/checkpointer/internal/special-write-cleanup.d.ts +0 -23
- package/dist/checkpointer/internal/special-write-cleanup.js +0 -50
- package/dist/checkpointer/internal/special-write-verify.d.ts +0 -53
- package/dist/checkpointer/internal/special-write-verify.js +0 -80
- package/dist/checkpointer/internal/stored-channels.d.ts +0 -31
- package/dist/checkpointer/internal/stored-channels.js +0 -70
- package/dist/checkpointer/internal/validation.d.ts +0 -18
- package/dist/checkpointer/internal/validation.js +0 -40
- package/dist/checkpointer/internal/write-guard.d.ts +0 -20
- package/dist/checkpointer/internal/write-guard.js +0 -48
- package/dist/checkpointer/internal/write-index.d.ts +0 -36
- package/dist/checkpointer/internal/write-index.js +0 -41
- package/dist/checkpointer/saver.d.ts +0 -70
- package/dist/checkpointer/saver.js +0 -105
- package/dist/checkpointer/types.d.ts +0 -58
- package/dist/factory/factory.d.ts +0 -40
- package/dist/factory/factory.js +0 -87
- package/dist/history/actions/add-messages.d.ts +0 -15
- package/dist/history/actions/add-messages.js +0 -77
- package/dist/history/actions/clear.d.ts +0 -10
- package/dist/history/actions/clear.js +0 -34
- package/dist/history/actions/get-messages.d.ts +0 -17
- package/dist/history/actions/get-messages.js +0 -79
- package/dist/history/actions/list-sessions.d.ts +0 -13
- package/dist/history/actions/list-sessions.js +0 -53
- package/dist/history/actions/reconcile-count.d.ts +0 -12
- package/dist/history/actions/reconcile-count.js +0 -64
- package/dist/history/chat-message-history.d.ts +0 -73
- package/dist/history/chat-message-history.js +0 -111
- package/dist/history/internal/append-saga.d.ts +0 -25
- package/dist/history/internal/append-saga.js +0 -79
- package/dist/history/internal/compensation.d.ts +0 -25
- package/dist/history/internal/compensation.js +0 -92
- package/dist/history/internal/item-mapper.d.ts +0 -9
- package/dist/history/internal/item-mapper.js +0 -27
- package/dist/history/internal/keys.d.ts +0 -16
- package/dist/history/internal/keys.js +0 -48
- package/dist/history/internal/message-chunker.d.ts +0 -13
- package/dist/history/internal/message-chunker.js +0 -67
- package/dist/history/internal/message-transaction.d.ts +0 -25
- package/dist/history/internal/message-transaction.js +0 -61
- package/dist/history/internal/message-window.d.ts +0 -17
- package/dist/history/internal/message-window.js +0 -49
- package/dist/history/internal/query.d.ts +0 -23
- package/dist/history/internal/query.js +0 -39
- package/dist/history/internal/session-count.d.ts +0 -47
- package/dist/history/internal/session-count.js +0 -115
- package/dist/history/internal/session-title.d.ts +0 -19
- package/dist/history/internal/session-title.js +0 -43
- package/dist/history/internal/session-update.d.ts +0 -27
- package/dist/history/internal/session-update.js +0 -69
- package/dist/history/internal/setup.d.ts +0 -31
- package/dist/history/internal/setup.js +0 -43
- package/dist/history/internal/title-generator.d.ts +0 -12
- package/dist/history/internal/title-generator.js +0 -41
- package/dist/history/internal/ttl-anchor.d.ts +0 -24
- package/dist/history/internal/ttl-anchor.js +0 -38
- package/dist/history/internal/validation.d.ts +0 -25
- package/dist/history/internal/validation.js +0 -53
- package/dist/history/session-adapter.d.ts +0 -29
- package/dist/history/session-adapter.js +0 -35
- package/dist/history/types.d.ts +0 -69
- package/dist/index.d.ts +0 -29
- package/dist/index.js +0 -32
- package/dist/shared/clock.d.ts +0 -8
- package/dist/shared/clock.js +0 -16
- package/dist/shared/codec/codec.d.ts +0 -53
- package/dist/shared/codec/codec.js +0 -66
- package/dist/shared/codec/compression.d.ts +0 -24
- package/dist/shared/codec/compression.js +0 -48
- package/dist/shared/codec/descriptor-keys.d.ts +0 -12
- package/dist/shared/codec/descriptor-keys.js +0 -14
- package/dist/shared/codec/encode.d.ts +0 -13
- package/dist/shared/codec/encode.js +0 -43
- package/dist/shared/codec/json-serde.d.ts +0 -7
- package/dist/shared/codec/json-serde.js +0 -17
- package/dist/shared/codec/payload-loss.d.ts +0 -12
- package/dist/shared/codec/payload-loss.js +0 -38
- package/dist/shared/codec/s3/adapter-config.d.ts +0 -13
- package/dist/shared/codec/s3/adapter-config.js +0 -22
- package/dist/shared/codec/s3/bounded-body.d.ts +0 -14
- package/dist/shared/codec/s3/bounded-body.js +0 -47
- package/dist/shared/codec/s3/client.d.ts +0 -18
- package/dist/shared/codec/s3/client.js +0 -46
- package/dist/shared/codec/s3/config.d.ts +0 -51
- package/dist/shared/codec/s3/config.js +0 -58
- package/dist/shared/codec/s3/delete.d.ts +0 -7
- package/dist/shared/codec/s3/delete.js +0 -28
- package/dist/shared/codec/s3/key-scope.d.ts +0 -23
- package/dist/shared/codec/s3/key-scope.js +0 -44
- package/dist/shared/codec/s3/lifecycle.d.ts +0 -14
- package/dist/shared/codec/s3/lifecycle.js +0 -63
- package/dist/shared/codec/s3/offloader.d.ts +0 -44
- package/dist/shared/codec/s3/offloader.js +0 -118
- package/dist/shared/codec/s3/orphans.d.ts +0 -23
- package/dist/shared/codec/s3/orphans.js +0 -71
- package/dist/shared/codec/s3/read-write.d.ts +0 -18
- package/dist/shared/codec/s3/read-write.js +0 -51
- package/dist/shared/codec/s3/retry.d.ts +0 -5
- package/dist/shared/codec/s3/retry.js +0 -22
- package/dist/shared/concurrency.d.ts +0 -6
- package/dist/shared/constants.d.ts +0 -112
- package/dist/shared/constants.js +0 -115
- package/dist/shared/dynamodb/abort.d.ts +0 -9
- package/dist/shared/dynamodb/abort.js +0 -27
- package/dist/shared/dynamodb/backoff.d.ts +0 -15
- package/dist/shared/dynamodb/backoff.js +0 -48
- package/dist/shared/dynamodb/batch-write.d.ts +0 -22
- package/dist/shared/dynamodb/batch-write.js +0 -53
- package/dist/shared/dynamodb/cancellation.d.ts +0 -6
- package/dist/shared/dynamodb/cancellation.js +0 -7
- package/dist/shared/dynamodb/client.d.ts +0 -28
- package/dist/shared/dynamodb/conditional-put.d.ts +0 -67
- package/dist/shared/dynamodb/conditional-put.js +0 -76
- package/dist/shared/dynamodb/drain-unprocessed.d.ts +0 -21
- package/dist/shared/dynamodb/drain-unprocessed.js +0 -43
- package/dist/shared/dynamodb/expiry.d.ts +0 -16
- package/dist/shared/dynamodb/expiry.js +0 -29
- package/dist/shared/dynamodb/paginate-core.d.ts +0 -24
- package/dist/shared/dynamodb/paginate-core.js +0 -82
- package/dist/shared/dynamodb/paginate.d.ts +0 -14
- package/dist/shared/dynamodb/paginate.js +0 -19
- package/dist/shared/dynamodb/partition-delete.d.ts +0 -39
- package/dist/shared/dynamodb/partition-delete.js +0 -71
- package/dist/shared/dynamodb/retry-classifier.d.ts +0 -17
- package/dist/shared/dynamodb/retry-classifier.js +0 -118
- package/dist/shared/dynamodb/retry-policy.d.ts +0 -26
- package/dist/shared/dynamodb/retry-policy.js +0 -22
- package/dist/shared/dynamodb/retry.d.ts +0 -31
- package/dist/shared/dynamodb/retry.js +0 -57
- package/dist/shared/dynamodb/scan.d.ts +0 -14
- package/dist/shared/dynamodb/scan.js +0 -19
- package/dist/shared/dynamodb/types.d.ts +0 -23
- package/dist/shared/errors/base-error.d.ts +0 -30
- package/dist/shared/errors/base-error.js +0 -27
- package/dist/shared/errors/boundary.d.ts +0 -18
- package/dist/shared/errors/boundary.js +0 -46
- package/dist/shared/errors/error-code.d.ts +0 -13
- package/dist/shared/errors/errors.d.ts +0 -68
- package/dist/shared/errors/errors.js +0 -114
- package/dist/shared/errors/upstream-error.d.ts +0 -16
- package/dist/shared/errors/upstream-error.js +0 -27
- package/dist/shared/errors/wrap-error.d.ts +0 -7
- package/dist/shared/errors/wrap-error.js +0 -15
- package/dist/shared/logging/logger.d.ts +0 -18
- package/dist/shared/logging/logger.js +0 -15
- package/dist/shared/logging/redaction-walk.d.ts +0 -23
- package/dist/shared/logging/redaction-walk.js +0 -112
- package/dist/shared/logging/redaction.d.ts +0 -39
- package/dist/shared/logging/redaction.js +0 -75
- package/dist/shared/logging/secret-patterns.d.ts +0 -92
- package/dist/shared/logging/secret-patterns.js +0 -133
- package/dist/shared/options.d.ts +0 -37
- package/dist/shared/ulid.d.ts +0 -23
- package/dist/shared/validation/options.d.ts +0 -8
- package/dist/shared/validation/options.js +0 -90
- package/dist/shared/validation/primitives.d.ts +0 -29
- package/dist/shared/validation/primitives.js +0 -82
- package/dist/shared/validation/ttl.d.ts +0 -28
- package/dist/shared/validation/ttl.js +0 -52
- package/dist/store/actions/get.d.ts +0 -13
- package/dist/store/actions/get.js +0 -73
- package/dist/store/actions/list-namespaces.d.ts +0 -8
- package/dist/store/actions/list-namespaces.js +0 -59
- package/dist/store/actions/put.d.ts +0 -10
- package/dist/store/actions/put.js +0 -96
- package/dist/store/actions/reconcile-vector-index.d.ts +0 -18
- package/dist/store/actions/reconcile-vector-index.js +0 -26
- package/dist/store/actions/search.d.ts +0 -9
- package/dist/store/actions/search.js +0 -34
- package/dist/store/internal/backend-search.d.ts +0 -4
- package/dist/store/internal/backend-search.js +0 -74
- package/dist/store/internal/batch-plan.d.ts +0 -11
- package/dist/store/internal/batch-plan.js +0 -52
- package/dist/store/internal/candidates.d.ts +0 -23
- package/dist/store/internal/candidates.js +0 -94
- package/dist/store/internal/filter.d.ts +0 -9
- package/dist/store/internal/filter.js +0 -85
- package/dist/store/internal/index-reconcile.d.ts +0 -21
- package/dist/store/internal/index-reconcile.js +0 -118
- package/dist/store/internal/index-sync.d.ts +0 -10
- package/dist/store/internal/index-sync.js +0 -25
- package/dist/store/internal/item-mapper.d.ts +0 -27
- package/dist/store/internal/item-mapper.js +0 -61
- package/dist/store/internal/keys.d.ts +0 -17
- package/dist/store/internal/keys.js +0 -41
- package/dist/store/internal/namespace-match.d.ts +0 -11
- package/dist/store/internal/namespace-match.js +0 -40
- package/dist/store/internal/option-validation.d.ts +0 -13
- package/dist/store/internal/option-validation.js +0 -77
- package/dist/store/internal/overwrite-swap.d.ts +0 -32
- package/dist/store/internal/overwrite-swap.js +0 -68
- package/dist/store/internal/persist.d.ts +0 -28
- package/dist/store/internal/persist.js +0 -64
- package/dist/store/internal/query.d.ts +0 -11
- package/dist/store/internal/query.js +0 -48
- package/dist/store/internal/ranker.d.ts +0 -18
- package/dist/store/internal/ranker.js +0 -39
- package/dist/store/internal/read-existing.d.ts +0 -23
- package/dist/store/internal/read-existing.js +0 -41
- package/dist/store/internal/score-direction.d.ts +0 -31
- package/dist/store/internal/score-direction.js +0 -38
- package/dist/store/internal/search-filter.d.ts +0 -3
- package/dist/store/internal/search-filter.js +0 -10
- package/dist/store/internal/semantic-search.d.ts +0 -34
- package/dist/store/internal/semantic-search.js +0 -87
- package/dist/store/internal/setup.d.ts +0 -36
- package/dist/store/internal/setup.js +0 -40
- package/dist/store/internal/text-path.d.ts +0 -17
- package/dist/store/internal/validation.d.ts +0 -18
- package/dist/store/internal/validation.js +0 -51
- package/dist/store/internal/write-verify.d.ts +0 -42
- package/dist/store/internal/write-verify.js +0 -71
- package/dist/store/store.d.ts +0 -61
- package/dist/store/store.js +0 -107
- package/dist/store/types.d.ts +0 -50
- package/dist/store/types.js +0 -2
- package/dist/store/vector-backend.d.ts +0 -43
- package/dist/store/vector-backend.js +0 -2
- /package/dist/{checkpointer → cjs/checkpointer}/types.js +0 -0
- /package/dist/{factory → cjs/factory}/types.js +0 -0
- /package/dist/{history → cjs/history}/types.js +0 -0
- /package/dist/{shared → cjs/shared}/options.js +0 -0
- /package/dist/{shared/dynamodb → cjs/store}/types.js +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides what it takes for a checkpoint to land exactly once.
|
|
3
|
+
*
|
|
4
|
+
* The META and PAYLOAD rows go out as one transaction under a request token
|
|
5
|
+
* drawn once, and a failure with S3 offload configured is read back before
|
|
6
|
+
* any upload is released, so a lost acknowledgement reports success and only a
|
|
7
|
+
* confirmed non-commit cleans up (record 6). Every channel value is stored
|
|
8
|
+
* whatever `newVersions` says (record 10). A caller gets back the config that
|
|
9
|
+
* addresses the stored checkpoint and none of this.
|
|
10
|
+
*/
|
|
11
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
12
|
+
import type { Checkpoint, CheckpointMetadata } from '@langchain/langgraph-checkpoint';
|
|
13
|
+
import { type WriteVerdict } from '../../shared/dynamodb/idempotent-write.js';
|
|
14
|
+
import { type CheckpointMetaRow, type CheckpointPayloadRow } from '../internal/rows.js';
|
|
15
|
+
import type { CheckpointerContext } from '../internal/setup.js';
|
|
16
|
+
/**
|
|
17
|
+
* Persist a checkpoint and its metadata as a transactional pair of META and
|
|
18
|
+
* PAYLOAD rows, returning the config that addresses the stored checkpoint. The
|
|
19
|
+
* incoming `checkpoint_id` (if any) becomes the new checkpoint's parent.
|
|
20
|
+
*
|
|
21
|
+
* **Every channel value the checkpoint carries is stored.** The saver's
|
|
22
|
+
* `put` accepts a `newVersions` argument because `BaseCheckpointSaver.put`
|
|
23
|
+
* declares it (`@langchain/langgraph-checkpoint@1.1.5` `dist/base.d.ts:68`)
|
|
24
|
+
* and does not hand it on: narrowing the stored values to the ones it names, and
|
|
25
|
+
* carrying the rest forward from the parent, made a put whose `newVersions` is
|
|
26
|
+
* `{}` write no values at all. LangGraph passes `{}` when forking a checkpoint
|
|
27
|
+
* and when writing an empty-checkpoint update (`@langchain/langgraph@1.4.13`
|
|
28
|
+
* `dist/pregel/index.js:668` and `:613`), so that put silently dropped user
|
|
29
|
+
* state. The reference saver does not narrow either: `MemorySaver.put` takes
|
|
30
|
+
* three parameters and stores the whole checkpoint (`dist/memory.js:206`).
|
|
31
|
+
*
|
|
32
|
+
* Accepts: `config` — its `checkpoint_id`, when present, becomes the new
|
|
33
|
+
* checkpoint's parent. `checkpoint.id` — validated as the sort-key segment it
|
|
34
|
+
* becomes. `metadata` — stored beside it, on the light row a listing reads.
|
|
35
|
+
* `config.signal` — cancels the writes' retries; checked before anything is
|
|
36
|
+
* encoded.
|
|
37
|
+
*
|
|
38
|
+
* Returns: the config addressing the stored checkpoint, which is what the
|
|
39
|
+
* caller passes back to continue the thread.
|
|
40
|
+
*
|
|
41
|
+
* Throws: `VALIDATION` naming `config`, `configurable` or `signal` for a
|
|
42
|
+
* config of the wrong shape, `thread_id`, `checkpoint_ns`, `checkpoint_id` or
|
|
43
|
+
* `thread_ts` for a malformed identifier, `checkpoint` for a `null` or
|
|
44
|
+
* `undefined` checkpoint, `checkpoint_id` for a malformed `checkpoint.id`,
|
|
45
|
+
* `payload` for a payload too large to store inline without `s3`, or, once
|
|
46
|
+
* offloaded, larger than `s3.maxDownloadBytes`; `s3Key` for an offloaded
|
|
47
|
+
* object's key over S3's cap; `S3_OFFLOAD_FAILED`; whatever the transaction
|
|
48
|
+
* throws once the outcome is established.
|
|
49
|
+
*
|
|
50
|
+
* Guarantees: both rows land or neither does — they are one transaction, so a
|
|
51
|
+
* META row never names a payload that is not there. That transaction goes out
|
|
52
|
+
* under a client request token drawn once, with the request it travels on, so
|
|
53
|
+
* a retry that follows a lost acknowledgement is discarded by the service
|
|
54
|
+
* rather than applied a second time. Writing the same `checkpoint.id` again
|
|
55
|
+
* replaces both, which is what a retry and a repair tool both need; the objects
|
|
56
|
+
* the replaced rows named are not deleted by the put, and are left to the
|
|
57
|
+
* lifecycle rule. A payload the serde refuses is refused before any write and
|
|
58
|
+
* releases whatever the same call had already uploaded, so an encode that fails
|
|
59
|
+
* halfway leaves nothing behind either. On failure with S3 offload configured
|
|
60
|
+
* the row carrying an offloaded descriptor is read back before any upload is
|
|
61
|
+
* deleted (see {@link verifyCheckpointLanded}): a transaction that committed
|
|
62
|
+
* and lost its response is reported as success, a confirmed non-commit cleans
|
|
63
|
+
* up the objects this call uploaded, and an unverifiable outcome — a failed
|
|
64
|
+
* read, or a failure after which DynamoDB may still apply the write, because
|
|
65
|
+
* an attempt of its budget got no answer, was answered
|
|
66
|
+
* `TransactionInProgressException` or failed with a server error (5xx) —
|
|
67
|
+
* leaks them rather than risk stranding a live row, and a put
|
|
68
|
+
* whose signal fired before the transaction was sent sends nothing and
|
|
69
|
+
* releases its uploads. Each put uploads under an object id of its own, so no
|
|
70
|
+
* row another put commits names this call's uploads.
|
|
71
|
+
*/
|
|
72
|
+
export declare function putCheckpoint(context: CheckpointerContext, config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata): Promise<RunnableConfig>;
|
|
73
|
+
/**
|
|
74
|
+
* Read one of the two rows back after the META+PAYLOAD transaction failed and
|
|
75
|
+
* report what that failure actually did — never assuming it did nothing.
|
|
76
|
+
*
|
|
77
|
+
* Accepts: `meta` and `payload` — the two rows the failed transaction carried.
|
|
78
|
+
* Whichever of them has something offloaded is the one read back; a fully
|
|
79
|
+
* inline write has no object at stake and spends no read.
|
|
80
|
+
*
|
|
81
|
+
* Returns: the verdict. See {@link WriteVerdict} for what each answer licenses
|
|
82
|
+
* the caller to do. `'landed'` when the row holds this attempt's key,
|
|
83
|
+
* `'not-landed'` when it holds another or none, `'unverified'` when the read
|
|
84
|
+
* failed.
|
|
85
|
+
*
|
|
86
|
+
* Throws: nothing — a failed read is the `'unverified'` answer.
|
|
87
|
+
*
|
|
88
|
+
* Guarantees: both descriptors' keys end in the object id this put drew, which
|
|
89
|
+
* no other put uses. The row holds this attempt's key only if this put's
|
|
90
|
+
* transaction committed, and the other row commits with it, so one read decides
|
|
91
|
+
* the landing. A row holding any other key was committed by another put, whose
|
|
92
|
+
* rows name only that put's objects, so a `'not-landed'` answer leaves both of
|
|
93
|
+
* this put's uploads named by no row.
|
|
94
|
+
*/
|
|
95
|
+
export declare function verifyCheckpointLanded(context: CheckpointerContext, meta: CheckpointMetaRow, payload: CheckpointPayloadRow): Promise<WriteVerdict>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { collectS3Keys } from '../../shared/codec/codec.js';
|
|
2
|
+
import { cleanUpS3Orphans } from '../../shared/codec/s3/offloader.js';
|
|
3
|
+
import { abortErrorFrom } from '../../shared/dynamodb/abort.js';
|
|
4
|
+
import { offloadedKey, settledVerdict, transactIdempotently, verifyRow, } from '../../shared/dynamodb/idempotent-write.js';
|
|
5
|
+
import { rowKeyOf } from '../../shared/dynamodb/table-schema.js';
|
|
6
|
+
import { calculateTtlTimestamp } from '../../shared/validation/ttl.js';
|
|
7
|
+
import { parsePutRequest } from '../internal/parse.js';
|
|
8
|
+
import { buildCheckpointRows, } from '../internal/rows.js';
|
|
9
|
+
export async function putCheckpoint(context, config, checkpoint, metadata) {
|
|
10
|
+
const request = parsePutRequest(config, checkpoint, metadata);
|
|
11
|
+
const { threadId, checkpointNs, checkpointId } = request.address;
|
|
12
|
+
const ttlTimestamp = context.ttl ? calculateTtlTimestamp(context.ttl) : undefined;
|
|
13
|
+
const { meta, payload } = await buildCheckpointRows(context, request, ttlTimestamp);
|
|
14
|
+
const stored = {
|
|
15
|
+
configurable: { thread_id: threadId, checkpoint_ns: checkpointNs, checkpoint_id: checkpointId },
|
|
16
|
+
};
|
|
17
|
+
if (request.signal?.aborted) {
|
|
18
|
+
await releaseOwnUploads(context, meta, payload);
|
|
19
|
+
throw abortErrorFrom(request.signal);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
await transactIdempotently(context, [
|
|
23
|
+
{ Put: { TableName: context.tableName, Item: meta } },
|
|
24
|
+
{ Put: { TableName: context.tableName, Item: payload } },
|
|
25
|
+
], { signal: request.signal });
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (!context.offloader)
|
|
29
|
+
throw error;
|
|
30
|
+
const verdict = settledVerdict(await verifyCheckpointLanded(context, meta, payload), error);
|
|
31
|
+
if (verdict === 'landed') {
|
|
32
|
+
context.logger.debug('put: transaction committed although its response was lost', {
|
|
33
|
+
threadId,
|
|
34
|
+
checkpointId,
|
|
35
|
+
});
|
|
36
|
+
return stored;
|
|
37
|
+
}
|
|
38
|
+
if (verdict === 'not-landed')
|
|
39
|
+
await releaseOwnUploads(context, meta, payload);
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
return stored;
|
|
43
|
+
}
|
|
44
|
+
async function releaseOwnUploads(context, meta, payload) {
|
|
45
|
+
if (!context.offloader)
|
|
46
|
+
return;
|
|
47
|
+
await cleanUpS3Orphans(context.offloader, {
|
|
48
|
+
keys: collectS3Keys([meta.metadata, payload.checkpoint]),
|
|
49
|
+
operation: 'put',
|
|
50
|
+
logger: context.logger,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function chooseProbe(meta, payload) {
|
|
54
|
+
const metaKey = offloadedKey(meta.metadata);
|
|
55
|
+
if (metaKey !== undefined) {
|
|
56
|
+
return {
|
|
57
|
+
key: rowKeyOf(meta),
|
|
58
|
+
kind: 'descriptor',
|
|
59
|
+
attribute: 'metadata',
|
|
60
|
+
expected: metaKey,
|
|
61
|
+
descriptors: ['metadata'],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
key: rowKeyOf(payload),
|
|
66
|
+
kind: 'descriptor',
|
|
67
|
+
attribute: 'checkpoint',
|
|
68
|
+
expected: offloadedKey(payload.checkpoint),
|
|
69
|
+
descriptors: ['checkpoint'],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export async function verifyCheckpointLanded(context, meta, payload) {
|
|
73
|
+
const { verdict } = await verifyRow(context, chooseProbe(meta, payload));
|
|
74
|
+
return verdict;
|
|
75
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides how a delta channel's history is rebuilt, and what a hole in it means.
|
|
3
|
+
*
|
|
4
|
+
* A delta channel stores a full value only every `snapshotFrequency` updates,
|
|
5
|
+
* so its value at a checkpoint is its last snapshot plus the writes since,
|
|
6
|
+
* collected by walking parent pointers. The walk, the order the writes are
|
|
7
|
+
* collected in, and what a pointer the walk cannot follow means — a hole to
|
|
8
|
+
* report, whether its row is still stored past its ttl or already swept, and
|
|
9
|
+
* never the history's true start, which is a checkpoint with no pointer at all
|
|
10
|
+
* — are decided here.
|
|
11
|
+
*/
|
|
12
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
13
|
+
import type { CheckpointTuple, DeltaChannelHistory } from '@langchain/langgraph-checkpoint';
|
|
14
|
+
import { DynamoDBLangGraphError } from '../../shared/errors/base-error.js';
|
|
15
|
+
import type { CheckpointerContext } from './setup.js';
|
|
16
|
+
/**
|
|
17
|
+
* Walk a checkpoint's ancestors for the delta channels named, accumulating
|
|
18
|
+
* their writes oldest-first and the nearest stored value of each.
|
|
19
|
+
*
|
|
20
|
+
* Same contract and same result as the inherited implementation
|
|
21
|
+
* (`@langchain/langgraph-checkpoint@1.1.5` `dist/base.js:78`), with one
|
|
22
|
+
* difference that is the reason for overriding it: where the inherited walk
|
|
23
|
+
* meets an ancestor it cannot read it simply stops (`if (tup === void 0)
|
|
24
|
+
* break`), reports no seed, and the consumer rebuilds the channel from its
|
|
25
|
+
* initial value (`@langchain/langgraph@1.4.13` `dist/channels/delta.js:65`).
|
|
26
|
+
* That is silent state loss, and this package can produce it: a ttl is computed
|
|
27
|
+
* per put, so a long-running thread expires its own older checkpoints while the
|
|
28
|
+
* newer ones live on.
|
|
29
|
+
*
|
|
30
|
+
* Accepts: `channels` — the delta channels to rebuild; none returns nothing and
|
|
31
|
+
* reads nothing. `getTuple` — the saver's own, so the walk sees exactly what a
|
|
32
|
+
* reader would. `config` — the checkpoint to walk back from. `config.signal` —
|
|
33
|
+
* cancels the whole walk: it is re-attached to each ancestor cursor
|
|
34
|
+
* ({@link cursorFor}), because the pointer a tuple carries is a bare address.
|
|
35
|
+
*
|
|
36
|
+
* Returns: per channel, its on-path writes oldest-first and the nearest stored
|
|
37
|
+
* value found. A channel whose value was never stored gets none, which is the
|
|
38
|
+
* consumer's cue to start from its initial value — correctly, because there is
|
|
39
|
+
* nothing to lose.
|
|
40
|
+
*
|
|
41
|
+
* Throws: `ANCESTOR_EXPIRED` when a channel still needs an ancestor the walk
|
|
42
|
+
* cannot read — its row stored but past its ttl, or already removed by the
|
|
43
|
+
* sweep — or when the chain points back to a checkpoint already read
|
|
44
|
+
* ({@link ancestorExpired}). A checkpoint with no parent pointer ends the walk
|
|
45
|
+
* quietly — that is a thread's true start. `ABORTED` when the signal fires,
|
|
46
|
+
* at whichever hop it fires on, and in preference to a diagnosis of the stop:
|
|
47
|
+
* a walk cancelled just as it reached an expired ancestor reports the cancel,
|
|
48
|
+
* since the caller stopped waiting for the answer either way.
|
|
49
|
+
*
|
|
50
|
+
* Guarantees: the walk stops at the first ancestor that answers for every
|
|
51
|
+
* channel, so a deep thread costs reads only as far back as the nearest
|
|
52
|
+
* snapshot.
|
|
53
|
+
*/
|
|
54
|
+
export declare function deltaChannelHistory(context: CheckpointerContext, getTuple: (config: RunnableConfig) => Promise<CheckpointTuple | undefined>, config: RunnableConfig, channels: string[]): Promise<Record<string, DeltaChannelHistory>>;
|
|
55
|
+
/** Where an ancestor walk stopped, and what kind of hole in the thread it found there. */
|
|
56
|
+
export interface WalkStop {
|
|
57
|
+
threadId: string;
|
|
58
|
+
checkpointId: string;
|
|
59
|
+
/**
|
|
60
|
+
* `'expired'` — the row is still stored, past its `ttl`; `'gone'` — no row at
|
|
61
|
+
* all, the sweep having removed it (or something else having deleted it);
|
|
62
|
+
* `'revisited'` — the chain pointed back to a checkpoint already read.
|
|
63
|
+
*/
|
|
64
|
+
stop: 'expired' | 'gone' | 'revisited';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Read the META row an ancestor walk could not follow, **ignoring expiry**, to
|
|
68
|
+
* tell "this checkpoint is still stored but has expired" apart from "it is
|
|
69
|
+
* gone" — the sweep has removed it, which every expired row becomes within
|
|
70
|
+
* days. Both are holes; the read decides only what the error says.
|
|
71
|
+
*
|
|
72
|
+
* Every other read in this package hides an expired row, which is the right
|
|
73
|
+
* rule for a reader asking for state: checkpoint META, store and history rows
|
|
74
|
+
* by their own ttl, and a checkpoint's PAYLOAD and pending-WRITE rows by their
|
|
75
|
+
* checkpoint's META row, which is the only one checked (a pre-v4 checkpoint's
|
|
76
|
+
* migration is the exception: it reads its parent's pending writes under the
|
|
77
|
+
* child's META row). Here the row is wanted expired or not.
|
|
78
|
+
*
|
|
79
|
+
* Accepts: `config` — the parent pointer a walk stopped at. `config.signal` —
|
|
80
|
+
* cancels the read, and is read before it is sent. The walk re-attaches the
|
|
81
|
+
* caller's signal to every cursor, so the probe takes its cancel from the same
|
|
82
|
+
* place every other reader in this package takes it, rather than from a
|
|
83
|
+
* parameter of its own.
|
|
84
|
+
*
|
|
85
|
+
* Returns: whether that checkpoint is still stored and expired, or gone, or
|
|
86
|
+
* `undefined` when the config names no thread or no checkpoint — such a pointer
|
|
87
|
+
* addresses nothing that could have expired, so the walk has simply run out of
|
|
88
|
+
* chain.
|
|
89
|
+
*
|
|
90
|
+
* Throws: whatever the read throws after retries; `ABORTED` when the signal
|
|
91
|
+
* has already fired, which is answered in preference to the expiry this read
|
|
92
|
+
* exists to diagnose — a caller who cancelled is owed its own stop, and is no
|
|
93
|
+
* longer waiting to be told why the walk ended.
|
|
94
|
+
*
|
|
95
|
+
* Guarantees: the read ignores the ttl, deliberately. Every other read in this
|
|
96
|
+
* package hides an expired row by the rule above — META, store and history rows
|
|
97
|
+
* by their own ttl, PAYLOAD and WRITE rows by their checkpoint's META row, with
|
|
98
|
+
* the pre-v4 migration the exception — which is right for a reader asking for
|
|
99
|
+
* state; here an expired row is the evidence the error names.
|
|
100
|
+
*/
|
|
101
|
+
export declare function probeAncestor(context: CheckpointerContext, config: RunnableConfig): Promise<WalkStop | undefined>;
|
|
102
|
+
/**
|
|
103
|
+
* The error a read raises when a delta channel's history has a hole in it.
|
|
104
|
+
*
|
|
105
|
+
* Accepts: `stop` — the ancestor the walk could not follow, and why. `channels`
|
|
106
|
+
* — the delta channels that still needed it, named in the message so the
|
|
107
|
+
* operator knows what was lost.
|
|
108
|
+
*
|
|
109
|
+
* Returns: the error, coded `ANCESTOR_EXPIRED` and carrying the thread and
|
|
110
|
+
* checkpoint. The message bounds all three: after the first hop the walk's
|
|
111
|
+
* cursor is a row's own `parentConfig`, so the identifiers it names come off a
|
|
112
|
+
* row, and `channels` is checked for being an array of strings and for nothing
|
|
113
|
+
* else — neither how many nor how long. `context` carries both identifiers
|
|
114
|
+
* whole, which is what a caller branches on.
|
|
115
|
+
*
|
|
116
|
+
* Throws: nothing — it builds the error, the caller throws it.
|
|
117
|
+
*
|
|
118
|
+
* Guarantees: returning the partial history instead would hand the caller a
|
|
119
|
+
* channel rebuilt from its initial value plus whatever writes survived — a
|
|
120
|
+
* shorter message list, say, with nothing to say that anything is missing. The
|
|
121
|
+
* reference contract has no way to express "incomplete", so refusing the read
|
|
122
|
+
* is the only honest answer.
|
|
123
|
+
*/
|
|
124
|
+
export declare function ancestorExpired(stop: WalkStop, channels: string[]): DynamoDBLangGraphError;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { nowSeconds } from '../../shared/clock.js';
|
|
2
|
+
import { withDynamoDBRetry, retryFor } from '../../shared/dynamodb/retry.js';
|
|
3
|
+
import { isExpiredRow } from '../../shared/dynamodb/table-schema.js';
|
|
4
|
+
import { DynamoDBLangGraphError } from '../../shared/errors/base-error.js';
|
|
5
|
+
import { ErrorCode } from '../../shared/errors/error-code.js';
|
|
6
|
+
import { truncateForLog, truncateLabelsForLog } from '../../shared/logging/truncate.js';
|
|
7
|
+
import { metaRowKey } from './rows.js';
|
|
8
|
+
function startWalk(channels) {
|
|
9
|
+
const writes = {};
|
|
10
|
+
for (const channel of channels)
|
|
11
|
+
writes[channel] = [];
|
|
12
|
+
return { remaining: new Set(channels), writes, seeds: {}, visited: new Set() };
|
|
13
|
+
}
|
|
14
|
+
function collectWrites(tuple, walk) {
|
|
15
|
+
const perChannel = {};
|
|
16
|
+
for (const write of tuple.pendingWrites ?? []) {
|
|
17
|
+
const channel = write[1];
|
|
18
|
+
if (walk.remaining.has(channel))
|
|
19
|
+
(perChannel[channel] ??= []).push(write);
|
|
20
|
+
}
|
|
21
|
+
for (const channel of Object.keys(perChannel)) {
|
|
22
|
+
const block = perChannel[channel];
|
|
23
|
+
for (let i = block.length - 1; i >= 0; i -= 1)
|
|
24
|
+
walk.writes[channel].push(block[i]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function takeSeeds(tuple, walk) {
|
|
28
|
+
for (const channel of [...walk.remaining]) {
|
|
29
|
+
if (Object.prototype.hasOwnProperty.call(tuple.checkpoint.channel_values, channel)) {
|
|
30
|
+
walk.seeds[channel] = tuple.checkpoint.channel_values[channel];
|
|
31
|
+
walk.remaining.delete(channel);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function cursorFor(parent, signal) {
|
|
36
|
+
if (parent === undefined || signal === undefined)
|
|
37
|
+
return parent;
|
|
38
|
+
return { ...parent, signal };
|
|
39
|
+
}
|
|
40
|
+
async function walkAncestors(context, getTuple, walk, from) {
|
|
41
|
+
let cursor = cursorFor(from.start, from.signal);
|
|
42
|
+
while (cursor !== undefined && walk.remaining.size > 0) {
|
|
43
|
+
const revisit = revisitOf(cursor, walk);
|
|
44
|
+
if (revisit !== undefined)
|
|
45
|
+
throw ancestorExpired(revisit, [...walk.remaining]);
|
|
46
|
+
const tuple = await getTuple(cursor);
|
|
47
|
+
if (tuple === undefined) {
|
|
48
|
+
const stop = await probeAncestor(context, cursor);
|
|
49
|
+
if (stop === undefined)
|
|
50
|
+
return;
|
|
51
|
+
throw ancestorExpired(stop, [...walk.remaining]);
|
|
52
|
+
}
|
|
53
|
+
collectWrites(tuple, walk);
|
|
54
|
+
takeSeeds(tuple, walk);
|
|
55
|
+
cursor = cursorFor(tuple.parentConfig, from.signal);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function revisitOf(cursor, walk) {
|
|
59
|
+
const ids = cursor.configurable;
|
|
60
|
+
const threadId = ids?.thread_id;
|
|
61
|
+
const checkpointId = ids?.checkpoint_id;
|
|
62
|
+
if (typeof threadId !== 'string' || typeof checkpointId !== 'string')
|
|
63
|
+
return undefined;
|
|
64
|
+
const key = `${ids?.checkpoint_ns ?? ''}#${checkpointId}`;
|
|
65
|
+
if (walk.visited.has(key))
|
|
66
|
+
return { threadId, checkpointId, stop: 'revisited' };
|
|
67
|
+
walk.visited.add(key);
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
function historyOf(walk, channel) {
|
|
71
|
+
const writes = walk.writes[channel].slice().reverse();
|
|
72
|
+
return Object.prototype.hasOwnProperty.call(walk.seeds, channel)
|
|
73
|
+
? { writes, seed: walk.seeds[channel] }
|
|
74
|
+
: { writes };
|
|
75
|
+
}
|
|
76
|
+
export async function deltaChannelHistory(context, getTuple, config, channels) {
|
|
77
|
+
if (channels.length === 0)
|
|
78
|
+
return {};
|
|
79
|
+
const walk = startWalk(channels);
|
|
80
|
+
const target = await getTuple(config);
|
|
81
|
+
await walkAncestors(context, getTuple, walk, {
|
|
82
|
+
start: target?.parentConfig,
|
|
83
|
+
signal: config.signal,
|
|
84
|
+
});
|
|
85
|
+
const result = {};
|
|
86
|
+
for (const channel of channels)
|
|
87
|
+
result[channel] = historyOf(walk, channel);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
export async function probeAncestor(context, config) {
|
|
91
|
+
const ids = config.configurable;
|
|
92
|
+
const threadId = ids?.thread_id;
|
|
93
|
+
const checkpointId = ids?.checkpoint_id;
|
|
94
|
+
if (typeof threadId !== 'string' || typeof checkpointId !== 'string')
|
|
95
|
+
return undefined;
|
|
96
|
+
const checkpointNs = ids?.checkpoint_ns ?? '';
|
|
97
|
+
const result = await withDynamoDBRetry((request) => context.client.get({
|
|
98
|
+
TableName: context.tableName,
|
|
99
|
+
Key: metaRowKey({ threadId, checkpointNs, checkpointId }),
|
|
100
|
+
ConsistentRead: true,
|
|
101
|
+
}, request), retryFor(context, config.signal));
|
|
102
|
+
const row = result.Item;
|
|
103
|
+
return {
|
|
104
|
+
threadId,
|
|
105
|
+
checkpointId,
|
|
106
|
+
stop: row !== undefined && isExpiredRow(row, nowSeconds()) ? 'expired' : 'gone',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function ancestorExpired(stop, channels) {
|
|
110
|
+
const named = truncateLabelsForLog(channels)
|
|
111
|
+
.map((channel) => `"${channel}"`)
|
|
112
|
+
.join(', ');
|
|
113
|
+
const what = stop.stop === 'expired'
|
|
114
|
+
? 'has expired'
|
|
115
|
+
: stop.stop === 'gone'
|
|
116
|
+
? 'is gone (expired and removed by DynamoDB, or deleted)'
|
|
117
|
+
: 'is named as its own ancestor, so the chain never reaches a stored value';
|
|
118
|
+
return new DynamoDBLangGraphError(`checkpoint "${truncateForLog(stop.checkpointId)}" of thread ` +
|
|
119
|
+
`"${truncateForLog(stop.threadId)}" ${what}, but later ` +
|
|
120
|
+
`checkpoints still need it to reconstruct ${named}. ` +
|
|
121
|
+
'A delta channel writes a full snapshot only every `snapshotFrequency` updates and leaves ' +
|
|
122
|
+
'itself out of the checkpoints in between, so its value is rebuilt from an earlier ' +
|
|
123
|
+
'ancestor — which a per-checkpoint ttl expires while its descendants live on. Lower ' +
|
|
124
|
+
'`snapshotFrequency` (1 makes every checkpoint self-contained), or do not configure a ttl ' +
|
|
125
|
+
'on threads that use delta channels.', ErrorCode.ANCESTOR_EXPIRED, { threadId: stop.threadId, checkpointId: stop.checkpointId });
|
|
126
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides where a listing's META rows come from and which of them pass its filters.
|
|
3
|
+
*
|
|
4
|
+
* A listing that names a thread is a partition query; one that does not is a
|
|
5
|
+
* recency-index read when the table carries the index and a table scan when it
|
|
6
|
+
* does not (record 8). Whichever it is, rows are narrowed to this adapter's own,
|
|
7
|
+
* and a row passes only when its key fields match the scope and, when the caller
|
|
8
|
+
* gave a filter, its decoded metadata equals the filter clause for clause.
|
|
9
|
+
*/
|
|
10
|
+
import type { QueryCommandInput, ScanCommandInput } from '@aws-sdk/lib-dynamodb';
|
|
11
|
+
import type { CheckpointMetadata } from '@langchain/langgraph-checkpoint';
|
|
12
|
+
import type { AttributeMap } from '../../shared/dynamodb/client.js';
|
|
13
|
+
import type { FilterValue, ListScope, ThreadId } from './parse.js';
|
|
14
|
+
import { type CheckpointMetaRow } from './rows.js';
|
|
15
|
+
import type { CheckpointerContext } from './setup.js';
|
|
16
|
+
/**
|
|
17
|
+
* The META query for a scope that names a thread.
|
|
18
|
+
*
|
|
19
|
+
* Accepts: `scope.filter` — its presence means rows may be dropped client-side,
|
|
20
|
+
* so only an unfiltered list passes the caller's `limit` through as the page
|
|
21
|
+
* size; passing it through a filtered read would cut the page short of matches
|
|
22
|
+
* that exist. `scope.checkpointNs` — absent spans every namespace of the
|
|
23
|
+
* thread. `scope.before` — bounds the key range only with an explicit
|
|
24
|
+
* namespace, since across namespaces ids do not share one order; it is applied
|
|
25
|
+
* in-process otherwise.
|
|
26
|
+
*
|
|
27
|
+
* Returns: the Query input.
|
|
28
|
+
*
|
|
29
|
+
* Throws: nothing.
|
|
30
|
+
*/
|
|
31
|
+
export declare function listQuery(context: CheckpointerContext, scope: ListScope & {
|
|
32
|
+
threadId: ThreadId;
|
|
33
|
+
}): QueryCommandInput;
|
|
34
|
+
/**
|
|
35
|
+
* The table `Scan` a thread-less `list()` runs when no recency index is
|
|
36
|
+
* configured.
|
|
37
|
+
*
|
|
38
|
+
* Accepts: `scope.checkpointNs` — narrows the filter to one namespace when the
|
|
39
|
+
* caller gave one.
|
|
40
|
+
*
|
|
41
|
+
* Returns: the Scan input, filtered to this adapter's META rows. It is what the
|
|
42
|
+
* reference savers do for a config without a thread, and on DynamoDB it costs a
|
|
43
|
+
* read of the whole table — cross-tenant by construction, which the public
|
|
44
|
+
* documentation says outright.
|
|
45
|
+
*
|
|
46
|
+
* Throws: nothing.
|
|
47
|
+
*/
|
|
48
|
+
export declare function listScan(context: CheckpointerContext, scope: ListScope): ScanCommandInput;
|
|
49
|
+
/**
|
|
50
|
+
* Whether `meta` passes the key-level filters.
|
|
51
|
+
*
|
|
52
|
+
* Accepts: any narrowed META row, from a query or a scan.
|
|
53
|
+
*
|
|
54
|
+
* Returns: whether it is strictly older than `before` and — on a table scan,
|
|
55
|
+
* where the key condition cannot narrow them — in the requested namespace and,
|
|
56
|
+
* when one is given, the requested checkpoint. Applied to query results too,
|
|
57
|
+
* which is redundant there and free: one rule, one place.
|
|
58
|
+
*
|
|
59
|
+
* "Older" is {@link compareSortKeys}, because on the query path the same bound
|
|
60
|
+
* is already a `BETWEEN` on the composed sort key, which DynamoDB evaluates in
|
|
61
|
+
* UTF-8 byte order. JavaScript's `<` orders UTF-16 code units instead, and at
|
|
62
|
+
* an astral id the two disagree, so `<` here would turn the redundant pass
|
|
63
|
+
* into a second, different filter that drops rows the query rightly returned.
|
|
64
|
+
* Every id in one namespace shares its sort key's prefix, so comparing the id
|
|
65
|
+
* is comparing the sort key.
|
|
66
|
+
*
|
|
67
|
+
* Throws: nothing.
|
|
68
|
+
*/
|
|
69
|
+
export declare function passesKeyFilters(meta: CheckpointMetaRow, scope: ListScope): boolean;
|
|
70
|
+
/** Outcome of the metadata filter: rejected, or accepted with any metadata decoded on the way. */
|
|
71
|
+
export type MetadataVerdict = {
|
|
72
|
+
pass: false;
|
|
73
|
+
} | {
|
|
74
|
+
pass: true;
|
|
75
|
+
metadata?: CheckpointMetadata;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Apply the optional metadata-equality filter.
|
|
79
|
+
*
|
|
80
|
+
* Accepts: `scope.filter` — absent means every row passes and nothing is
|
|
81
|
+
* decoded. `meta` — already bound to its partition, so the scope its metadata
|
|
82
|
+
* is read under is its own.
|
|
83
|
+
*
|
|
84
|
+
* Returns: whether the row passes and, when it does and a filter forced the
|
|
85
|
+
* decode, the metadata itself — handed to the tuple assembly, so a filtered
|
|
86
|
+
* list decodes (and, when offloaded, downloads) each blob once instead of
|
|
87
|
+
* twice.
|
|
88
|
+
*
|
|
89
|
+
* Throws: whatever the decode throws. Metadata that decodes to something that
|
|
90
|
+
* is not an object matches no filter clause rather than failing the listing.
|
|
91
|
+
*/
|
|
92
|
+
export declare function passesMetadataFilter(context: CheckpointerContext, meta: CheckpointMetaRow, scope: ListScope): Promise<MetadataVerdict>;
|
|
93
|
+
/**
|
|
94
|
+
* The META rows a scope covers: a partition query when the scope names a
|
|
95
|
+
* thread, and {@link threadlessRows} when it does not.
|
|
96
|
+
*
|
|
97
|
+
* Accepts: `scope` — a thread, or none, in which case every thread in the table
|
|
98
|
+
* is read, through the recency index when `indexName` is set and a scan
|
|
99
|
+
* otherwise. `now` — the instant expiry is judged against, taken once so one
|
|
100
|
+
* listing cannot disagree with itself.
|
|
101
|
+
*
|
|
102
|
+
* Returns: an async generator over the raw rows, newest-first within a
|
|
103
|
+
* namespace. Abandoning it stops the read.
|
|
104
|
+
*
|
|
105
|
+
* Throws: whatever the query or scan throws; `ABORTED` when the signal
|
|
106
|
+
* fires.
|
|
107
|
+
*
|
|
108
|
+
* Guarantees: the read is deliberately unbounded. This is a stream that never
|
|
109
|
+
* accumulates, a limit stops it early, and a row cap would turn a caller asking
|
|
110
|
+
* for a handful of rare matches over a large thread into a hard error instead
|
|
111
|
+
* of the true answer.
|
|
112
|
+
*/
|
|
113
|
+
export declare function metaRows(context: CheckpointerContext, scope: ListScope, now: number): AsyncGenerator<AttributeMap>;
|
|
114
|
+
/**
|
|
115
|
+
* Narrow a row from that stream, saying so when it is not one of ours.
|
|
116
|
+
*
|
|
117
|
+
* Accepts: `raw` — any row the stream yielded.
|
|
118
|
+
*
|
|
119
|
+
* Returns: the META item, or undefined for a row that is not this adapter's —
|
|
120
|
+
* logged at `warn`, since on a shared table a row of another adapter can share
|
|
121
|
+
* the sort-key prefix and an operator should know it is there.
|
|
122
|
+
*
|
|
123
|
+
* Throws: `FORMAT_UNSUPPORTED` for one of ours written by a newer version.
|
|
124
|
+
*
|
|
125
|
+
* Guarantees: a foreign row is skipped, never assembled. Treating one as a
|
|
126
|
+
* checkpoint would surface a tuple built from another adapter's data.
|
|
127
|
+
*/
|
|
128
|
+
export declare function parseListedRow(context: CheckpointerContext, raw: AttributeMap): CheckpointMetaRow | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Whether `metadata` satisfies every clause of `filter`.
|
|
131
|
+
*
|
|
132
|
+
* Accepts: `metadata` — a checkpoint's decoded metadata. Declared as a record,
|
|
133
|
+
* but a row can hold anything its writer stored, including `null` and a scalar;
|
|
134
|
+
* such a value has no own properties and so matches no clause.
|
|
135
|
+
* `filter` — the caller's equality clauses; `{}` matches everything.
|
|
136
|
+
*
|
|
137
|
+
* Returns: true when every key of `filter` is an **own** property of `metadata`
|
|
138
|
+
* with a deeply equal value. Equality is structural and key-order-independent
|
|
139
|
+
* for nested objects, order-significant for arrays, and type-strict — `3` does
|
|
140
|
+
* not match `'3'`.
|
|
141
|
+
*
|
|
142
|
+
* Throws: nothing. A filtered `list()` walks every row, so a single row whose
|
|
143
|
+
* metadata is not an object must not fail the listing.
|
|
144
|
+
*
|
|
145
|
+
* Guarantees: only own properties count, so a filter on `constructor` or
|
|
146
|
+
* `toString` compares against nothing rather than against the prototype's
|
|
147
|
+
* function — the same rule the store's filter applies.
|
|
148
|
+
*/
|
|
149
|
+
export declare function matchesFilter(metadata: Record<string, FilterValue>, filter: Record<string, FilterValue>): boolean;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
import { DEFAULT_READ_CONCURRENCY } from '../../shared/concurrency.js';
|
|
3
|
+
import { paginateQuery, paginateScan } from '../../shared/dynamodb/paginate.js';
|
|
4
|
+
import { DEFAULT_INDEX_SHARDS, iterateRecencyIndex } from '../../shared/dynamodb/recency-index.js';
|
|
5
|
+
import { retryFor } from '../../shared/dynamodb/retry.js';
|
|
6
|
+
import { compareSortKeys, PARTITION_KEY_ATTRIBUTE, SORT_KEY_ATTRIBUTE, withoutExpired, } from '../../shared/dynamodb/table-schema.js';
|
|
7
|
+
import { truncateForLog } from '../../shared/logging/truncate.js';
|
|
8
|
+
import { beginsWithQuery, checkpointerPartitionPrefix, metaAnyNamespacePrefix, metaSortKey, metaSortKeyPrefix, parseMetaRow, partitionKey, readMetadata, } from './rows.js';
|
|
9
|
+
export function listQuery(context, scope) {
|
|
10
|
+
const partition = partitionKey(scope.threadId);
|
|
11
|
+
const limit = scope.filter === undefined ? scope.limit : undefined;
|
|
12
|
+
if (scope.checkpointNs === undefined) {
|
|
13
|
+
return beginsWithQuery(context.tableName, partition, metaAnyNamespacePrefix(), { limit });
|
|
14
|
+
}
|
|
15
|
+
return beginsWithQuery(context.tableName, partition, metaSortKeyPrefix(scope.checkpointNs), {
|
|
16
|
+
limit,
|
|
17
|
+
beforeSortKey: scope.before === undefined ? undefined : metaSortKey(scope.checkpointNs, scope.before),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function listScan(context, scope) {
|
|
21
|
+
return {
|
|
22
|
+
TableName: context.tableName,
|
|
23
|
+
FilterExpression: 'begins_with(#pk, :pk) AND begins_with(#sk, :sk)',
|
|
24
|
+
ExpressionAttributeNames: { '#pk': PARTITION_KEY_ATTRIBUTE, '#sk': SORT_KEY_ATTRIBUTE },
|
|
25
|
+
ExpressionAttributeValues: {
|
|
26
|
+
':pk': checkpointerPartitionPrefix(),
|
|
27
|
+
':sk': scope.checkpointNs === undefined
|
|
28
|
+
? metaAnyNamespacePrefix()
|
|
29
|
+
: metaSortKeyPrefix(scope.checkpointNs),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function passesKeyFilters(meta, scope) {
|
|
34
|
+
return ((scope.before === undefined || compareSortKeys(meta.checkpointId, scope.before) < 0) &&
|
|
35
|
+
(scope.checkpointNs === undefined || meta.checkpointNs === scope.checkpointNs) &&
|
|
36
|
+
(scope.checkpointId === undefined || meta.checkpointId === scope.checkpointId));
|
|
37
|
+
}
|
|
38
|
+
export async function passesMetadataFilter(context, meta, scope) {
|
|
39
|
+
if (!scope.filter)
|
|
40
|
+
return { pass: true };
|
|
41
|
+
const metadata = await readMetadata(context, meta, meta.threadId, scope.signal);
|
|
42
|
+
return matchesFilter(metadata, scope.filter) ? { pass: true, metadata } : { pass: false };
|
|
43
|
+
}
|
|
44
|
+
function threadlessRows(context, scope, now) {
|
|
45
|
+
if (context.indexName === undefined) {
|
|
46
|
+
return paginateScan({
|
|
47
|
+
retry: retryFor(context, scope.signal),
|
|
48
|
+
signal: scope.signal,
|
|
49
|
+
client: context.client,
|
|
50
|
+
params: withoutExpired(listScan(context, scope), now),
|
|
51
|
+
maxItems: Number.POSITIVE_INFINITY,
|
|
52
|
+
maxIterations: Number.POSITIVE_INFINITY,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return iterateRecencyIndex({
|
|
56
|
+
client: context.client,
|
|
57
|
+
tableName: context.tableName,
|
|
58
|
+
indexName: context.indexName,
|
|
59
|
+
tag: 'CHKPT',
|
|
60
|
+
shards: context.indexShards ?? DEFAULT_INDEX_SHARDS,
|
|
61
|
+
concurrency: context.readConcurrency ?? DEFAULT_READ_CONCURRENCY,
|
|
62
|
+
retry: retryFor(context, scope.signal),
|
|
63
|
+
signal: scope.signal,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
export function metaRows(context, scope, now) {
|
|
67
|
+
const retry = retryFor(context, scope.signal);
|
|
68
|
+
const bounds = { maxItems: Number.POSITIVE_INFINITY, maxIterations: Number.POSITIVE_INFINITY };
|
|
69
|
+
return scope.threadId === undefined
|
|
70
|
+
? threadlessRows(context, scope, now)
|
|
71
|
+
: paginateQuery({
|
|
72
|
+
retry,
|
|
73
|
+
signal: scope.signal,
|
|
74
|
+
client: context.client,
|
|
75
|
+
params: withoutExpired(listQuery(context, { ...scope, threadId: scope.threadId }), now),
|
|
76
|
+
...bounds,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
export function parseListedRow(context, raw) {
|
|
80
|
+
const meta = parseMetaRow(raw);
|
|
81
|
+
if (!meta) {
|
|
82
|
+
context.logger.warn('list: skipped a row that is not a checkpoint meta item', {
|
|
83
|
+
sortKey: truncateForLog(raw.SK),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return meta;
|
|
87
|
+
}
|
|
88
|
+
function ownValue(metadata, key) {
|
|
89
|
+
if (metadata === null || typeof metadata !== 'object')
|
|
90
|
+
return undefined;
|
|
91
|
+
return Object.hasOwn(metadata, key) ? metadata[key] : undefined;
|
|
92
|
+
}
|
|
93
|
+
export function matchesFilter(metadata, filter) {
|
|
94
|
+
return Object.entries(filter).every(([key, value]) => isDeepStrictEqual(ownValue(metadata, key), value));
|
|
95
|
+
}
|