@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,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides how rows written before the recency index are given its keys.
|
|
3
|
+
*
|
|
4
|
+
* The index is opt-in (record 8), so a table can hold rows from before it
|
|
5
|
+
* existed. An operator walks the table a page at a time, resumably, and gives
|
|
6
|
+
* each row the keys its adapter would have written; which rows those are is
|
|
7
|
+
* each adapter's own answer, asked here, and a row that gained keys since the
|
|
8
|
+
* scan read it is left alone.
|
|
9
|
+
*/
|
|
10
|
+
import type { AttributeMap, DynamoDBDocumentLike } from '../shared/dynamodb/client';
|
|
11
|
+
import { type IndexTarget } from '../shared/dynamodb/recency-index';
|
|
12
|
+
import { type RetryOptions } from '../shared/dynamodb/retry';
|
|
13
|
+
/**
|
|
14
|
+
* Give rows written before the recency index their index keys.
|
|
15
|
+
*
|
|
16
|
+
* **Run this before setting `indexName` on any adapter.** A row without the
|
|
17
|
+
* keys is not in the index, so enabling the index first would make every
|
|
18
|
+
* pre-existing session, item and checkpoint silently vanish from the listings
|
|
19
|
+
* that read it — the rows are still there, and every other read still returns
|
|
20
|
+
* them, but a listing would not.
|
|
21
|
+
*
|
|
22
|
+
* Safe to re-run and safe to run while adapters are writing: every write is
|
|
23
|
+
* conditional on the row still being there and having no keys yet, so a row a
|
|
24
|
+
* live adapter has already indexed is left exactly as it is, and a row deleted
|
|
25
|
+
* after the scan found it stays deleted rather than being re-created by an
|
|
26
|
+
* `UpdateItem`, which upserts.
|
|
27
|
+
*
|
|
28
|
+
* `indexShards` must match what the adapters use. A mismatch puts rows on
|
|
29
|
+
* shards no listing queries, which looks exactly like the rows being missing.
|
|
30
|
+
*
|
|
31
|
+
* Accepts: `options` — validated in full before any read: only the keys
|
|
32
|
+
* `BackfillOptions` declares; `tableName`, `indexShards` and the numbers in
|
|
33
|
+
* `retry` by the adapters' rules; `signal` as their methods check it; a
|
|
34
|
+
* `client` providing `scan` and `update`. `options.pageSize` — a positive integer,
|
|
35
|
+
* default 100. `options.cursor` — from a previous run, to resume.
|
|
36
|
+
* `options.maxPages` — how far one run goes, so a large table can be
|
|
37
|
+
* backfilled in bounded slices. `options.indexShards` — must equal the
|
|
38
|
+
* adapters' setting, and has their ceiling. `options.dryRun` — a boolean.
|
|
39
|
+
* `options.signal` — cancels the run; `retry.signal` does so when there is no
|
|
40
|
+
* top-level `signal`, and the top-level one wins when both are given.
|
|
41
|
+
*
|
|
42
|
+
* Returns: how many rows were scanned, how many were given keys and how many
|
|
43
|
+
* were skipped — a row no listing reaches, and a row whose write the condition
|
|
44
|
+
* refused because the row already has keys or is gone — plus a `nextCursor`
|
|
45
|
+
* when the run stopped short of the end. An absent cursor means the table is
|
|
46
|
+
* fully backfilled.
|
|
47
|
+
*
|
|
48
|
+
* Throws: `VALIDATION` naming the offending option, before any DynamoDB
|
|
49
|
+
* call; `RETRY_EXHAUSTED` once a transient failure has used every attempt;
|
|
50
|
+
* `ABORTED` when `signal` fires, or `retry.signal` when no top-level `signal`
|
|
51
|
+
* is given; any other error the scan or the writes throw, wrapped with the
|
|
52
|
+
* code the classifier assigns — this is the function's own error boundary,
|
|
53
|
+
* the same as every adapter's public methods, so a caller's mistake never escapes as a bare
|
|
54
|
+
* exception. A refused write is none of these: it is an outcome for one row,
|
|
55
|
+
* reported in `skipped`.
|
|
56
|
+
*
|
|
57
|
+
* Guarantees: every write is conditional on the row still being there and
|
|
58
|
+
* having no keys yet, so re-running is safe, running against a live table is
|
|
59
|
+
* safe, a row a live adapter has already indexed is left exactly as it is, and
|
|
60
|
+
* a row deleted between the scan and the write is never re-created. Neither
|
|
61
|
+
* refusal stops the run: both mean this run has nothing to do for that row, so
|
|
62
|
+
* the row is counted as skipped and the walk carries on to the rest of the
|
|
63
|
+
* table.
|
|
64
|
+
*/
|
|
65
|
+
export declare function backfillRecencyIndex(options: BackfillOptions): Promise<BackfillResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Which rows the index covers: each adapter answers for its own, and no row belongs to two.
|
|
68
|
+
*
|
|
69
|
+
* Accepts: `row` — any row a table scan returns, including a foreign one and
|
|
70
|
+
* one whose `PK`/`SK` are not strings.
|
|
71
|
+
*
|
|
72
|
+
* Returns: the index identity, or undefined for a row no listing reaches — a
|
|
73
|
+
* foreign row, a payload or write row, a META row carrying no `checkpointId`.
|
|
74
|
+
*
|
|
75
|
+
* Throws: nothing. A backfill walks the whole table; one unrecognised row must
|
|
76
|
+
* be skipped, not fatal.
|
|
77
|
+
*/
|
|
78
|
+
export declare function indexTargetOf(row: AttributeMap): IndexTarget | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* A scan position, as an opaque string.
|
|
81
|
+
*
|
|
82
|
+
* Accepts: `key` — a `LastEvaluatedKey` from the scan being resumed.
|
|
83
|
+
*
|
|
84
|
+
* Returns: it base64url-encoded. Opaque to the caller: its shape is not a
|
|
85
|
+
* promise, which is what leaves the encoding free to change.
|
|
86
|
+
*
|
|
87
|
+
* Throws: nothing.
|
|
88
|
+
*/
|
|
89
|
+
export declare function encodeScanCursor(key: AttributeMap): string;
|
|
90
|
+
/**
|
|
91
|
+
* The scan position a cursor encodes.
|
|
92
|
+
*
|
|
93
|
+
* Accepts: `cursor` — as a previous page returned it.
|
|
94
|
+
*
|
|
95
|
+
* Returns: the `ExclusiveStartKey` to resume from — always exactly `{ PK,
|
|
96
|
+
* SK }`, both strings, since a plain table `Scan` (no `IndexName`) never
|
|
97
|
+
* returns a `LastEvaluatedKey` shaped any other way.
|
|
98
|
+
*
|
|
99
|
+
* Throws: `VALIDATION` naming `cursor` for anything this tool did not
|
|
100
|
+
* issue — text that is not base64url, that does not decode to JSON, or that
|
|
101
|
+
* decodes to anything but `{ PK: string, SK: string }`: an array, an object
|
|
102
|
+
* missing either key, carrying an extra one, or carrying a non-string value
|
|
103
|
+
* for either. A cursor is fed straight back to DynamoDB as
|
|
104
|
+
* `ExclusiveStartKey`, so a value of the wrong shape is refused here rather
|
|
105
|
+
* than surfacing as a raw `ValidationException` from the service.
|
|
106
|
+
*/
|
|
107
|
+
export declare function decodeScanCursor(cursor: string): AttributeMap;
|
|
108
|
+
/** What one pass of the backfill did, and where to resume. */
|
|
109
|
+
export interface BackfillResult {
|
|
110
|
+
/** Rows the scan evaluated. */
|
|
111
|
+
scanned: number;
|
|
112
|
+
/** Rows given index keys. */
|
|
113
|
+
indexed: number;
|
|
114
|
+
/**
|
|
115
|
+
* Rows this run wrote no keys for: one no listing reaches, and one whose
|
|
116
|
+
* write the condition refused because it already has keys or is gone.
|
|
117
|
+
*/
|
|
118
|
+
skipped: number;
|
|
119
|
+
/**
|
|
120
|
+
* Opaque; absent when the table is fully walked. Pass it back to continue —
|
|
121
|
+
* the pass is resumable, so a large table can be backfilled in bounded runs.
|
|
122
|
+
*/
|
|
123
|
+
nextCursor?: string;
|
|
124
|
+
}
|
|
125
|
+
/** What the backfill needs to walk a table. A key this type does not declare is refused. */
|
|
126
|
+
export interface BackfillOptions {
|
|
127
|
+
client: DynamoDBDocumentLike;
|
|
128
|
+
tableName: string;
|
|
129
|
+
/** Must equal the adapters' `indexShards`, or rows land on shards no listing queries. */
|
|
130
|
+
indexShards?: number;
|
|
131
|
+
/** Rows per scan page. */
|
|
132
|
+
pageSize?: number;
|
|
133
|
+
/** Stop after this many pages and return a cursor. Default: walk the whole table. */
|
|
134
|
+
maxPages?: number;
|
|
135
|
+
cursor?: string;
|
|
136
|
+
/** Report what would change without writing. */
|
|
137
|
+
dryRun?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* The full retry surface, not the adapters' narrower `RetryPolicy`:
|
|
140
|
+
* `onRetry` is backfill's only way to observe retries in progress, since it
|
|
141
|
+
* takes no `logger`.
|
|
142
|
+
*/
|
|
143
|
+
retry?: RetryOptions;
|
|
144
|
+
signal?: AbortSignal;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Validate every option `backfillRecencyIndex` reads, before any of them is
|
|
148
|
+
* read for real.
|
|
149
|
+
*
|
|
150
|
+
* Accepts: `options` — must be an object naming only the nine keys
|
|
151
|
+
* {@link BackfillOptions} declares. `tableName` and `client` are required, the
|
|
152
|
+
* rest optional; each, when given, follows the same rule an adapter's own
|
|
153
|
+
* option of the same name does. `tableName` reuses the adapters' own
|
|
154
|
+
* `tableName` validator outright; `indexShards` is held to the adapters'
|
|
155
|
+
* shard cap, `MAX_INDEX_SHARDS`; and `retry` shares its numeric bounds with
|
|
156
|
+
* the adapters' own `retry` validator while accepting the wider surface
|
|
157
|
+
* backfill's `RetryOptions` needs, so a mismatch between backfill and the
|
|
158
|
+
* adapters it feeds cannot drift in on what a bound means.
|
|
159
|
+
*
|
|
160
|
+
* Returns: nothing: the value is kept under its declared type, and this
|
|
161
|
+
* checks it.
|
|
162
|
+
*
|
|
163
|
+
* Throws: `VALIDATION` naming `options.<key>` for an unknown key;
|
|
164
|
+
* `tableName`; `client` or `client.<member>`; `indexShards`, `pageSize` or
|
|
165
|
+
* `maxPages` for a non-positive-integer bound (`indexShards` is additionally
|
|
166
|
+
* capped); `dryRun` for a non-boolean; `retry`/`retry.<key>`; `signal`.
|
|
167
|
+
*/
|
|
168
|
+
export declare function assertBackfillOptions(options: BackfillOptions): void;
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hides how rows written before the recency index are given its keys.
|
|
4
|
+
*
|
|
5
|
+
* The index is opt-in (record 8), so a table can hold rows from before it
|
|
6
|
+
* existed. An operator walks the table a page at a time, resumably, and gives
|
|
7
|
+
* each row the keys its adapter would have written; which rows those are is
|
|
8
|
+
* each adapter's own answer, asked here, and a row that gained keys since the
|
|
9
|
+
* scan read it is left alone.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.backfillRecencyIndex = backfillRecencyIndex;
|
|
13
|
+
exports.indexTargetOf = indexTargetOf;
|
|
14
|
+
exports.encodeScanCursor = encodeScanCursor;
|
|
15
|
+
exports.decodeScanCursor = decodeScanCursor;
|
|
16
|
+
exports.assertBackfillOptions = assertBackfillOptions;
|
|
17
|
+
const rows_1 = require("../checkpointer/internal/rows");
|
|
18
|
+
const session_1 = require("../history/internal/session");
|
|
19
|
+
const concurrency_1 = require("../shared/concurrency");
|
|
20
|
+
const idempotent_write_1 = require("../shared/dynamodb/idempotent-write");
|
|
21
|
+
const recency_index_1 = require("../shared/dynamodb/recency-index");
|
|
22
|
+
const retry_1 = require("../shared/dynamodb/retry");
|
|
23
|
+
const table_schema_1 = require("../shared/dynamodb/table-schema");
|
|
24
|
+
const boundary_1 = require("../shared/errors/boundary");
|
|
25
|
+
const errors_1 = require("../shared/errors/errors");
|
|
26
|
+
const collaborators_1 = require("../shared/validation/collaborators");
|
|
27
|
+
const option_shape_1 = require("../shared/validation/option-shape");
|
|
28
|
+
const options_1 = require("../shared/validation/options");
|
|
29
|
+
const primitives_1 = require("../shared/validation/primitives");
|
|
30
|
+
const rows_2 = require("../store/internal/rows");
|
|
31
|
+
/**
|
|
32
|
+
* The retry policy every request of one run uses: the caller's `retry`, with
|
|
33
|
+
* the signal that cancels the run. That is the top-level `signal` when one is
|
|
34
|
+
* given and `retry.signal` otherwise — the top-level one is the caller's handle
|
|
35
|
+
* on the whole operation, so it wins when both are set.
|
|
36
|
+
*/
|
|
37
|
+
function runRetry(options) {
|
|
38
|
+
return { ...options.retry, signal: options.signal ?? options.retry?.signal };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Write one row's index keys; false when this run wrote none for it.
|
|
42
|
+
*
|
|
43
|
+
* False is an ordinary outcome and never a failure. Either the row is not one a
|
|
44
|
+
* listing reaches, so it needs no keys; or the conditional update was refused,
|
|
45
|
+
* which by the terms of that condition means the row already carries keys a
|
|
46
|
+
* live adapter gave it, or the row is gone. In every one of those cases this
|
|
47
|
+
* run has nothing to do for the row, and the row is counted as skipped.
|
|
48
|
+
*
|
|
49
|
+
* Which is why the refusal ends the row rather than the run. Both races are
|
|
50
|
+
* ordinary on a table that is being written to, and that is the only kind of
|
|
51
|
+
* table anyone runs a backfill against; a tool that stopped whenever the table
|
|
52
|
+
* it is migrating is in use would never finish one. Re-running is cheap and
|
|
53
|
+
* safe besides — the scan's own `attribute_not_exists` filter never looks at a
|
|
54
|
+
* row an earlier run indexed.
|
|
55
|
+
*
|
|
56
|
+
* Any other failure is rethrown and ends the run, because nothing about it says
|
|
57
|
+
* this row needed no writing.
|
|
58
|
+
*/
|
|
59
|
+
async function indexRow(options, row, shards) {
|
|
60
|
+
const target = indexTargetOf(row);
|
|
61
|
+
if (target === undefined)
|
|
62
|
+
return false;
|
|
63
|
+
const keys = (0, recency_index_1.indexKeys)(target.tag, target.id, target.at, shards);
|
|
64
|
+
if (options.dryRun)
|
|
65
|
+
return true;
|
|
66
|
+
try {
|
|
67
|
+
await writeIndexKeys(options, row, keys);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (!(0, idempotent_write_1.isConditionalCheckFailed)(error))
|
|
71
|
+
throw error;
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
/** The conditional `UpdateItem` that gives one row the keys computed for it. */
|
|
77
|
+
async function writeIndexKeys(options, row, keys) {
|
|
78
|
+
await (0, retry_1.withDynamoDBRetry)((request) => options.client.update({
|
|
79
|
+
TableName: options.tableName,
|
|
80
|
+
Key: (0, table_schema_1.rowKeyOf)(row),
|
|
81
|
+
UpdateExpression: 'SET #gpk = :gpk, #gsk = :gsk',
|
|
82
|
+
ExpressionAttributeNames: { '#gpk': 'gsi1pk', '#gsk': 'gsi1sk' },
|
|
83
|
+
ExpressionAttributeValues: { ':gpk': keys.gsi1pk, ':gsk': keys.gsi1sk },
|
|
84
|
+
// Two clauses, and both are load-bearing.
|
|
85
|
+
//
|
|
86
|
+
// `attribute_not_exists(#gpk)` never overwrites keys a row already has:
|
|
87
|
+
// a row a running adapter wrote carries its true timestamp, and
|
|
88
|
+
// replacing it with the pre-index epoch would move a live row to the
|
|
89
|
+
// bottom of every listing.
|
|
90
|
+
//
|
|
91
|
+
// `attribute_exists(PK)` is what makes this an update rather than an
|
|
92
|
+
// upsert, which is what `UpdateItem` is by default. A condition naming
|
|
93
|
+
// only the index attribute is satisfied by a key holding *nothing at
|
|
94
|
+
// all*, so without it, a row deleted between the scan that found it
|
|
95
|
+
// and this update would be re-created as a stub carrying nothing but
|
|
96
|
+
// `PK`, `SK` and the two index keys — and carrying them, it would land
|
|
97
|
+
// in the recency index that the cross-partition listings read. The
|
|
98
|
+
// tool exists to give keys to rows that are already there, so nothing
|
|
99
|
+
// legitimate is refused.
|
|
100
|
+
ConditionExpression: `attribute_exists(${table_schema_1.PARTITION_KEY_ATTRIBUTE}) AND attribute_not_exists(#gpk)`,
|
|
101
|
+
}, request), runRetry(options));
|
|
102
|
+
}
|
|
103
|
+
/** One scan page, and the rows of it that were given keys. */
|
|
104
|
+
async function backfillPage(options, shards, startKey) {
|
|
105
|
+
const result = await (0, retry_1.withDynamoDBRetry)((request) => options.client.scan({
|
|
106
|
+
TableName: options.tableName,
|
|
107
|
+
Limit: options.pageSize ?? 100,
|
|
108
|
+
ExclusiveStartKey: startKey,
|
|
109
|
+
// Rows that already carry keys are not read into memory at all.
|
|
110
|
+
FilterExpression: 'attribute_not_exists(#gpk)',
|
|
111
|
+
ExpressionAttributeNames: { '#gpk': 'gsi1pk' },
|
|
112
|
+
}, request), runRetry(options));
|
|
113
|
+
const rows = (result.Items ?? []);
|
|
114
|
+
const written = await (0, concurrency_1.mapWithConcurrency)(rows, concurrency_1.DEFAULT_READ_CONCURRENCY, (row) => indexRow(options, row, shards));
|
|
115
|
+
return {
|
|
116
|
+
rows: rows.length,
|
|
117
|
+
indexed: written.filter(Boolean).length,
|
|
118
|
+
nextKey: result.LastEvaluatedKey,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Give rows written before the recency index their index keys.
|
|
123
|
+
*
|
|
124
|
+
* **Run this before setting `indexName` on any adapter.** A row without the
|
|
125
|
+
* keys is not in the index, so enabling the index first would make every
|
|
126
|
+
* pre-existing session, item and checkpoint silently vanish from the listings
|
|
127
|
+
* that read it — the rows are still there, and every other read still returns
|
|
128
|
+
* them, but a listing would not.
|
|
129
|
+
*
|
|
130
|
+
* Safe to re-run and safe to run while adapters are writing: every write is
|
|
131
|
+
* conditional on the row still being there and having no keys yet, so a row a
|
|
132
|
+
* live adapter has already indexed is left exactly as it is, and a row deleted
|
|
133
|
+
* after the scan found it stays deleted rather than being re-created by an
|
|
134
|
+
* `UpdateItem`, which upserts.
|
|
135
|
+
*
|
|
136
|
+
* `indexShards` must match what the adapters use. A mismatch puts rows on
|
|
137
|
+
* shards no listing queries, which looks exactly like the rows being missing.
|
|
138
|
+
*
|
|
139
|
+
* Accepts: `options` — validated in full before any read: only the keys
|
|
140
|
+
* `BackfillOptions` declares; `tableName`, `indexShards` and the numbers in
|
|
141
|
+
* `retry` by the adapters' rules; `signal` as their methods check it; a
|
|
142
|
+
* `client` providing `scan` and `update`. `options.pageSize` — a positive integer,
|
|
143
|
+
* default 100. `options.cursor` — from a previous run, to resume.
|
|
144
|
+
* `options.maxPages` — how far one run goes, so a large table can be
|
|
145
|
+
* backfilled in bounded slices. `options.indexShards` — must equal the
|
|
146
|
+
* adapters' setting, and has their ceiling. `options.dryRun` — a boolean.
|
|
147
|
+
* `options.signal` — cancels the run; `retry.signal` does so when there is no
|
|
148
|
+
* top-level `signal`, and the top-level one wins when both are given.
|
|
149
|
+
*
|
|
150
|
+
* Returns: how many rows were scanned, how many were given keys and how many
|
|
151
|
+
* were skipped — a row no listing reaches, and a row whose write the condition
|
|
152
|
+
* refused because the row already has keys or is gone — plus a `nextCursor`
|
|
153
|
+
* when the run stopped short of the end. An absent cursor means the table is
|
|
154
|
+
* fully backfilled.
|
|
155
|
+
*
|
|
156
|
+
* Throws: `VALIDATION` naming the offending option, before any DynamoDB
|
|
157
|
+
* call; `RETRY_EXHAUSTED` once a transient failure has used every attempt;
|
|
158
|
+
* `ABORTED` when `signal` fires, or `retry.signal` when no top-level `signal`
|
|
159
|
+
* is given; any other error the scan or the writes throw, wrapped with the
|
|
160
|
+
* code the classifier assigns — this is the function's own error boundary,
|
|
161
|
+
* the same as every adapter's public methods, so a caller's mistake never escapes as a bare
|
|
162
|
+
* exception. A refused write is none of these: it is an outcome for one row,
|
|
163
|
+
* reported in `skipped`.
|
|
164
|
+
*
|
|
165
|
+
* Guarantees: every write is conditional on the row still being there and
|
|
166
|
+
* having no keys yet, so re-running is safe, running against a live table is
|
|
167
|
+
* safe, a row a live adapter has already indexed is left exactly as it is, and
|
|
168
|
+
* a row deleted between the scan and the write is never re-created. Neither
|
|
169
|
+
* refusal stops the run: both mean this run has nothing to do for that row, so
|
|
170
|
+
* the row is counted as skipped and the walk carries on to the rest of the
|
|
171
|
+
* table.
|
|
172
|
+
*/
|
|
173
|
+
async function backfillRecencyIndex(options) {
|
|
174
|
+
return (0, boundary_1.guardPublic)('backfillRecencyIndex', async () => {
|
|
175
|
+
assertBackfillOptions(options);
|
|
176
|
+
const shards = options.indexShards ?? recency_index_1.DEFAULT_INDEX_SHARDS;
|
|
177
|
+
let startKey = options.cursor === undefined ? undefined : decodeScanCursor(options.cursor);
|
|
178
|
+
let scanned = 0;
|
|
179
|
+
let indexed = 0;
|
|
180
|
+
for (let page = 1;; page++) {
|
|
181
|
+
const result = await backfillPage(options, shards, startKey);
|
|
182
|
+
scanned += result.rows;
|
|
183
|
+
indexed += result.indexed;
|
|
184
|
+
startKey = result.nextKey;
|
|
185
|
+
if (startKey === undefined)
|
|
186
|
+
break;
|
|
187
|
+
if (options.maxPages !== undefined && page >= options.maxPages) {
|
|
188
|
+
return {
|
|
189
|
+
scanned,
|
|
190
|
+
indexed,
|
|
191
|
+
skipped: scanned - indexed,
|
|
192
|
+
nextCursor: encodeScanCursor(startKey),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { scanned, indexed, skipped: scanned - indexed };
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Which rows the index covers: each adapter answers for its own, and no row belongs to two.
|
|
201
|
+
*
|
|
202
|
+
* Accepts: `row` — any row a table scan returns, including a foreign one and
|
|
203
|
+
* one whose `PK`/`SK` are not strings.
|
|
204
|
+
*
|
|
205
|
+
* Returns: the index identity, or undefined for a row no listing reaches — a
|
|
206
|
+
* foreign row, a payload or write row, a META row carrying no `checkpointId`.
|
|
207
|
+
*
|
|
208
|
+
* Throws: nothing. A backfill walks the whole table; one unrecognised row must
|
|
209
|
+
* be skipped, not fatal.
|
|
210
|
+
*/
|
|
211
|
+
function indexTargetOf(row) {
|
|
212
|
+
return (0, rows_1.checkpointIndexTarget)(row) ?? (0, rows_2.storeIndexTarget)(row) ?? (0, session_1.sessionIndexTarget)(row);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A scan position, as an opaque string.
|
|
216
|
+
*
|
|
217
|
+
* Accepts: `key` — a `LastEvaluatedKey` from the scan being resumed.
|
|
218
|
+
*
|
|
219
|
+
* Returns: it base64url-encoded. Opaque to the caller: its shape is not a
|
|
220
|
+
* promise, which is what leaves the encoding free to change.
|
|
221
|
+
*
|
|
222
|
+
* Throws: nothing.
|
|
223
|
+
*/
|
|
224
|
+
function encodeScanCursor(key) {
|
|
225
|
+
return Buffer.from(JSON.stringify(key), 'utf8').toString('base64url');
|
|
226
|
+
}
|
|
227
|
+
/** Whether `value` is exactly the base table's primary key: `PK` and `SK`, both strings, nothing else. */
|
|
228
|
+
function isTableKeyShape(value) {
|
|
229
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
230
|
+
return false;
|
|
231
|
+
const keys = Object.keys(value);
|
|
232
|
+
return keys.length === 2 && typeof value.PK === 'string' && typeof value.SK === 'string';
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The scan position a cursor encodes.
|
|
236
|
+
*
|
|
237
|
+
* Accepts: `cursor` — as a previous page returned it.
|
|
238
|
+
*
|
|
239
|
+
* Returns: the `ExclusiveStartKey` to resume from — always exactly `{ PK,
|
|
240
|
+
* SK }`, both strings, since a plain table `Scan` (no `IndexName`) never
|
|
241
|
+
* returns a `LastEvaluatedKey` shaped any other way.
|
|
242
|
+
*
|
|
243
|
+
* Throws: `VALIDATION` naming `cursor` for anything this tool did not
|
|
244
|
+
* issue — text that is not base64url, that does not decode to JSON, or that
|
|
245
|
+
* decodes to anything but `{ PK: string, SK: string }`: an array, an object
|
|
246
|
+
* missing either key, carrying an extra one, or carrying a non-string value
|
|
247
|
+
* for either. A cursor is fed straight back to DynamoDB as
|
|
248
|
+
* `ExclusiveStartKey`, so a value of the wrong shape is refused here rather
|
|
249
|
+
* than surfacing as a raw `ValidationException` from the service.
|
|
250
|
+
*/
|
|
251
|
+
function decodeScanCursor(cursor) {
|
|
252
|
+
try {
|
|
253
|
+
const decoded = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'));
|
|
254
|
+
if (!isTableKeyShape(decoded))
|
|
255
|
+
throw new Error('not a scan position');
|
|
256
|
+
return decoded;
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
throw (0, errors_1.validationError)('cursor is not one this tool issued', 'cursor');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* The keys of {@link BackfillOptions}, exhaustive in both directions —
|
|
264
|
+
* `allKeysOf<T>` fails to compile if this list omits or invents one.
|
|
265
|
+
*/
|
|
266
|
+
const BACKFILL_KEYS = (0, option_shape_1.allKeysOf)({
|
|
267
|
+
client: 'client',
|
|
268
|
+
tableName: 'tableName',
|
|
269
|
+
indexShards: 'indexShards',
|
|
270
|
+
pageSize: 'pageSize',
|
|
271
|
+
maxPages: 'maxPages',
|
|
272
|
+
cursor: 'cursor',
|
|
273
|
+
dryRun: 'dryRun',
|
|
274
|
+
retry: 'retry',
|
|
275
|
+
signal: 'signal',
|
|
276
|
+
});
|
|
277
|
+
/** The `DynamoDBDocument` methods the backfill calls on an injected `client`. */
|
|
278
|
+
const BACKFILL_CLIENT_MEMBERS = ['scan', 'update'];
|
|
279
|
+
/**
|
|
280
|
+
* The keys of {@link RetryOptions}, exhaustive in both directions. Backfill
|
|
281
|
+
* accepts the full retry surface, not the adapters' narrower `RetryPolicy`
|
|
282
|
+
* `assertRetryPolicy` checks — `onRetry` is backfill's only way to observe
|
|
283
|
+
* retries, since it takes no `logger`.
|
|
284
|
+
*
|
|
285
|
+
* `deadlineAt` is the one exclusion: it is an internal per-call bound a write
|
|
286
|
+
* path sets on itself, not something an application names, so it stays an
|
|
287
|
+
* unknown key here and is refused like any other. Excluding it by `Omit`
|
|
288
|
+
* rather than by leaving it out keeps the list exhaustive, so a genuinely new
|
|
289
|
+
* option still fails to compile until it is decided on here.
|
|
290
|
+
*/
|
|
291
|
+
const BACKFILL_RETRY_KEYS = (0, option_shape_1.allKeysOf)({
|
|
292
|
+
maxAttempts: 'maxAttempts',
|
|
293
|
+
baseDelayMs: 'baseDelayMs',
|
|
294
|
+
maxDelayMs: 'maxDelayMs',
|
|
295
|
+
retryableErrors: 'retryableErrors',
|
|
296
|
+
isRetryable: 'isRetryable',
|
|
297
|
+
onRetry: 'onRetry',
|
|
298
|
+
signal: 'signal',
|
|
299
|
+
rng: 'rng',
|
|
300
|
+
});
|
|
301
|
+
/**
|
|
302
|
+
* Validate a `backfillRecencyIndex` retry policy against the full
|
|
303
|
+
* {@link RetryOptions} surface.
|
|
304
|
+
*
|
|
305
|
+
* Accepts: `retry` — must be an object naming only {@link BACKFILL_RETRY_KEYS}.
|
|
306
|
+
* `maxAttempts`/`baseDelayMs`/`maxDelayMs` share the adapters' own bounds
|
|
307
|
+
* ({@link assertRetryBounds}), so backfill and the adapters it feeds cannot
|
|
308
|
+
* drift apart on what a legal value is. `retryableErrors`, when given, must be
|
|
309
|
+
* an array of strings. `isRetryable`, `onRetry` and `rng`, when given, must
|
|
310
|
+
* each be a function. `signal` is checked the same way the top-level
|
|
311
|
+
* `options.signal` is. Either one cancels the run; when both are given the
|
|
312
|
+
* top-level one wins, since the caller's own signal is meant to cancel the
|
|
313
|
+
* whole operation.
|
|
314
|
+
*
|
|
315
|
+
* Returns: nothing: the value is kept under its declared type, and this
|
|
316
|
+
* checks it.
|
|
317
|
+
*
|
|
318
|
+
* Throws: `VALIDATION` naming `retry`, `retry.<numeric key>`,
|
|
319
|
+
* `retry.retryableErrors`, `retry.isRetryable`, `retry.onRetry`, `retry.rng`
|
|
320
|
+
* or `retry.signal`.
|
|
321
|
+
*/
|
|
322
|
+
function assertBackfillRetryOptions(retry) {
|
|
323
|
+
(0, option_shape_1.assertShape)(retry, BACKFILL_RETRY_KEYS, 'retry');
|
|
324
|
+
(0, options_1.assertRetryBounds)(retry);
|
|
325
|
+
if (retry.retryableErrors !== undefined) {
|
|
326
|
+
(0, primitives_1.assertStringArray)(retry.retryableErrors, 'retry.retryableErrors');
|
|
327
|
+
}
|
|
328
|
+
if (retry.isRetryable !== undefined && typeof retry.isRetryable !== 'function') {
|
|
329
|
+
throw (0, errors_1.validationError)('retry.isRetryable must be a function', 'retry.isRetryable');
|
|
330
|
+
}
|
|
331
|
+
if (retry.onRetry !== undefined && typeof retry.onRetry !== 'function') {
|
|
332
|
+
throw (0, errors_1.validationError)('retry.onRetry must be a function', 'retry.onRetry');
|
|
333
|
+
}
|
|
334
|
+
if (retry.rng !== undefined && typeof retry.rng !== 'function') {
|
|
335
|
+
throw (0, errors_1.validationError)('retry.rng must be a function', 'retry.rng');
|
|
336
|
+
}
|
|
337
|
+
(0, collaborators_1.assertSignalLike)(retry.signal, 'retry.signal');
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Reject a non-integer positive bound, `undefined` left to its own default.
|
|
341
|
+
*
|
|
342
|
+
* Accepts: `value` — `options.pageSize`, `options.maxPages` or
|
|
343
|
+
* `options.indexShards`, as the caller gave it. `field` — what the error
|
|
344
|
+
* names. `max` — an upper bound, when one applies.
|
|
345
|
+
*
|
|
346
|
+
* Returns: nothing: the value is kept under its declared type, and this
|
|
347
|
+
* checks it.
|
|
348
|
+
*
|
|
349
|
+
* Throws: `VALIDATION` naming `field` — including for `null`, which is a
|
|
350
|
+
* caller's explicit (wrong) value, not "unset", so it is refused rather than
|
|
351
|
+
* silently falling through to the default the way `??` alone would.
|
|
352
|
+
*/
|
|
353
|
+
function assertPositiveBound(value, field, max) {
|
|
354
|
+
if (value === undefined)
|
|
355
|
+
return;
|
|
356
|
+
(0, primitives_1.assertInteger)(value, field, max === undefined ? { min: 1 } : { min: 1, max });
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Validate every option `backfillRecencyIndex` reads, before any of them is
|
|
360
|
+
* read for real.
|
|
361
|
+
*
|
|
362
|
+
* Accepts: `options` — must be an object naming only the nine keys
|
|
363
|
+
* {@link BackfillOptions} declares. `tableName` and `client` are required, the
|
|
364
|
+
* rest optional; each, when given, follows the same rule an adapter's own
|
|
365
|
+
* option of the same name does. `tableName` reuses the adapters' own
|
|
366
|
+
* `tableName` validator outright; `indexShards` is held to the adapters'
|
|
367
|
+
* shard cap, `MAX_INDEX_SHARDS`; and `retry` shares its numeric bounds with
|
|
368
|
+
* the adapters' own `retry` validator while accepting the wider surface
|
|
369
|
+
* backfill's `RetryOptions` needs, so a mismatch between backfill and the
|
|
370
|
+
* adapters it feeds cannot drift in on what a bound means.
|
|
371
|
+
*
|
|
372
|
+
* Returns: nothing: the value is kept under its declared type, and this
|
|
373
|
+
* checks it.
|
|
374
|
+
*
|
|
375
|
+
* Throws: `VALIDATION` naming `options.<key>` for an unknown key;
|
|
376
|
+
* `tableName`; `client` or `client.<member>`; `indexShards`, `pageSize` or
|
|
377
|
+
* `maxPages` for a non-positive-integer bound (`indexShards` is additionally
|
|
378
|
+
* capped); `dryRun` for a non-boolean; `retry`/`retry.<key>`; `signal`.
|
|
379
|
+
*/
|
|
380
|
+
function assertBackfillOptions(options) {
|
|
381
|
+
(0, option_shape_1.assertShape)(options, BACKFILL_KEYS, 'options');
|
|
382
|
+
(0, options_1.assertTableName)(options.tableName);
|
|
383
|
+
(0, collaborators_1.assertMembers)(options.client, BACKFILL_CLIENT_MEMBERS, 'client');
|
|
384
|
+
assertPositiveBound(options.indexShards, 'indexShards', recency_index_1.MAX_INDEX_SHARDS);
|
|
385
|
+
assertPositiveBound(options.pageSize, 'pageSize');
|
|
386
|
+
assertPositiveBound(options.maxPages, 'maxPages');
|
|
387
|
+
if (options.dryRun !== undefined && typeof options.dryRun !== 'boolean') {
|
|
388
|
+
throw (0, errors_1.validationError)('dryRun must be a boolean', 'dryRun');
|
|
389
|
+
}
|
|
390
|
+
if (options.retry !== undefined)
|
|
391
|
+
assertBackfillRetryOptions(options.retry);
|
|
392
|
+
(0, collaborators_1.assertSignalLike)(options.signal);
|
|
393
|
+
}
|
|
@@ -1,9 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides what deleting a thread means for the checkpointer's rows.
|
|
3
|
+
*
|
|
4
|
+
* The partition delete itself is shared; what is decided here is which rows of
|
|
5
|
+
* a thread's partition are the checkpointer's to remove, which objects each one
|
|
6
|
+
* names, and which write id pins each delete, so a checkpoint or a pending
|
|
7
|
+
* write rewritten after the read is left alone. A caller names a thread and
|
|
8
|
+
* never learns the row kinds, their sort keys or how a refusal is counted.
|
|
9
|
+
*/
|
|
1
10
|
import type { CheckpointerContext } from '../internal/setup';
|
|
2
11
|
/**
|
|
3
|
-
* Delete
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
12
|
+
* Delete exactly the checkpoint, payload and write rows of one thread that the
|
|
13
|
+
* partition read observed.
|
|
14
|
+
*
|
|
15
|
+
* Accepts: `threadId` — validated like every identifier. `options.signal` —
|
|
16
|
+
* stops the read between pages.
|
|
17
|
+
*
|
|
18
|
+
* Returns: nothing. Deleting a thread that does not exist is not an error:
|
|
19
|
+
* there is simply nothing in the partition.
|
|
20
|
+
*
|
|
21
|
+
* Throws: `VALIDATION` for a malformed `threadId`;
|
|
22
|
+
* `BATCH_WRITE_INCOMPLETE` when a row's delete fails, carrying what did
|
|
23
|
+
* succeed; `ABORTED` when the signal fires, whether between pages or during
|
|
24
|
+
* a row's delete — a cancel is reported as a cancel and never as an incomplete
|
|
25
|
+
* delete, and no further row is issued after it. A refused row is **not** one of
|
|
26
|
+
* those failures and raises nothing: the pin turned it away because it was
|
|
27
|
+
* rewritten after the read, and deleting it would erase a write already
|
|
28
|
+
* acknowledged to its author and release the object that write uploaded, so
|
|
29
|
+
* leaving it is the safe answer rather than a degraded one. The error's two
|
|
30
|
+
* counts are **rows**, not batches — rows deleted and rows attempted, summed
|
|
31
|
+
* across every flush of the pass, with `details.succeededCount` repeating the first
|
|
32
|
+
* and `details.failedChunks` holding each failing row's own error — and its message says so,
|
|
33
|
+
* because a pass that sends one request per row is not a batch that did not
|
|
34
|
+
* drain. Refused rows are in neither count; they are reported at `warn` with
|
|
35
|
+
* their sort keys and counted as skipped. The remedy for a refusal is the same
|
|
36
|
+
* as for a row written after the read: re-run once the thread is quiescent.
|
|
37
|
+
*
|
|
38
|
+
* Guarantees: a row this adapter did not write is left in place and logged, so
|
|
39
|
+
* a shared-table partition is never collaterally wiped. A row written or
|
|
40
|
+
* rewritten after the read is left in place and reported too: every delete is
|
|
41
|
+
* pinned on the id of the write that produced the row it names, so a checkpoint
|
|
42
|
+
* re-put while this runs keeps both its rows and the objects they name, and its
|
|
43
|
+
* pending writes are then left alone with them. A row written before that id
|
|
44
|
+
* existed carries none and is deleted as it always was. A row written at a key
|
|
45
|
+
* the read never saw still survives the pass, which is why the thread should be
|
|
46
|
+
* quiescent.
|
|
7
47
|
*/
|
|
8
|
-
export declare function deleteThread(context: CheckpointerContext, threadId: string
|
|
9
|
-
|
|
48
|
+
export declare function deleteThread(context: CheckpointerContext, threadId: string, options?: {
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
}): Promise<void>;
|