@farukada/aws-langgraph-dynamodb-ts 0.9.0 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1720 -154
- package/dist/backfill/backfill.d.ts +168 -0
- package/dist/backfill/backfill.js +393 -0
- package/dist/checkpointer/actions/delete-thread.d.ts +47 -6
- package/dist/checkpointer/actions/delete-thread.js +58 -21
- package/dist/checkpointer/actions/get-tuple.d.ts +29 -4
- package/dist/checkpointer/actions/get-tuple.js +44 -10
- package/dist/checkpointer/actions/list.d.ts +46 -4
- package/dist/checkpointer/actions/list.js +121 -66
- package/dist/checkpointer/actions/put-writes.d.ts +41 -9
- package/dist/checkpointer/actions/put-writes.js +62 -77
- package/dist/checkpointer/actions/put.d.ts +83 -4
- package/dist/checkpointer/actions/put.js +177 -25
- package/dist/checkpointer/internal/delta-history.d.ts +112 -0
- package/dist/checkpointer/internal/delta-history.js +252 -0
- package/dist/checkpointer/internal/listing.d.ts +149 -0
- package/dist/checkpointer/internal/listing.js +245 -0
- package/dist/checkpointer/internal/parse.d.ts +262 -0
- package/dist/checkpointer/internal/parse.js +372 -0
- package/dist/checkpointer/internal/pending-writes.d.ts +275 -0
- package/dist/checkpointer/internal/pending-writes.js +588 -0
- package/dist/checkpointer/internal/read.d.ts +130 -0
- package/dist/checkpointer/internal/read.js +264 -0
- package/dist/checkpointer/internal/rows.d.ts +571 -0
- package/dist/checkpointer/internal/rows.js +834 -0
- package/dist/checkpointer/internal/setup.d.ts +42 -19
- package/dist/checkpointer/internal/setup.js +65 -29
- package/dist/checkpointer/saver.d.ts +256 -16
- package/dist/checkpointer/saver.js +275 -29
- package/dist/checkpointer/types.d.ts +39 -39
- package/dist/checkpointer/types.js +10 -1
- package/dist/factory/factory.d.ts +134 -28
- package/dist/factory/factory.js +240 -21
- package/dist/factory/types.d.ts +76 -0
- package/dist/factory/types.js +10 -0
- package/dist/history/actions/add-messages.d.ts +31 -4
- package/dist/history/actions/add-messages.js +38 -58
- package/dist/history/actions/clear.d.ts +49 -6
- package/dist/history/actions/clear.js +66 -14
- package/dist/history/actions/get-messages.d.ts +54 -6
- package/dist/history/actions/get-messages.js +126 -43
- package/dist/history/actions/list-sessions.d.ts +52 -10
- package/dist/history/actions/list-sessions.js +139 -40
- package/dist/history/actions/reconcile-count.d.ts +42 -10
- package/dist/history/actions/reconcile-count.js +45 -45
- package/dist/history/chat-message-history.d.ts +220 -33
- package/dist/history/chat-message-history.js +240 -43
- package/dist/history/internal/append.d.ts +212 -0
- package/dist/history/internal/append.js +500 -0
- package/dist/history/internal/message-read.d.ts +84 -0
- package/dist/history/internal/message-read.js +204 -0
- package/dist/history/internal/parse.d.ts +153 -0
- package/dist/history/internal/parse.js +252 -0
- package/dist/history/internal/rows.d.ts +195 -0
- package/dist/history/internal/rows.js +250 -0
- package/dist/history/internal/session.d.ts +331 -0
- package/dist/history/internal/session.js +628 -0
- package/dist/history/internal/setup.d.ts +52 -17
- package/dist/history/internal/setup.js +92 -21
- package/dist/history/session-adapter.d.ts +102 -7
- package/dist/history/session-adapter.js +103 -9
- package/dist/history/types.d.ts +80 -29
- package/dist/history/types.js +10 -1
- package/dist/index.d.ts +42 -11
- package/dist/index.js +33 -12
- package/dist/shared/adapter.d.ts +135 -0
- package/dist/shared/adapter.js +143 -0
- package/dist/shared/clock.d.ts +51 -2
- package/dist/shared/clock.js +57 -2
- package/dist/shared/codec/codec.d.ts +288 -13
- package/dist/shared/codec/codec.js +416 -19
- package/dist/shared/codec/compression.d.ts +43 -7
- package/dist/shared/codec/compression.js +53 -13
- package/dist/shared/codec/json-serde.d.ts +76 -4
- package/dist/shared/codec/json-serde.js +181 -8
- package/dist/shared/codec/s3/client-types.d.ts +53 -0
- package/dist/shared/codec/s3/client-types.js +26 -0
- package/dist/shared/codec/s3/client.d.ts +43 -10
- package/dist/shared/codec/s3/client.js +82 -9
- package/dist/shared/codec/s3/config.d.ts +242 -11
- package/dist/shared/codec/s3/config.js +293 -11
- package/dist/shared/codec/s3/lifecycle.d.ts +164 -6
- package/dist/shared/codec/s3/lifecycle.js +335 -27
- package/dist/shared/codec/s3/offloader.d.ts +393 -18
- package/dist/shared/codec/s3/offloader.js +595 -37
- package/dist/shared/concurrency.d.ts +43 -0
- package/dist/shared/concurrency.js +78 -0
- package/dist/shared/dynamodb/abort.d.ts +47 -0
- package/dist/shared/dynamodb/abort.js +59 -0
- package/dist/shared/dynamodb/batch-write.d.ts +77 -14
- package/dist/shared/dynamodb/batch-write.js +146 -27
- package/dist/shared/dynamodb/cancellation.d.ts +121 -4
- package/dist/shared/dynamodb/cancellation.js +147 -3
- package/dist/shared/dynamodb/client.d.ts +162 -8
- package/dist/shared/dynamodb/client.js +153 -5
- package/dist/shared/dynamodb/idempotent-write.d.ts +551 -0
- package/dist/shared/dynamodb/idempotent-write.js +593 -0
- package/dist/shared/dynamodb/paginate.d.ts +105 -9
- package/dist/shared/dynamodb/paginate.js +175 -7
- package/dist/shared/dynamodb/partition-delete.d.ts +185 -14
- package/dist/shared/dynamodb/partition-delete.js +314 -44
- package/dist/shared/dynamodb/recency-index.d.ts +231 -0
- package/dist/shared/dynamodb/recency-index.js +377 -0
- package/dist/shared/dynamodb/retry.d.ts +276 -8
- package/dist/shared/dynamodb/retry.js +433 -23
- package/dist/shared/dynamodb/table-schema.d.ts +190 -0
- package/dist/shared/dynamodb/table-schema.js +209 -0
- package/dist/shared/errors/base-error.d.ts +184 -10
- package/dist/shared/errors/base-error.js +160 -14
- package/dist/shared/errors/boundary.d.ts +71 -0
- package/dist/shared/errors/boundary.js +143 -0
- package/dist/shared/errors/classify.d.ts +97 -0
- package/dist/shared/errors/classify.js +257 -0
- package/dist/shared/errors/error-code.d.ts +77 -2
- package/dist/shared/errors/error-code.js +83 -1
- package/dist/shared/errors/errors.d.ts +158 -59
- package/dist/shared/errors/errors.js +219 -92
- package/dist/shared/logging/logger.d.ts +69 -3
- package/dist/shared/logging/logger.js +97 -3
- package/dist/shared/logging/redaction.d.ts +92 -8
- package/dist/shared/logging/redaction.js +273 -17
- package/dist/shared/logging/secret-patterns.d.ts +149 -19
- package/dist/shared/logging/secret-patterns.js +188 -27
- package/dist/shared/logging/truncate.d.ts +197 -0
- package/dist/shared/logging/truncate.js +231 -0
- package/dist/shared/options.d.ts +59 -7
- package/dist/shared/options.js +9 -1
- package/dist/shared/ulid.d.ts +77 -7
- package/dist/shared/ulid.js +103 -8
- package/dist/shared/validation/collaborators.d.ts +141 -0
- package/dist/shared/validation/collaborators.js +188 -0
- package/dist/shared/validation/option-shape.d.ts +89 -0
- package/dist/shared/validation/option-shape.js +113 -0
- package/dist/shared/validation/options.d.ts +145 -0
- package/dist/shared/validation/options.js +328 -0
- package/dist/shared/validation/primitives.d.ts +288 -21
- package/dist/shared/validation/primitives.js +353 -50
- package/dist/shared/validation/ttl.d.ts +66 -10
- package/dist/shared/validation/ttl.js +113 -15
- package/dist/store/actions/list-namespaces.d.ts +76 -6
- package/dist/store/actions/list-namespaces.js +166 -24
- package/dist/store/actions/put.d.ts +33 -8
- package/dist/store/actions/put.js +53 -60
- package/dist/store/actions/reconcile-vector-index.d.ts +31 -10
- package/dist/store/actions/reconcile-vector-index.js +34 -15
- package/dist/store/actions/search.d.ts +34 -6
- package/dist/store/actions/search.js +56 -51
- package/dist/store/internal/batch-plan.d.ts +26 -0
- package/dist/store/internal/batch-plan.js +109 -0
- package/dist/store/internal/filter.d.ts +36 -3
- package/dist/store/internal/filter.js +66 -15
- package/dist/store/internal/get-item.d.ts +45 -0
- package/dist/store/internal/get-item.js +115 -0
- package/dist/store/internal/item-write.d.ts +230 -0
- package/dist/store/internal/item-write.js +463 -0
- package/dist/store/internal/parse.d.ts +225 -0
- package/dist/store/internal/parse.js +350 -0
- package/dist/store/internal/rows.d.ts +355 -0
- package/dist/store/internal/rows.js +447 -0
- package/dist/store/internal/semantic-search.d.ts +161 -6
- package/dist/store/internal/semantic-search.js +360 -18
- package/dist/store/internal/setup.d.ts +77 -20
- package/dist/store/internal/setup.js +178 -47
- package/dist/store/internal/table-search.d.ts +100 -0
- package/dist/store/internal/table-search.js +213 -0
- package/dist/store/internal/vector-index.d.ts +247 -0
- package/dist/store/internal/vector-index.js +546 -0
- package/dist/store/store.d.ts +270 -17
- package/dist/store/store.js +329 -38
- package/dist/store/types.d.ts +76 -26
- package/dist/store/types.js +13 -1
- package/dist/store/vector-backend.d.ts +64 -4
- package/dist/store/vector-backend.js +15 -1
- package/package.json +58 -36
- package/dist/checkpointer/actions/delete-thread.d.ts.map +0 -1
- package/dist/checkpointer/actions/delete-thread.js.map +0 -1
- package/dist/checkpointer/actions/get-tuple.d.ts.map +0 -1
- package/dist/checkpointer/actions/get-tuple.js.map +0 -1
- package/dist/checkpointer/actions/list.d.ts.map +0 -1
- package/dist/checkpointer/actions/list.js.map +0 -1
- package/dist/checkpointer/actions/put-writes.d.ts.map +0 -1
- package/dist/checkpointer/actions/put-writes.js.map +0 -1
- package/dist/checkpointer/actions/put.d.ts.map +0 -1
- package/dist/checkpointer/actions/put.js.map +0 -1
- package/dist/checkpointer/internal/assemble.d.ts +0 -10
- package/dist/checkpointer/internal/assemble.d.ts.map +0 -1
- package/dist/checkpointer/internal/assemble.js +0 -37
- package/dist/checkpointer/internal/assemble.js.map +0 -1
- package/dist/checkpointer/internal/configurable.d.ts +0 -13
- package/dist/checkpointer/internal/configurable.d.ts.map +0 -1
- package/dist/checkpointer/internal/configurable.js +0 -23
- package/dist/checkpointer/internal/configurable.js.map +0 -1
- package/dist/checkpointer/internal/fetch.d.ts +0 -10
- package/dist/checkpointer/internal/fetch.d.ts.map +0 -1
- package/dist/checkpointer/internal/fetch.js +0 -46
- package/dist/checkpointer/internal/fetch.js.map +0 -1
- package/dist/checkpointer/internal/filter-match.d.ts +0 -12
- package/dist/checkpointer/internal/filter-match.d.ts.map +0 -1
- package/dist/checkpointer/internal/filter-match.js +0 -14
- package/dist/checkpointer/internal/filter-match.js.map +0 -1
- package/dist/checkpointer/internal/item-reader.d.ts +0 -55
- package/dist/checkpointer/internal/item-reader.d.ts.map +0 -1
- package/dist/checkpointer/internal/item-reader.js +0 -88
- package/dist/checkpointer/internal/item-reader.js.map +0 -1
- package/dist/checkpointer/internal/item-writer.d.ts +0 -26
- package/dist/checkpointer/internal/item-writer.d.ts.map +0 -1
- package/dist/checkpointer/internal/item-writer.js +0 -92
- package/dist/checkpointer/internal/item-writer.js.map +0 -1
- package/dist/checkpointer/internal/keys.d.ts +0 -31
- package/dist/checkpointer/internal/keys.d.ts.map +0 -1
- package/dist/checkpointer/internal/keys.js +0 -87
- package/dist/checkpointer/internal/keys.js.map +0 -1
- package/dist/checkpointer/internal/query.d.ts +0 -20
- package/dist/checkpointer/internal/query.d.ts.map +0 -1
- package/dist/checkpointer/internal/query.js +0 -36
- package/dist/checkpointer/internal/query.js.map +0 -1
- package/dist/checkpointer/internal/setup.d.ts.map +0 -1
- package/dist/checkpointer/internal/setup.js.map +0 -1
- package/dist/checkpointer/internal/special-write-cas.d.ts +0 -30
- package/dist/checkpointer/internal/special-write-cas.d.ts.map +0 -1
- package/dist/checkpointer/internal/special-write-cas.js +0 -104
- package/dist/checkpointer/internal/special-write-cas.js.map +0 -1
- package/dist/checkpointer/internal/special-write-cleanup.d.ts +0 -24
- package/dist/checkpointer/internal/special-write-cleanup.d.ts.map +0 -1
- package/dist/checkpointer/internal/special-write-cleanup.js +0 -47
- package/dist/checkpointer/internal/special-write-cleanup.js.map +0 -1
- package/dist/checkpointer/internal/special-write-verify.d.ts +0 -54
- package/dist/checkpointer/internal/special-write-verify.d.ts.map +0 -1
- package/dist/checkpointer/internal/special-write-verify.js +0 -65
- package/dist/checkpointer/internal/special-write-verify.js.map +0 -1
- package/dist/checkpointer/internal/validation.d.ts +0 -13
- package/dist/checkpointer/internal/validation.d.ts.map +0 -1
- package/dist/checkpointer/internal/validation.js +0 -30
- package/dist/checkpointer/internal/validation.js.map +0 -1
- package/dist/checkpointer/internal/write-guard.d.ts +0 -13
- package/dist/checkpointer/internal/write-guard.d.ts.map +0 -1
- package/dist/checkpointer/internal/write-guard.js +0 -39
- package/dist/checkpointer/internal/write-guard.js.map +0 -1
- package/dist/checkpointer/internal/write-index.d.ts +0 -37
- package/dist/checkpointer/internal/write-index.d.ts.map +0 -1
- package/dist/checkpointer/internal/write-index.js +0 -42
- package/dist/checkpointer/internal/write-index.js.map +0 -1
- package/dist/checkpointer/saver.d.ts.map +0 -1
- package/dist/checkpointer/saver.js.map +0 -1
- package/dist/checkpointer/types.d.ts.map +0 -1
- package/dist/checkpointer/types.js.map +0 -1
- package/dist/factory/factory.d.ts.map +0 -1
- package/dist/factory/factory.js.map +0 -1
- package/dist/history/actions/add-messages.d.ts.map +0 -1
- package/dist/history/actions/add-messages.js.map +0 -1
- package/dist/history/actions/clear.d.ts.map +0 -1
- package/dist/history/actions/clear.js.map +0 -1
- package/dist/history/actions/get-messages.d.ts.map +0 -1
- package/dist/history/actions/get-messages.js.map +0 -1
- package/dist/history/actions/list-sessions.d.ts.map +0 -1
- package/dist/history/actions/list-sessions.js.map +0 -1
- package/dist/history/actions/reconcile-count.d.ts.map +0 -1
- package/dist/history/actions/reconcile-count.js.map +0 -1
- package/dist/history/chat-message-history.d.ts.map +0 -1
- package/dist/history/chat-message-history.js.map +0 -1
- package/dist/history/internal/append-saga.d.ts +0 -20
- package/dist/history/internal/append-saga.d.ts.map +0 -1
- package/dist/history/internal/append-saga.js +0 -35
- package/dist/history/internal/append-saga.js.map +0 -1
- package/dist/history/internal/compensation.d.ts +0 -21
- package/dist/history/internal/compensation.d.ts.map +0 -1
- package/dist/history/internal/compensation.js +0 -84
- package/dist/history/internal/compensation.js.map +0 -1
- package/dist/history/internal/item-mapper.d.ts +0 -12
- package/dist/history/internal/item-mapper.d.ts.map +0 -1
- package/dist/history/internal/item-mapper.js +0 -33
- package/dist/history/internal/item-mapper.js.map +0 -1
- package/dist/history/internal/keys.d.ts +0 -17
- package/dist/history/internal/keys.d.ts.map +0 -1
- package/dist/history/internal/keys.js +0 -49
- package/dist/history/internal/keys.js.map +0 -1
- package/dist/history/internal/message-chunker.d.ts +0 -14
- package/dist/history/internal/message-chunker.d.ts.map +0 -1
- package/dist/history/internal/message-chunker.js +0 -68
- package/dist/history/internal/message-chunker.js.map +0 -1
- package/dist/history/internal/message-transaction.d.ts +0 -26
- package/dist/history/internal/message-transaction.d.ts.map +0 -1
- package/dist/history/internal/message-transaction.js +0 -60
- package/dist/history/internal/message-transaction.js.map +0 -1
- package/dist/history/internal/query.d.ts +0 -10
- package/dist/history/internal/query.d.ts.map +0 -1
- package/dist/history/internal/query.js +0 -31
- package/dist/history/internal/query.js.map +0 -1
- package/dist/history/internal/session-count.d.ts +0 -41
- package/dist/history/internal/session-count.d.ts.map +0 -1
- package/dist/history/internal/session-count.js +0 -109
- package/dist/history/internal/session-count.js.map +0 -1
- package/dist/history/internal/session-title.d.ts +0 -20
- package/dist/history/internal/session-title.d.ts.map +0 -1
- package/dist/history/internal/session-title.js +0 -44
- package/dist/history/internal/session-title.js.map +0 -1
- package/dist/history/internal/session-update.d.ts +0 -28
- package/dist/history/internal/session-update.d.ts.map +0 -1
- package/dist/history/internal/session-update.js +0 -70
- package/dist/history/internal/session-update.js.map +0 -1
- package/dist/history/internal/setup.d.ts.map +0 -1
- package/dist/history/internal/setup.js.map +0 -1
- package/dist/history/internal/title-generator.d.ts +0 -13
- package/dist/history/internal/title-generator.d.ts.map +0 -1
- package/dist/history/internal/title-generator.js +0 -25
- package/dist/history/internal/title-generator.js.map +0 -1
- package/dist/history/internal/ttl-anchor.d.ts +0 -25
- package/dist/history/internal/ttl-anchor.d.ts.map +0 -1
- package/dist/history/internal/ttl-anchor.js +0 -38
- package/dist/history/internal/ttl-anchor.js.map +0 -1
- package/dist/history/internal/validation.d.ts +0 -9
- package/dist/history/internal/validation.d.ts.map +0 -1
- package/dist/history/internal/validation.js +0 -16
- package/dist/history/internal/validation.js.map +0 -1
- package/dist/history/session-adapter.d.ts.map +0 -1
- package/dist/history/session-adapter.js.map +0 -1
- package/dist/history/types.d.ts.map +0 -1
- package/dist/history/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/shared/clock.d.ts.map +0 -1
- package/dist/shared/clock.js.map +0 -1
- package/dist/shared/codec/codec.d.ts.map +0 -1
- package/dist/shared/codec/codec.js.map +0 -1
- package/dist/shared/codec/compression.d.ts.map +0 -1
- package/dist/shared/codec/compression.js.map +0 -1
- package/dist/shared/codec/descriptor-keys.d.ts +0 -4
- package/dist/shared/codec/descriptor-keys.d.ts.map +0 -1
- package/dist/shared/codec/descriptor-keys.js +0 -14
- package/dist/shared/codec/descriptor-keys.js.map +0 -1
- package/dist/shared/codec/json-serde.d.ts.map +0 -1
- package/dist/shared/codec/json-serde.js.map +0 -1
- package/dist/shared/codec/s3/client.d.ts.map +0 -1
- package/dist/shared/codec/s3/client.js.map +0 -1
- package/dist/shared/codec/s3/config.d.ts.map +0 -1
- package/dist/shared/codec/s3/config.js.map +0 -1
- package/dist/shared/codec/s3/delete.d.ts +0 -8
- package/dist/shared/codec/s3/delete.d.ts.map +0 -1
- package/dist/shared/codec/s3/delete.js +0 -29
- package/dist/shared/codec/s3/delete.js.map +0 -1
- package/dist/shared/codec/s3/lifecycle.d.ts.map +0 -1
- package/dist/shared/codec/s3/lifecycle.js.map +0 -1
- package/dist/shared/codec/s3/offloader.d.ts.map +0 -1
- package/dist/shared/codec/s3/offloader.js.map +0 -1
- package/dist/shared/codec/s3/orphans.d.ts +0 -18
- package/dist/shared/codec/s3/orphans.d.ts.map +0 -1
- package/dist/shared/codec/s3/orphans.js +0 -58
- package/dist/shared/codec/s3/orphans.js.map +0 -1
- package/dist/shared/codec/s3/read-write.d.ts +0 -14
- package/dist/shared/codec/s3/read-write.d.ts.map +0 -1
- package/dist/shared/codec/s3/read-write.js +0 -43
- package/dist/shared/codec/s3/read-write.js.map +0 -1
- package/dist/shared/codec/s3/retry.d.ts +0 -5
- package/dist/shared/codec/s3/retry.d.ts.map +0 -1
- package/dist/shared/codec/s3/retry.js +0 -25
- package/dist/shared/codec/s3/retry.js.map +0 -1
- package/dist/shared/constants.d.ts +0 -64
- package/dist/shared/constants.d.ts.map +0 -1
- package/dist/shared/constants.js +0 -67
- package/dist/shared/constants.js.map +0 -1
- package/dist/shared/dynamodb/backoff.d.ts +0 -15
- package/dist/shared/dynamodb/backoff.d.ts.map +0 -1
- package/dist/shared/dynamodb/backoff.js +0 -48
- package/dist/shared/dynamodb/backoff.js.map +0 -1
- package/dist/shared/dynamodb/batch-write.d.ts.map +0 -1
- package/dist/shared/dynamodb/batch-write.js.map +0 -1
- package/dist/shared/dynamodb/cancellation.d.ts.map +0 -1
- package/dist/shared/dynamodb/cancellation.js.map +0 -1
- package/dist/shared/dynamodb/client.d.ts.map +0 -1
- package/dist/shared/dynamodb/client.js.map +0 -1
- package/dist/shared/dynamodb/conditional-put.d.ts +0 -51
- package/dist/shared/dynamodb/conditional-put.d.ts.map +0 -1
- package/dist/shared/dynamodb/conditional-put.js +0 -59
- package/dist/shared/dynamodb/conditional-put.js.map +0 -1
- package/dist/shared/dynamodb/drain-unprocessed.d.ts +0 -19
- package/dist/shared/dynamodb/drain-unprocessed.d.ts.map +0 -1
- package/dist/shared/dynamodb/drain-unprocessed.js +0 -44
- package/dist/shared/dynamodb/drain-unprocessed.js.map +0 -1
- package/dist/shared/dynamodb/paginate-core.d.ts +0 -22
- package/dist/shared/dynamodb/paginate-core.d.ts.map +0 -1
- package/dist/shared/dynamodb/paginate-core.js +0 -52
- package/dist/shared/dynamodb/paginate-core.js.map +0 -1
- package/dist/shared/dynamodb/paginate.d.ts.map +0 -1
- package/dist/shared/dynamodb/paginate.js.map +0 -1
- package/dist/shared/dynamodb/partition-delete.d.ts.map +0 -1
- package/dist/shared/dynamodb/partition-delete.js.map +0 -1
- package/dist/shared/dynamodb/retry-classifier.d.ts +0 -9
- package/dist/shared/dynamodb/retry-classifier.d.ts.map +0 -1
- package/dist/shared/dynamodb/retry-classifier.js +0 -87
- package/dist/shared/dynamodb/retry-classifier.js.map +0 -1
- package/dist/shared/dynamodb/retry.d.ts.map +0 -1
- package/dist/shared/dynamodb/retry.js.map +0 -1
- package/dist/shared/dynamodb/scan.d.ts +0 -15
- package/dist/shared/dynamodb/scan.d.ts.map +0 -1
- package/dist/shared/dynamodb/scan.js +0 -20
- package/dist/shared/dynamodb/scan.js.map +0 -1
- package/dist/shared/dynamodb/types.d.ts +0 -24
- package/dist/shared/dynamodb/types.d.ts.map +0 -1
- package/dist/shared/dynamodb/types.js +0 -3
- package/dist/shared/dynamodb/types.js.map +0 -1
- package/dist/shared/errors/base-error.d.ts.map +0 -1
- package/dist/shared/errors/base-error.js.map +0 -1
- package/dist/shared/errors/error-code.d.ts.map +0 -1
- package/dist/shared/errors/error-code.js.map +0 -1
- package/dist/shared/errors/errors.d.ts.map +0 -1
- package/dist/shared/errors/errors.js.map +0 -1
- package/dist/shared/errors/wrap-error.d.ts +0 -16
- package/dist/shared/errors/wrap-error.d.ts.map +0 -1
- package/dist/shared/errors/wrap-error.js +0 -30
- package/dist/shared/errors/wrap-error.js.map +0 -1
- package/dist/shared/logging/logger.d.ts.map +0 -1
- package/dist/shared/logging/logger.js.map +0 -1
- package/dist/shared/logging/redaction-walk.d.ts +0 -23
- package/dist/shared/logging/redaction-walk.d.ts.map +0 -1
- package/dist/shared/logging/redaction-walk.js +0 -92
- package/dist/shared/logging/redaction-walk.js.map +0 -1
- package/dist/shared/logging/redaction.d.ts.map +0 -1
- package/dist/shared/logging/redaction.js.map +0 -1
- package/dist/shared/logging/secret-patterns.d.ts.map +0 -1
- package/dist/shared/logging/secret-patterns.js.map +0 -1
- package/dist/shared/options.d.ts.map +0 -1
- package/dist/shared/options.js.map +0 -1
- package/dist/shared/ulid.d.ts.map +0 -1
- package/dist/shared/ulid.js.map +0 -1
- package/dist/shared/validation/primitives.d.ts.map +0 -1
- package/dist/shared/validation/primitives.js.map +0 -1
- package/dist/shared/validation/ttl.d.ts.map +0 -1
- package/dist/shared/validation/ttl.js.map +0 -1
- package/dist/store/actions/get.d.ts +0 -5
- package/dist/store/actions/get.d.ts.map +0 -1
- package/dist/store/actions/get.js +0 -35
- package/dist/store/actions/get.js.map +0 -1
- package/dist/store/actions/list-namespaces.d.ts.map +0 -1
- package/dist/store/actions/list-namespaces.js.map +0 -1
- package/dist/store/actions/put.d.ts.map +0 -1
- package/dist/store/actions/put.js.map +0 -1
- package/dist/store/actions/reconcile-vector-index.d.ts.map +0 -1
- package/dist/store/actions/reconcile-vector-index.js.map +0 -1
- package/dist/store/actions/search.d.ts.map +0 -1
- package/dist/store/actions/search.js.map +0 -1
- package/dist/store/internal/backend-search.d.ts +0 -5
- package/dist/store/internal/backend-search.d.ts.map +0 -1
- package/dist/store/internal/backend-search.js +0 -68
- package/dist/store/internal/backend-search.js.map +0 -1
- package/dist/store/internal/filter.d.ts.map +0 -1
- package/dist/store/internal/filter.js.map +0 -1
- package/dist/store/internal/index-reconcile.d.ts +0 -22
- package/dist/store/internal/index-reconcile.d.ts.map +0 -1
- package/dist/store/internal/index-reconcile.js +0 -105
- package/dist/store/internal/index-reconcile.js.map +0 -1
- package/dist/store/internal/index-sync.d.ts +0 -11
- package/dist/store/internal/index-sync.d.ts.map +0 -1
- package/dist/store/internal/index-sync.js +0 -26
- package/dist/store/internal/index-sync.js.map +0 -1
- package/dist/store/internal/item-mapper.d.ts +0 -25
- package/dist/store/internal/item-mapper.d.ts.map +0 -1
- package/dist/store/internal/item-mapper.js +0 -53
- package/dist/store/internal/item-mapper.js.map +0 -1
- package/dist/store/internal/keys.d.ts +0 -18
- package/dist/store/internal/keys.d.ts.map +0 -1
- package/dist/store/internal/keys.js +0 -42
- package/dist/store/internal/keys.js.map +0 -1
- package/dist/store/internal/namespace-match.d.ts +0 -12
- package/dist/store/internal/namespace-match.d.ts.map +0 -1
- package/dist/store/internal/namespace-match.js +0 -41
- package/dist/store/internal/namespace-match.js.map +0 -1
- package/dist/store/internal/overwrite-swap.d.ts +0 -33
- package/dist/store/internal/overwrite-swap.d.ts.map +0 -1
- package/dist/store/internal/overwrite-swap.js +0 -62
- package/dist/store/internal/overwrite-swap.js.map +0 -1
- package/dist/store/internal/persist.d.ts +0 -27
- package/dist/store/internal/persist.d.ts.map +0 -1
- package/dist/store/internal/persist.js +0 -59
- package/dist/store/internal/persist.js.map +0 -1
- package/dist/store/internal/query.d.ts +0 -6
- package/dist/store/internal/query.d.ts.map +0 -1
- package/dist/store/internal/query.js +0 -32
- package/dist/store/internal/query.js.map +0 -1
- package/dist/store/internal/ranker.d.ts +0 -13
- package/dist/store/internal/ranker.d.ts.map +0 -1
- package/dist/store/internal/ranker.js +0 -31
- package/dist/store/internal/ranker.js.map +0 -1
- package/dist/store/internal/read-existing.d.ts +0 -19
- package/dist/store/internal/read-existing.d.ts.map +0 -1
- package/dist/store/internal/read-existing.js +0 -29
- package/dist/store/internal/read-existing.js.map +0 -1
- package/dist/store/internal/score-direction.d.ts +0 -32
- package/dist/store/internal/score-direction.d.ts.map +0 -1
- package/dist/store/internal/score-direction.js +0 -39
- package/dist/store/internal/score-direction.js.map +0 -1
- package/dist/store/internal/search-filter.d.ts +0 -4
- package/dist/store/internal/search-filter.d.ts.map +0 -1
- package/dist/store/internal/search-filter.js +0 -11
- package/dist/store/internal/search-filter.js.map +0 -1
- package/dist/store/internal/semantic-search.d.ts.map +0 -1
- package/dist/store/internal/semantic-search.js.map +0 -1
- package/dist/store/internal/setup.d.ts.map +0 -1
- package/dist/store/internal/setup.js.map +0 -1
- package/dist/store/internal/validation.d.ts +0 -13
- package/dist/store/internal/validation.d.ts.map +0 -1
- package/dist/store/internal/validation.js +0 -35
- package/dist/store/internal/validation.js.map +0 -1
- package/dist/store/internal/write-verify.d.ts +0 -37
- package/dist/store/internal/write-verify.d.ts.map +0 -1
- package/dist/store/internal/write-verify.js +0 -68
- package/dist/store/internal/write-verify.js.map +0 -1
- package/dist/store/store.d.ts.map +0 -1
- package/dist/store/store.js.map +0 -1
- package/dist/store/types.d.ts.map +0 -1
- package/dist/store/types.js.map +0 -1
- package/dist/store/vector-backend.d.ts.map +0 -1
- package/dist/store/vector-backend.js.map +0 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hides how a delta channel's history is rebuilt, and what a hole in it means.
|
|
4
|
+
*
|
|
5
|
+
* A delta channel stores a full value only every `snapshotFrequency` updates,
|
|
6
|
+
* so its value at a checkpoint is its last snapshot plus the writes since,
|
|
7
|
+
* collected by walking parent pointers. The walk, the order the writes are
|
|
8
|
+
* collected in, and the one read that tells an expired ancestor (a hole to
|
|
9
|
+
* report) from one that never existed (the history's true start) are decided
|
|
10
|
+
* here.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.deltaChannelHistory = deltaChannelHistory;
|
|
14
|
+
exports.probeAncestor = probeAncestor;
|
|
15
|
+
exports.ancestorExpired = ancestorExpired;
|
|
16
|
+
const clock_1 = require("../../shared/clock");
|
|
17
|
+
const retry_1 = require("../../shared/dynamodb/retry");
|
|
18
|
+
const table_schema_1 = require("../../shared/dynamodb/table-schema");
|
|
19
|
+
const base_error_1 = require("../../shared/errors/base-error");
|
|
20
|
+
const error_code_1 = require("../../shared/errors/error-code");
|
|
21
|
+
const truncate_1 = require("../../shared/logging/truncate");
|
|
22
|
+
const rows_1 = require("./rows");
|
|
23
|
+
/** An empty accumulator wanting every channel named. */
|
|
24
|
+
function startWalk(channels) {
|
|
25
|
+
const writes = {};
|
|
26
|
+
for (const channel of channels)
|
|
27
|
+
writes[channel] = [];
|
|
28
|
+
return { remaining: new Set(channels), writes, seeds: {} };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Collect one ancestor's pending writes for the channels still being walked,
|
|
32
|
+
* newest task first within the ancestor, matching the reference walk.
|
|
33
|
+
*/
|
|
34
|
+
function collectWrites(tuple, walk) {
|
|
35
|
+
const perChannel = {};
|
|
36
|
+
for (const write of tuple.pendingWrites ?? []) {
|
|
37
|
+
const channel = write[1];
|
|
38
|
+
if (walk.remaining.has(channel))
|
|
39
|
+
(perChannel[channel] ??= []).push(write);
|
|
40
|
+
}
|
|
41
|
+
for (const channel of Object.keys(perChannel)) {
|
|
42
|
+
const block = perChannel[channel];
|
|
43
|
+
block.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
|
|
44
|
+
for (let i = block.length - 1; i >= 0; i -= 1)
|
|
45
|
+
walk.writes[channel].push(block[i]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Take the seed for every channel this ancestor stores a value for, and stop
|
|
50
|
+
* walking those channels: the nearest stored value is the one that counts.
|
|
51
|
+
*/
|
|
52
|
+
function takeSeeds(tuple, walk) {
|
|
53
|
+
for (const channel of [...walk.remaining]) {
|
|
54
|
+
if (Object.prototype.hasOwnProperty.call(tuple.checkpoint.channel_values, channel)) {
|
|
55
|
+
walk.seeds[channel] = tuple.checkpoint.channel_values[channel];
|
|
56
|
+
walk.remaining.delete(channel);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The parent pointer a tuple carries, re-given the caller's `signal`.
|
|
62
|
+
*
|
|
63
|
+
* A tuple's `config` and `parentConfig` are built by `assembleTuple` as bare
|
|
64
|
+
* `{ configurable }` addresses, and they stay that way: they are handed to
|
|
65
|
+
* whoever called `getTuple`, who may keep a `parentConfig` and read from it
|
|
66
|
+
* later, long after this call's signal has fired. So the signal is re-attached
|
|
67
|
+
* here, to the cursor this walk reads with, rather than stamped onto the value
|
|
68
|
+
* the tuple publishes.
|
|
69
|
+
*
|
|
70
|
+
* The cursor is a `RunnableConfig`, and `config.signal` is how every reader in
|
|
71
|
+
* this package already takes a cancel, so nothing new carries it: the second
|
|
72
|
+
* hop is cancellable for exactly the reason the first one is.
|
|
73
|
+
*/
|
|
74
|
+
function cursorFor(parent, signal) {
|
|
75
|
+
if (parent === undefined || signal === undefined)
|
|
76
|
+
return parent;
|
|
77
|
+
return { ...parent, signal };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Follow `parentConfig` from `from.start` until every channel has a seed or the
|
|
81
|
+
* chain ends, feeding each ancestor to {@link collectWrites} and
|
|
82
|
+
* {@link takeSeeds}.
|
|
83
|
+
*
|
|
84
|
+
* An ancestor that cannot be read ends the walk — quietly when it was never
|
|
85
|
+
* written or the cursor names no checkpoint, both ordinary ends of a chain, and
|
|
86
|
+
* with {@link ancestorExpired} when the row is still stored but past its ttl,
|
|
87
|
+
* which is a hole in the thread.
|
|
88
|
+
*
|
|
89
|
+
* `from.signal` cancels every hop, not just the first. The chain is unbounded
|
|
90
|
+
* in principle — a delta channel rebuilds from the nearest ancestor that stored
|
|
91
|
+
* a value — and each hop is a `getTuple`, which can cost an S3 download, so a
|
|
92
|
+
* walk that could not be stopped part-way would be the one read in this
|
|
93
|
+
* package that ignores a cancel it is given. A cancel is read before each
|
|
94
|
+
* request is sent, so the hop the signal fires on is the last read the call
|
|
95
|
+
* makes.
|
|
96
|
+
*/
|
|
97
|
+
async function walkAncestors(context, getTuple, walk, from) {
|
|
98
|
+
let cursor = cursorFor(from.start, from.signal);
|
|
99
|
+
while (cursor !== undefined && walk.remaining.size > 0) {
|
|
100
|
+
const tuple = await getTuple(cursor);
|
|
101
|
+
if (tuple === undefined) {
|
|
102
|
+
const stop = await probeAncestor(context, cursor);
|
|
103
|
+
if (stop?.expired)
|
|
104
|
+
throw ancestorExpired(stop, [...walk.remaining]);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
collectWrites(tuple, walk);
|
|
108
|
+
takeSeeds(tuple, walk);
|
|
109
|
+
cursor = cursorFor(tuple.parentConfig, from.signal);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Shape one channel's accumulated writes and seed into its public history. */
|
|
113
|
+
function historyOf(walk, channel) {
|
|
114
|
+
const writes = walk.writes[channel].slice().reverse();
|
|
115
|
+
return Object.prototype.hasOwnProperty.call(walk.seeds, channel)
|
|
116
|
+
? { writes, seed: walk.seeds[channel] }
|
|
117
|
+
: { writes };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Walk a checkpoint's ancestors for the delta channels named, accumulating
|
|
121
|
+
* their writes oldest-first and the nearest stored value of each.
|
|
122
|
+
*
|
|
123
|
+
* Same contract and same result as the inherited implementation
|
|
124
|
+
* (`@langchain/langgraph-checkpoint@1.1.5` `dist/base.js:78`), with one
|
|
125
|
+
* difference that is the reason for overriding it: where the inherited walk
|
|
126
|
+
* meets an ancestor it cannot read it simply stops (`if (tup === void 0)
|
|
127
|
+
* break`), reports no seed, and the consumer rebuilds the channel from its
|
|
128
|
+
* initial value (`@langchain/langgraph@1.4.13` `dist/channels/delta.js:65`).
|
|
129
|
+
* That is silent state loss, and this package can produce it: a ttl is computed
|
|
130
|
+
* per put, so a long-running thread expires its own older checkpoints while the
|
|
131
|
+
* newer ones live on.
|
|
132
|
+
*
|
|
133
|
+
* Accepts: `channels` — the delta channels to rebuild; none returns nothing and
|
|
134
|
+
* reads nothing. `getTuple` — the saver's own, so the walk sees exactly what a
|
|
135
|
+
* reader would. `config` — the checkpoint to walk back from. `config.signal` —
|
|
136
|
+
* cancels the whole walk: it is re-attached to each ancestor cursor
|
|
137
|
+
* ({@link cursorFor}), because the pointer a tuple carries is a bare address.
|
|
138
|
+
*
|
|
139
|
+
* Returns: per channel, its on-path writes oldest-first and the nearest stored
|
|
140
|
+
* value found. A channel whose value was never stored gets none, which is the
|
|
141
|
+
* consumer's cue to start from its initial value — correctly, because there is
|
|
142
|
+
* nothing to lose.
|
|
143
|
+
*
|
|
144
|
+
* Throws: `ANCESTOR_EXPIRED` when an ancestor a channel still needs exists but
|
|
145
|
+
* has expired ({@link ancestorExpired}). An ancestor that was never written
|
|
146
|
+
* still ends the walk quietly — that is an ordinary root. `ABORTED` when the
|
|
147
|
+
* signal fires, at whichever hop it fires on, and in preference to a diagnosis
|
|
148
|
+
* of the stop: a walk cancelled just as it reached an expired ancestor reports
|
|
149
|
+
* the cancel, since the caller stopped waiting for the answer either way.
|
|
150
|
+
*
|
|
151
|
+
* Guarantees: the walk stops at the first ancestor that answers for every
|
|
152
|
+
* channel, so a deep thread costs reads only as far back as the nearest
|
|
153
|
+
* snapshot.
|
|
154
|
+
*/
|
|
155
|
+
async function deltaChannelHistory(context, getTuple, config, channels) {
|
|
156
|
+
if (channels.length === 0)
|
|
157
|
+
return {};
|
|
158
|
+
const walk = startWalk(channels);
|
|
159
|
+
const target = await getTuple(config);
|
|
160
|
+
await walkAncestors(context, getTuple, walk, {
|
|
161
|
+
start: target?.parentConfig,
|
|
162
|
+
signal: config.signal,
|
|
163
|
+
});
|
|
164
|
+
const result = {};
|
|
165
|
+
for (const channel of channels)
|
|
166
|
+
result[channel] = historyOf(walk, channel);
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Read the META row an ancestor walk could not follow, **ignoring expiry**, to
|
|
171
|
+
* tell "this checkpoint was never written" apart from "it expired out from
|
|
172
|
+
* under its own descendants".
|
|
173
|
+
*
|
|
174
|
+
* Every other read in this package treats an expired row as absent, which is
|
|
175
|
+
* the right rule for a reader asking for state. Here the distinction is the
|
|
176
|
+
* whole point: one is an ordinary root, the other is data loss.
|
|
177
|
+
*
|
|
178
|
+
* Accepts: `config` — the parent pointer a walk stopped at. `config.signal` —
|
|
179
|
+
* cancels the read, and is read before it is sent. The walk re-attaches the
|
|
180
|
+
* caller's signal to every cursor, so the probe takes its cancel from the same
|
|
181
|
+
* place every other reader in this package takes it, rather than from a
|
|
182
|
+
* parameter of its own.
|
|
183
|
+
*
|
|
184
|
+
* Returns: whether that checkpoint exists and whether it has expired, or
|
|
185
|
+
* `undefined` when the config names no thread or no checkpoint — such a pointer
|
|
186
|
+
* addresses nothing that could have expired, so the walk has simply run out of
|
|
187
|
+
* chain.
|
|
188
|
+
*
|
|
189
|
+
* Throws: whatever the read throws after retries; `ABORTED` when the signal
|
|
190
|
+
* has already fired, which is answered in preference to the expiry this read
|
|
191
|
+
* exists to diagnose — a caller who cancelled is owed its own stop, and is no
|
|
192
|
+
* longer waiting to be told why the walk ended.
|
|
193
|
+
*
|
|
194
|
+
* Guarantees: the read ignores the ttl, deliberately. Every other read in this
|
|
195
|
+
* package treats an expired row as absent, which is the right rule for a reader
|
|
196
|
+
* asking for state; here the distinction is the whole point, because one answer
|
|
197
|
+
* is an ordinary root and the other is data loss.
|
|
198
|
+
*/
|
|
199
|
+
async function probeAncestor(context, config) {
|
|
200
|
+
const ids = config.configurable;
|
|
201
|
+
const threadId = ids?.thread_id;
|
|
202
|
+
const checkpointId = ids?.checkpoint_id;
|
|
203
|
+
if (typeof threadId !== 'string' || typeof checkpointId !== 'string')
|
|
204
|
+
return undefined;
|
|
205
|
+
const checkpointNs = ids?.checkpoint_ns ?? '';
|
|
206
|
+
const result = await (0, retry_1.withDynamoDBRetry)((request) => context.client.get({
|
|
207
|
+
TableName: context.tableName,
|
|
208
|
+
Key: (0, rows_1.metaRowKey)({ threadId, checkpointNs, checkpointId }),
|
|
209
|
+
ConsistentRead: true,
|
|
210
|
+
}, request), (0, retry_1.retryFor)(context, config.signal));
|
|
211
|
+
const row = result.Item;
|
|
212
|
+
return {
|
|
213
|
+
threadId,
|
|
214
|
+
checkpointId,
|
|
215
|
+
expired: row !== undefined && (0, table_schema_1.isExpiredRow)(row, (0, clock_1.nowSeconds)()),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The error a read raises when a delta channel's history has a hole in it.
|
|
220
|
+
*
|
|
221
|
+
* Accepts: `stop` — the expired ancestor the walk reached. `channels` — the
|
|
222
|
+
* delta channels that still needed it, named in the message so the operator
|
|
223
|
+
* knows what was lost.
|
|
224
|
+
*
|
|
225
|
+
* Returns: the error, coded `ANCESTOR_EXPIRED` and carrying the thread and
|
|
226
|
+
* checkpoint. The message bounds all three: after the first hop the walk's
|
|
227
|
+
* cursor is a row's own `parentConfig`, so the identifiers it names come off a
|
|
228
|
+
* row, and `channels` is checked for being an array of strings and for nothing
|
|
229
|
+
* else — neither how many nor how long. `context` carries both identifiers
|
|
230
|
+
* whole, which is what a caller branches on.
|
|
231
|
+
*
|
|
232
|
+
* Throws: nothing — it builds the error, the caller throws it.
|
|
233
|
+
*
|
|
234
|
+
* Guarantees: returning the partial history instead would hand the caller a
|
|
235
|
+
* channel rebuilt from its initial value plus whatever writes survived — a
|
|
236
|
+
* shorter message list, say, with nothing to say that anything is missing. The
|
|
237
|
+
* reference contract has no way to express "incomplete", so refusing the read
|
|
238
|
+
* is the only honest answer.
|
|
239
|
+
*/
|
|
240
|
+
function ancestorExpired(stop, channels) {
|
|
241
|
+
const named = (0, truncate_1.truncateLabelsForLog)(channels)
|
|
242
|
+
.map((channel) => `"${channel}"`)
|
|
243
|
+
.join(', ');
|
|
244
|
+
return new base_error_1.DynamoDBLangGraphError(`checkpoint "${(0, truncate_1.truncateForLog)(stop.checkpointId)}" of thread ` +
|
|
245
|
+
`"${(0, truncate_1.truncateForLog)(stop.threadId)}" has expired, but later ` +
|
|
246
|
+
`checkpoints still need it to reconstruct ${named}. ` +
|
|
247
|
+
'A delta channel writes a full snapshot only every `snapshotFrequency` updates and leaves ' +
|
|
248
|
+
'itself out of the checkpoints in between, so its value is rebuilt from an earlier ' +
|
|
249
|
+
'ancestor — which a per-checkpoint ttl expires while its descendants live on. Lower ' +
|
|
250
|
+
'`snapshotFrequency` (1 makes every checkpoint self-contained), or do not configure a ttl ' +
|
|
251
|
+
'on threads that use delta channels.', error_code_1.ErrorCode.ANCESTOR_EXPIRED, { threadId: stop.threadId, checkpointId: stop.checkpointId });
|
|
252
|
+
}
|
|
@@ -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';
|
|
13
|
+
import type { FilterValue, ListScope, ThreadId } from './parse';
|
|
14
|
+
import { type CheckpointMetaRow } from './rows';
|
|
15
|
+
import type { CheckpointerContext } from './setup';
|
|
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,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hides where a listing's META rows come from and which of them pass its filters.
|
|
4
|
+
*
|
|
5
|
+
* A listing that names a thread is a partition query; one that does not is a
|
|
6
|
+
* recency-index read when the table carries the index and a table scan when it
|
|
7
|
+
* does not (record 8). Whichever it is, rows are narrowed to this adapter's own,
|
|
8
|
+
* and a row passes only when its key fields match the scope and, when the caller
|
|
9
|
+
* gave a filter, its decoded metadata equals the filter clause for clause.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.listQuery = listQuery;
|
|
13
|
+
exports.listScan = listScan;
|
|
14
|
+
exports.passesKeyFilters = passesKeyFilters;
|
|
15
|
+
exports.passesMetadataFilter = passesMetadataFilter;
|
|
16
|
+
exports.metaRows = metaRows;
|
|
17
|
+
exports.parseListedRow = parseListedRow;
|
|
18
|
+
exports.matchesFilter = matchesFilter;
|
|
19
|
+
const node_util_1 = require("node:util");
|
|
20
|
+
const concurrency_1 = require("../../shared/concurrency");
|
|
21
|
+
const paginate_1 = require("../../shared/dynamodb/paginate");
|
|
22
|
+
const recency_index_1 = require("../../shared/dynamodb/recency-index");
|
|
23
|
+
const retry_1 = require("../../shared/dynamodb/retry");
|
|
24
|
+
const table_schema_1 = require("../../shared/dynamodb/table-schema");
|
|
25
|
+
const truncate_1 = require("../../shared/logging/truncate");
|
|
26
|
+
const rows_1 = require("./rows");
|
|
27
|
+
/**
|
|
28
|
+
* The META query for a scope that names a thread.
|
|
29
|
+
*
|
|
30
|
+
* Accepts: `scope.filter` — its presence means rows may be dropped client-side,
|
|
31
|
+
* so only an unfiltered list passes the caller's `limit` through as the page
|
|
32
|
+
* size; passing it through a filtered read would cut the page short of matches
|
|
33
|
+
* that exist. `scope.checkpointNs` — absent spans every namespace of the
|
|
34
|
+
* thread. `scope.before` — bounds the key range only with an explicit
|
|
35
|
+
* namespace, since across namespaces ids do not share one order; it is applied
|
|
36
|
+
* in-process otherwise.
|
|
37
|
+
*
|
|
38
|
+
* Returns: the Query input.
|
|
39
|
+
*
|
|
40
|
+
* Throws: nothing.
|
|
41
|
+
*/
|
|
42
|
+
function listQuery(context, scope) {
|
|
43
|
+
const partition = (0, rows_1.partitionKey)(scope.threadId);
|
|
44
|
+
const limit = scope.filter === undefined ? scope.limit : undefined;
|
|
45
|
+
if (scope.checkpointNs === undefined) {
|
|
46
|
+
return (0, rows_1.beginsWithQuery)(context.tableName, partition, (0, rows_1.metaAnyNamespacePrefix)(), { limit });
|
|
47
|
+
}
|
|
48
|
+
return (0, rows_1.beginsWithQuery)(context.tableName, partition, (0, rows_1.metaSortKeyPrefix)(scope.checkpointNs), {
|
|
49
|
+
limit,
|
|
50
|
+
beforeSortKey: scope.before === undefined ? undefined : (0, rows_1.metaSortKey)(scope.checkpointNs, scope.before),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The table `Scan` a thread-less `list()` runs when no recency index is
|
|
55
|
+
* configured.
|
|
56
|
+
*
|
|
57
|
+
* Accepts: `scope.checkpointNs` — narrows the filter to one namespace when the
|
|
58
|
+
* caller gave one.
|
|
59
|
+
*
|
|
60
|
+
* Returns: the Scan input, filtered to this adapter's META rows. It is what the
|
|
61
|
+
* reference savers do for a config without a thread, and on DynamoDB it costs a
|
|
62
|
+
* read of the whole table — cross-tenant by construction, which the public
|
|
63
|
+
* documentation says outright.
|
|
64
|
+
*
|
|
65
|
+
* Throws: nothing.
|
|
66
|
+
*/
|
|
67
|
+
function listScan(context, scope) {
|
|
68
|
+
return {
|
|
69
|
+
TableName: context.tableName,
|
|
70
|
+
FilterExpression: 'begins_with(#pk, :pk) AND begins_with(#sk, :sk)',
|
|
71
|
+
ExpressionAttributeNames: { '#pk': table_schema_1.PARTITION_KEY_ATTRIBUTE, '#sk': table_schema_1.SORT_KEY_ATTRIBUTE },
|
|
72
|
+
ExpressionAttributeValues: {
|
|
73
|
+
':pk': (0, rows_1.checkpointerPartitionPrefix)(),
|
|
74
|
+
':sk': scope.checkpointNs === undefined
|
|
75
|
+
? (0, rows_1.metaAnyNamespacePrefix)()
|
|
76
|
+
: (0, rows_1.metaSortKeyPrefix)(scope.checkpointNs),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Whether `meta` passes the key-level filters.
|
|
82
|
+
*
|
|
83
|
+
* Accepts: any narrowed META row, from a query or a scan.
|
|
84
|
+
*
|
|
85
|
+
* Returns: whether it is strictly older than `before` and — on a table scan,
|
|
86
|
+
* where the key condition cannot narrow them — in the requested namespace and,
|
|
87
|
+
* when one is given, the requested checkpoint. Applied to query results too,
|
|
88
|
+
* which is redundant there and free: one rule, one place.
|
|
89
|
+
*
|
|
90
|
+
* "Older" is {@link compareSortKeys}, because on the query path the same bound
|
|
91
|
+
* is already a `BETWEEN` on the composed sort key, which DynamoDB evaluates in
|
|
92
|
+
* UTF-8 byte order. JavaScript's `<` orders UTF-16 code units instead, and at
|
|
93
|
+
* an astral id the two disagree, so `<` here would turn the redundant pass
|
|
94
|
+
* into a second, different filter that drops rows the query rightly returned.
|
|
95
|
+
* Every id in one namespace shares its sort key's prefix, so comparing the id
|
|
96
|
+
* is comparing the sort key.
|
|
97
|
+
*
|
|
98
|
+
* Throws: nothing.
|
|
99
|
+
*/
|
|
100
|
+
function passesKeyFilters(meta, scope) {
|
|
101
|
+
return ((scope.before === undefined || (0, table_schema_1.compareSortKeys)(meta.checkpointId, scope.before) < 0) &&
|
|
102
|
+
(scope.checkpointNs === undefined || meta.checkpointNs === scope.checkpointNs) &&
|
|
103
|
+
(scope.checkpointId === undefined || meta.checkpointId === scope.checkpointId));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Apply the optional metadata-equality filter.
|
|
107
|
+
*
|
|
108
|
+
* Accepts: `scope.filter` — absent means every row passes and nothing is
|
|
109
|
+
* decoded. `meta` — already bound to its partition, so the scope its metadata
|
|
110
|
+
* is read under is its own.
|
|
111
|
+
*
|
|
112
|
+
* Returns: whether the row passes and, when it does and a filter forced the
|
|
113
|
+
* decode, the metadata itself — handed to the tuple assembly, so a filtered
|
|
114
|
+
* list decodes (and, when offloaded, downloads) each blob once instead of
|
|
115
|
+
* twice.
|
|
116
|
+
*
|
|
117
|
+
* Throws: whatever the decode throws. Metadata that decodes to something that
|
|
118
|
+
* is not an object matches no filter clause rather than failing the listing.
|
|
119
|
+
*/
|
|
120
|
+
async function passesMetadataFilter(context, meta, scope) {
|
|
121
|
+
if (!scope.filter)
|
|
122
|
+
return { pass: true };
|
|
123
|
+
const metadata = await (0, rows_1.readMetadata)(context, meta, meta.threadId, scope.signal);
|
|
124
|
+
return matchesFilter(metadata, scope.filter) ? { pass: true, metadata } : { pass: false };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Every checkpoint META row of the table, newest first, without a thread to
|
|
128
|
+
* scope the read.
|
|
129
|
+
*
|
|
130
|
+
* From the recency index when `indexName` is set, 100 rows a page: each shard
|
|
131
|
+
* is read one DynamoDB page at a time, and its next page whenever it has no row
|
|
132
|
+
* buffered and the page still needs one, with at most `readConcurrency` shards
|
|
133
|
+
* queried at once, so memory is the page being built plus at most one DynamoDB
|
|
134
|
+
* page per shard. Without `indexName` it is a table `Scan`: read capacity for
|
|
135
|
+
* every row evaluated, not every row returned. The index path needs
|
|
136
|
+
* `backfillRecencyIndex` to have run, or rows written before the index are not
|
|
137
|
+
* in it.
|
|
138
|
+
*/
|
|
139
|
+
function threadlessRows(context, scope, now) {
|
|
140
|
+
if (context.indexName === undefined) {
|
|
141
|
+
return (0, paginate_1.paginateScan)({
|
|
142
|
+
retry: (0, retry_1.retryFor)(context, scope.signal),
|
|
143
|
+
signal: scope.signal,
|
|
144
|
+
client: context.client,
|
|
145
|
+
params: (0, table_schema_1.withoutExpired)(listScan(context, scope), now),
|
|
146
|
+
maxItems: Number.POSITIVE_INFINITY,
|
|
147
|
+
maxIterations: Number.POSITIVE_INFINITY,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return (0, recency_index_1.iterateRecencyIndex)({
|
|
151
|
+
client: context.client,
|
|
152
|
+
tableName: context.tableName,
|
|
153
|
+
indexName: context.indexName,
|
|
154
|
+
tag: 'CHKPT',
|
|
155
|
+
shards: context.indexShards ?? recency_index_1.DEFAULT_INDEX_SHARDS,
|
|
156
|
+
concurrency: context.readConcurrency ?? concurrency_1.DEFAULT_READ_CONCURRENCY,
|
|
157
|
+
retry: (0, retry_1.retryFor)(context, scope.signal),
|
|
158
|
+
signal: scope.signal,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The META rows a scope covers: a partition query when the scope names a
|
|
163
|
+
* thread, and {@link threadlessRows} when it does not.
|
|
164
|
+
*
|
|
165
|
+
* Accepts: `scope` — a thread, or none, in which case every thread in the table
|
|
166
|
+
* is read, through the recency index when `indexName` is set and a scan
|
|
167
|
+
* otherwise. `now` — the instant expiry is judged against, taken once so one
|
|
168
|
+
* listing cannot disagree with itself.
|
|
169
|
+
*
|
|
170
|
+
* Returns: an async generator over the raw rows, newest-first within a
|
|
171
|
+
* namespace. Abandoning it stops the read.
|
|
172
|
+
*
|
|
173
|
+
* Throws: whatever the query or scan throws; `ABORTED` when the signal
|
|
174
|
+
* fires.
|
|
175
|
+
*
|
|
176
|
+
* Guarantees: the read is deliberately unbounded. This is a stream that never
|
|
177
|
+
* accumulates, a limit stops it early, and a row cap would turn a caller asking
|
|
178
|
+
* for a handful of rare matches over a large thread into a hard error instead
|
|
179
|
+
* of the true answer.
|
|
180
|
+
*/
|
|
181
|
+
function metaRows(context, scope, now) {
|
|
182
|
+
const retry = (0, retry_1.retryFor)(context, scope.signal);
|
|
183
|
+
const bounds = { maxItems: Number.POSITIVE_INFINITY, maxIterations: Number.POSITIVE_INFINITY };
|
|
184
|
+
return scope.threadId === undefined
|
|
185
|
+
? threadlessRows(context, scope, now)
|
|
186
|
+
: (0, paginate_1.paginateQuery)({
|
|
187
|
+
retry,
|
|
188
|
+
signal: scope.signal,
|
|
189
|
+
client: context.client,
|
|
190
|
+
params: (0, table_schema_1.withoutExpired)(listQuery(context, { ...scope, threadId: scope.threadId }), now),
|
|
191
|
+
...bounds,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Narrow a row from that stream, saying so when it is not one of ours.
|
|
196
|
+
*
|
|
197
|
+
* Accepts: `raw` — any row the stream yielded.
|
|
198
|
+
*
|
|
199
|
+
* Returns: the META item, or undefined for a row that is not this adapter's —
|
|
200
|
+
* logged at `warn`, since on a shared table a row of another adapter can share
|
|
201
|
+
* the sort-key prefix and an operator should know it is there.
|
|
202
|
+
*
|
|
203
|
+
* Throws: `FORMAT_UNSUPPORTED` for one of ours written by a newer version.
|
|
204
|
+
*
|
|
205
|
+
* Guarantees: a foreign row is skipped, never assembled. Treating one as a
|
|
206
|
+
* checkpoint would surface a tuple built from another adapter's data.
|
|
207
|
+
*/
|
|
208
|
+
function parseListedRow(context, raw) {
|
|
209
|
+
const meta = (0, rows_1.parseMetaRow)(raw);
|
|
210
|
+
if (!meta) {
|
|
211
|
+
context.logger.warn('list: skipped a row that is not a checkpoint meta item', {
|
|
212
|
+
sortKey: (0, truncate_1.truncateForLog)(raw.SK),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return meta;
|
|
216
|
+
}
|
|
217
|
+
/** The value `metadata` holds at `key`, or undefined when it holds no such own property. */
|
|
218
|
+
function ownValue(metadata, key) {
|
|
219
|
+
if (metadata === null || typeof metadata !== 'object')
|
|
220
|
+
return undefined;
|
|
221
|
+
return Object.hasOwn(metadata, key) ? metadata[key] : undefined;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Whether `metadata` satisfies every clause of `filter`.
|
|
225
|
+
*
|
|
226
|
+
* Accepts: `metadata` — a checkpoint's decoded metadata. Declared as a record,
|
|
227
|
+
* but a row can hold anything its writer stored, including `null` and a scalar;
|
|
228
|
+
* such a value has no own properties and so matches no clause.
|
|
229
|
+
* `filter` — the caller's equality clauses; `{}` matches everything.
|
|
230
|
+
*
|
|
231
|
+
* Returns: true when every key of `filter` is an **own** property of `metadata`
|
|
232
|
+
* with a deeply equal value. Equality is structural and key-order-independent
|
|
233
|
+
* for nested objects, order-significant for arrays, and type-strict — `3` does
|
|
234
|
+
* not match `'3'`.
|
|
235
|
+
*
|
|
236
|
+
* Throws: nothing. A filtered `list()` walks every row, so a single row whose
|
|
237
|
+
* metadata is not an object must not fail the listing.
|
|
238
|
+
*
|
|
239
|
+
* Guarantees: only own properties count, so a filter on `constructor` or
|
|
240
|
+
* `toString` compares against nothing rather than against the prototype's
|
|
241
|
+
* function — the same rule the store's filter applies.
|
|
242
|
+
*/
|
|
243
|
+
function matchesFilter(metadata, filter) {
|
|
244
|
+
return Object.entries(filter).every(([key, value]) => (0, node_util_1.isDeepStrictEqual)(ownValue(metadata, key), value));
|
|
245
|
+
}
|