@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,377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hides the recency index (record 8).
|
|
4
|
+
*
|
|
5
|
+
* A row that a cross-partition listing reaches carries two index keys: a
|
|
6
|
+
* partition that hashes its identity onto one of a fixed number of shards, and
|
|
7
|
+
* a sort key that orders it by time. A listing reads every shard at once,
|
|
8
|
+
* merges them newest first, and hands out an opaque cursor that resumes the
|
|
9
|
+
* merge. The shard function, the key format and the merge are decided here.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MAX_INDEX_SHARDS = exports.DEFAULT_INDEX_SHARDS = exports.BACKFILLED_AT = void 0;
|
|
13
|
+
exports.queryRecencyIndex = queryRecencyIndex;
|
|
14
|
+
exports.iterateRecencyIndex = iterateRecencyIndex;
|
|
15
|
+
exports.backfilledAt = backfilledAt;
|
|
16
|
+
exports.indexKeys = indexKeys;
|
|
17
|
+
exports.indexPartitions = indexPartitions;
|
|
18
|
+
exports.shardReader = shardReader;
|
|
19
|
+
exports.readShardPage = readShardPage;
|
|
20
|
+
const concurrency_1 = require("../concurrency");
|
|
21
|
+
const errors_1 = require("../errors/errors");
|
|
22
|
+
const primitives_1 = require("../validation/primitives");
|
|
23
|
+
const paginate_1 = require("./paginate");
|
|
24
|
+
const retry_1 = require("./retry");
|
|
25
|
+
const table_schema_1 = require("./table-schema");
|
|
26
|
+
/**
|
|
27
|
+
* A cursor is the sort key of the last row handed out.
|
|
28
|
+
*
|
|
29
|
+
* That is all it needs to be: `gsi1sk` is `<timestamp>#<id>`, which is unique
|
|
30
|
+
* and totally ordered, so the next page is simply "everything below this". It
|
|
31
|
+
* is also why the cursor is not a `LastEvaluatedKey` — one per shard would have
|
|
32
|
+
* to be carried, and a shard count change would silently invalidate them.
|
|
33
|
+
* Opaque to the caller all the same: its shape is not a promise.
|
|
34
|
+
*
|
|
35
|
+
* The key handed here is always the last row {@link takeNewest} chose, and
|
|
36
|
+
* that is the only reason the cursor is sound: the merge hands rows out in
|
|
37
|
+
* descending {@link compareSortKeys} order, so the last one is the smallest
|
|
38
|
+
* key on the page in the server's own order, which is exactly what
|
|
39
|
+
* `#sk < :before` resumes below. There is no second comparison to keep in step
|
|
40
|
+
* — one comparator decides the order, and the cursor is a row it chose.
|
|
41
|
+
*/
|
|
42
|
+
function encodeCursor(sortKey) {
|
|
43
|
+
return Buffer.from(sortKey, 'utf8').toString('base64url');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The sort key a cursor encodes.
|
|
47
|
+
*
|
|
48
|
+
* Accepts: `cursor` — as a previous page returned it.
|
|
49
|
+
*
|
|
50
|
+
* Returns: the `gsi1sk` to resume below.
|
|
51
|
+
*
|
|
52
|
+
* Throws: `VALIDATION` naming `cursor` when the decoded value carries no
|
|
53
|
+
* `#`. `gsi1sk` is `<timestamp>#<id>`, so such a value was issued by something
|
|
54
|
+
* else — a scan cursor, a page token from another API — and using it as a bound
|
|
55
|
+
* would quietly return the wrong page rather than say so. A value that carries
|
|
56
|
+
* a `#` is not checked further.
|
|
57
|
+
*/
|
|
58
|
+
function decodeCursor(cursor) {
|
|
59
|
+
const decoded = Buffer.from(cursor, 'base64url').toString('utf8');
|
|
60
|
+
if (!decoded.includes('#')) {
|
|
61
|
+
throw (0, errors_1.validationError)('cursor is not one this adapter issued', 'cursor');
|
|
62
|
+
}
|
|
63
|
+
return decoded;
|
|
64
|
+
}
|
|
65
|
+
/** A shard with no row to offer that may still hold one. */
|
|
66
|
+
function isDry(reader) {
|
|
67
|
+
return reader.buffer.length === 0 && !reader.exhausted;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read the next page of every dry shard, at most `concurrency` at once, until
|
|
71
|
+
* no shard is dry. A page can hold no rows and still carry a key, and a shard
|
|
72
|
+
* in that state may hold the newest row of all, so choosing a row before it is
|
|
73
|
+
* read again could put an older row on the page first.
|
|
74
|
+
*
|
|
75
|
+
* The loop carries no iteration cap of its own, and that is a decision rather
|
|
76
|
+
* than an omission. Every pass calls {@link readShardPage} on every dry shard,
|
|
77
|
+
* and that call either advances the shard or, once the shard has read
|
|
78
|
+
* `MAX_LOOP_ITERATIONS` pages, throws `RESULT_TRUNCATED` without issuing a
|
|
79
|
+
* query — so a shard that answers with empty pages forever ends the listing
|
|
80
|
+
* there. A second cap here could only ever fire after that one, which makes it
|
|
81
|
+
* a branch no test could reach: {@link mapWithConcurrency}'s own floor (in
|
|
82
|
+
* `shared/concurrency.ts`) never starts zero workers, even for a
|
|
83
|
+
* non-integer or zero `concurrency`, so a pass here always advances at least
|
|
84
|
+
* one dry shard or reads nothing because none is dry. A collaborator that
|
|
85
|
+
* could silently spin without reading anything belongs fixed at that floor,
|
|
86
|
+
* not papered over by a cap here.
|
|
87
|
+
*/
|
|
88
|
+
async function refillDryShards(options, readers, before, needed) {
|
|
89
|
+
for (let dry = readers.filter(isDry); dry.length > 0; dry = readers.filter(isDry)) {
|
|
90
|
+
await (0, concurrency_1.mapWithConcurrency)(dry, options.concurrency, (reader) => readShardPage(options, reader, before, needed));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Move the newest buffered row off its shard; undefined when every buffer is
|
|
95
|
+
* empty.
|
|
96
|
+
*
|
|
97
|
+
* "Newest" is {@link compareSortKeys}, not `>`: the row this picks is the one
|
|
98
|
+
* the resumed `#sk < :before` query will agree is newest, and the two orders
|
|
99
|
+
* part company at an astral id. `''` is a safe starting bound because a
|
|
100
|
+
* DynamoDB key attribute is never the empty string, so no row can lose to it.
|
|
101
|
+
*/
|
|
102
|
+
function takeNewest(readers) {
|
|
103
|
+
let newest;
|
|
104
|
+
let newestKey = '';
|
|
105
|
+
for (const reader of readers) {
|
|
106
|
+
const head = reader.buffer[reader.buffer.length - 1];
|
|
107
|
+
if (head !== undefined && (0, table_schema_1.compareSortKeys)(head.gsi1sk, newestKey) > 0) {
|
|
108
|
+
newest = reader;
|
|
109
|
+
newestKey = head.gsi1sk;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return newest?.buffer.pop();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read one page of a recency listing from the index, newest first.
|
|
116
|
+
*
|
|
117
|
+
* Each shard is read one DynamoDB page at a time and the pages are merged row
|
|
118
|
+
* by row: the newest buffered row goes onto the page, and a shard whose buffer
|
|
119
|
+
* runs dry reads its next page before another row is chosen. That is correct
|
|
120
|
+
* because each shard is already sorted and no row is chosen while a shard that
|
|
121
|
+
* may hold a newer one is unread. It is also what bounds memory: a listing
|
|
122
|
+
* holds the page it is building, up to `limit` rows, plus at most one DynamoDB
|
|
123
|
+
* page per shard, and a shard none of whose buffered rows the page takes is
|
|
124
|
+
* never followed. The price is that a dry shard is read again whenever the page
|
|
125
|
+
* still needs a row, even when every row still to come is another shard's,
|
|
126
|
+
* which can cost a query per shard per page whose rows the page never takes.
|
|
127
|
+
* The alternative — one query over an unsharded index — would make every
|
|
128
|
+
* listing hit one partition, which is what the sharding exists to avoid.
|
|
129
|
+
*
|
|
130
|
+
* This replaces a full-table `Scan` with a `FilterExpression`, which consumed
|
|
131
|
+
* read capacity for every row *evaluated*, collected the whole table in memory
|
|
132
|
+
* and sorted it there.
|
|
133
|
+
*
|
|
134
|
+
* Accepts: `limit` — a `PageLimit`, already checked against the package-wide
|
|
135
|
+
* page rule by the caller's parser. `0` returns an empty page with no cursor
|
|
136
|
+
* and issues no query — and is answered here rather than left to the merge,
|
|
137
|
+
* where an empty page with shards still unread would have read
|
|
138
|
+
* `items[items.length - 1]` off an empty array to build the cursor. `cursor`
|
|
139
|
+
* — from a previous page, or none to start at the newest. `shards` — must
|
|
140
|
+
* match what the writers used. `concurrency` — how many shards are queried at
|
|
141
|
+
* once.
|
|
142
|
+
*
|
|
143
|
+
* Returns: the page, newest first, and a `nextCursor` exactly while rows may
|
|
144
|
+
* remain: a shard still buffers a row the page did not take, or has not
|
|
145
|
+
* reported its end. A cursor is never withheld while rows remain, and none is
|
|
146
|
+
* issued once every shard has reported its end, even for a page filled
|
|
147
|
+
* exactly. DynamoDB can still report a `LastEvaluatedKey` on a page that ends
|
|
148
|
+
* at a shard's last row, so the page after such a cursor may come back empty.
|
|
149
|
+
*
|
|
150
|
+
* Throws: `VALIDATION` naming `cursor`; `RESULT_TRUNCATED`
|
|
151
|
+
* for a shard whose pages do not end within `MAX_LOOP_ITERATIONS`; whatever
|
|
152
|
+
* the queries throw, including an `ABORTED` error.
|
|
153
|
+
*
|
|
154
|
+
* Guarantees: at most `concurrency` shards are queried at once; each shard is
|
|
155
|
+
* followed across DynamoDB's 1 MB page boundary, but its next page is read only
|
|
156
|
+
* when its buffer is empty and the page still needs a row, so besides the page
|
|
157
|
+
* being built, up to `limit` rows, no more than one DynamoDB page per shard is
|
|
158
|
+
* held at a time.
|
|
159
|
+
*/
|
|
160
|
+
async function queryRecencyIndex(options) {
|
|
161
|
+
if (options.limit === 0)
|
|
162
|
+
return { items: [] };
|
|
163
|
+
const before = options.cursor === undefined ? undefined : decodeCursor(options.cursor);
|
|
164
|
+
const readers = indexPartitions(options.tag, options.shards).map((partition) => shardReader(partition));
|
|
165
|
+
const items = [];
|
|
166
|
+
while (items.length < options.limit) {
|
|
167
|
+
await refillDryShards(options, readers, before, options.limit - items.length);
|
|
168
|
+
const row = takeNewest(readers);
|
|
169
|
+
if (row === undefined)
|
|
170
|
+
break;
|
|
171
|
+
items.push(row);
|
|
172
|
+
}
|
|
173
|
+
// Rows remain when a shard still buffers a row or has not reported its end.
|
|
174
|
+
// Either way the loop stopped on a full page, so the page is non-empty and
|
|
175
|
+
// its last row is the right place to resume.
|
|
176
|
+
const remain = readers.some((reader) => reader.buffer.length > 0 || !reader.exhausted);
|
|
177
|
+
return {
|
|
178
|
+
items,
|
|
179
|
+
...(remain ? { nextCursor: encodeCursor(items[items.length - 1].gsi1sk) } : {}),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/** Rows per page when a caller streams the whole index rather than paging it. */
|
|
183
|
+
const STREAM_PAGE_SIZE = (0, primitives_1.parseLimit)(100, 0);
|
|
184
|
+
/**
|
|
185
|
+
* Every row of one adapter's recency index, newest first, page by page.
|
|
186
|
+
*
|
|
187
|
+
* The streaming counterpart of {@link queryRecencyIndex}, for a caller that
|
|
188
|
+
* consumes rows until it has what it needs and then stops. It replaces a
|
|
189
|
+
* full-table `Scan` whose cost scaled with the table rather than with the
|
|
190
|
+
* answer.
|
|
191
|
+
*
|
|
192
|
+
* Accepts: as {@link queryRecencyIndex}, without `limit` and `cursor` — this
|
|
193
|
+
* walks the whole index, paging internally.
|
|
194
|
+
*
|
|
195
|
+
* Returns: an async generator over every row, newest first. An early `break`
|
|
196
|
+
* fetches no further page, so a caller that needs ten rows of a large index
|
|
197
|
+
* pays for one page.
|
|
198
|
+
*
|
|
199
|
+
* Throws: as {@link queryRecencyIndex}.
|
|
200
|
+
*/
|
|
201
|
+
async function* iterateRecencyIndex(options) {
|
|
202
|
+
let cursor;
|
|
203
|
+
do {
|
|
204
|
+
const page = await queryRecencyIndex({ ...options, limit: STREAM_PAGE_SIZE, cursor });
|
|
205
|
+
for (const item of page.items)
|
|
206
|
+
yield item;
|
|
207
|
+
cursor = page.nextCursor;
|
|
208
|
+
} while (cursor !== undefined);
|
|
209
|
+
}
|
|
210
|
+
/** The time a row that recorded none is indexed at, older than anything indexed since. */
|
|
211
|
+
exports.BACKFILLED_AT = '1970-01-01T00:00:00.000Z';
|
|
212
|
+
/**
|
|
213
|
+
* The time a backfilled row is indexed at.
|
|
214
|
+
*
|
|
215
|
+
* Accepts: `recorded` — the row's own time attribute, whatever it holds.
|
|
216
|
+
*
|
|
217
|
+
* Returns: that time when it is a string, else {@link BACKFILLED_AT}.
|
|
218
|
+
*
|
|
219
|
+
* Throws: nothing.
|
|
220
|
+
*/
|
|
221
|
+
function backfilledAt(recorded) {
|
|
222
|
+
return typeof recorded === 'string' ? recorded : exports.BACKFILLED_AT;
|
|
223
|
+
}
|
|
224
|
+
/** Default number of index partitions per adapter. */
|
|
225
|
+
exports.DEFAULT_INDEX_SHARDS = 8;
|
|
226
|
+
/**
|
|
227
|
+
* The most shards a recency index may have. The indexed read builds every
|
|
228
|
+
* shard's partition key and issues at least one query per shard, so an
|
|
229
|
+
* unbounded value turns a config typo into an unbounded stream of requests and
|
|
230
|
+
* an out-of-memory crash. How many of those queries run at once is
|
|
231
|
+
* `readConcurrency`.
|
|
232
|
+
*/
|
|
233
|
+
exports.MAX_INDEX_SHARDS = 1024;
|
|
234
|
+
/**
|
|
235
|
+
* A stable 32-bit FNV-1a hash of `value`.
|
|
236
|
+
*
|
|
237
|
+
* Deterministic and dependency-free, which is what a shard assignment needs: a
|
|
238
|
+
* row's index entry must be findable and deletable without a scan, so the same
|
|
239
|
+
* id must always map to the same shard — across processes, releases and
|
|
240
|
+
* machines. A cryptographic hash would cost more per write for a property
|
|
241
|
+
* nothing here depends on.
|
|
242
|
+
*/
|
|
243
|
+
function fnv1a(value) {
|
|
244
|
+
let hash = 0x811c9dc5;
|
|
245
|
+
for (let i = 0; i < value.length; i++) {
|
|
246
|
+
hash ^= value.charCodeAt(i);
|
|
247
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
248
|
+
}
|
|
249
|
+
return hash >>> 0;
|
|
250
|
+
}
|
|
251
|
+
/** Refuse a shard count that would make the index unusable in either direction. */
|
|
252
|
+
function assertShardCount(shards) {
|
|
253
|
+
if (!Number.isInteger(shards) || shards < 1) {
|
|
254
|
+
throw (0, errors_1.validationError)(`indexShards must be a positive integer (received ${shards}); a non-positive value would ` +
|
|
255
|
+
'make every row share one index partition or produce an unusable key', 'indexShards');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* The GSI1 keys for a row that takes part in cross-partition listing.
|
|
260
|
+
*
|
|
261
|
+
* The partition key is the adapter tag plus a shard, because an index keyed by
|
|
262
|
+
* the tag alone is one partition per adapter — a single hot partition, which is
|
|
263
|
+
* worse than the table scan it replaces. AWS names the sharding requirement
|
|
264
|
+
* directly: mapping one identifier onto one partition key "will quickly create
|
|
265
|
+
* partition hot spots", and the answer is a secondary sharding model
|
|
266
|
+
* (https://docs.aws.amazon.com/whitepapers/latest/multi-tenant-saas-storage-strategies/multitenancy-on-dynamodb.html).
|
|
267
|
+
*
|
|
268
|
+
* The sort key leads with an ISO-8601 timestamp, used unparsed: its byte order
|
|
269
|
+
* already is its chronological order, so a recency listing is a key condition
|
|
270
|
+
* rather than an in-memory sort. The row's own id follows it, which makes the
|
|
271
|
+
* key total — two rows written in the same millisecond still order, so a cursor
|
|
272
|
+
* can never loop.
|
|
273
|
+
*
|
|
274
|
+
* Accepts: `tag` — the adapter's. `id` — the row's own identifier, which
|
|
275
|
+
* decides its shard and breaks ties in the sort key. `at` — an ISO-8601
|
|
276
|
+
* instant. `shards` — index partitions per adapter, at least 1; fixed at table
|
|
277
|
+
* creation, since changing it changes every row's shard and requires a
|
|
278
|
+
* backfill.
|
|
279
|
+
*
|
|
280
|
+
* Returns: the two index attributes.
|
|
281
|
+
*
|
|
282
|
+
* Throws: `VALIDATION` naming `indexShards` for a count below 1 — the read
|
|
283
|
+
* side built an empty partition list from such a value and reported an empty
|
|
284
|
+
* table full of rows.
|
|
285
|
+
*
|
|
286
|
+
* Guarantees: the same row always lands on the same shard, so a listing that
|
|
287
|
+
* queries every shard sees every row exactly once.
|
|
288
|
+
*/
|
|
289
|
+
function indexKeys(tag, id, at, shards) {
|
|
290
|
+
assertShardCount(shards);
|
|
291
|
+
return {
|
|
292
|
+
gsi1pk: `${tag}#${fnv1a(id) % shards}`,
|
|
293
|
+
gsi1sk: `${at}#${id}`,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Every index partition of one adapter.
|
|
298
|
+
*
|
|
299
|
+
* Accepts: `shards` — the same count the rows were written with; validated
|
|
300
|
+
* here as it is in {@link indexKeys}, because a listing that silently queried
|
|
301
|
+
* an empty partition list would return nothing for a table full of rows.
|
|
302
|
+
*
|
|
303
|
+
* Returns: one partition key per shard, which a recency listing queries in
|
|
304
|
+
* parallel and merges.
|
|
305
|
+
*
|
|
306
|
+
* Throws: `VALIDATION` naming `indexShards`.
|
|
307
|
+
*/
|
|
308
|
+
function indexPartitions(tag, shards) {
|
|
309
|
+
assertShardCount(shards);
|
|
310
|
+
return Array.from({ length: shards }, (_unused, shard) => `${tag}#${shard}`);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* A reader placed before a shard's first page.
|
|
314
|
+
*
|
|
315
|
+
* Accepts: `partition` — the shard's index partition key.
|
|
316
|
+
*
|
|
317
|
+
* Returns: a reader with an empty buffer that is not exhausted, so a listing
|
|
318
|
+
* reads its first page before choosing any row.
|
|
319
|
+
*
|
|
320
|
+
* Throws: nothing.
|
|
321
|
+
*/
|
|
322
|
+
function shardReader(partition) {
|
|
323
|
+
return { partition, buffer: [], startKey: undefined, exhausted: false, pages: 0 };
|
|
324
|
+
}
|
|
325
|
+
/** The `Query` for one page of one shard. */
|
|
326
|
+
function shardQuery(options, reader, before, limit) {
|
|
327
|
+
return {
|
|
328
|
+
TableName: options.tableName,
|
|
329
|
+
IndexName: options.indexName,
|
|
330
|
+
KeyConditionExpression: before === undefined ? '#pk = :pk' : '#pk = :pk AND #sk < :before',
|
|
331
|
+
ExpressionAttributeNames: {
|
|
332
|
+
'#pk': 'gsi1pk',
|
|
333
|
+
...(before === undefined ? {} : { '#sk': 'gsi1sk' }),
|
|
334
|
+
},
|
|
335
|
+
ExpressionAttributeValues: {
|
|
336
|
+
':pk': reader.partition,
|
|
337
|
+
...(before === undefined ? {} : { ':before': before }),
|
|
338
|
+
},
|
|
339
|
+
ScanIndexForward: false,
|
|
340
|
+
Limit: limit,
|
|
341
|
+
...(reader.startKey === undefined ? {} : { ExclusiveStartKey: reader.startKey }),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Read a shard's next DynamoDB page into its buffer.
|
|
346
|
+
*
|
|
347
|
+
* `Limit` bounds the items a `Query` *evaluates*, and a page also stops at
|
|
348
|
+
* 1 MB, so a shard of large rows answers with fewer than `limit` items and a
|
|
349
|
+
* `LastEvaluatedKey`. Taking that short page as the whole shard would drop
|
|
350
|
+
* rows and report the listing complete. The key is kept here
|
|
351
|
+
* instead, and the listing reads the next page once the shard's buffer is empty
|
|
352
|
+
* and its page still needs a row. One page at a time is what bounds a listing's
|
|
353
|
+
* memory to at most one DynamoDB page per shard, besides the page it is
|
|
354
|
+
* building.
|
|
355
|
+
*
|
|
356
|
+
* Accepts: `reader` — its buffer empty and the shard not exhausted. `before` —
|
|
357
|
+
* the sort key to read below, or none for the newest. `limit` — the rows the
|
|
358
|
+
* listing's page still needs, at least 1; the shard cannot contribute more.
|
|
359
|
+
*
|
|
360
|
+
* Returns: nothing. The reader's buffer holds the page's rows, and its key,
|
|
361
|
+
* `exhausted` and page count describe what is left.
|
|
362
|
+
*
|
|
363
|
+
* Throws: `RESULT_TRUNCATED` naming `maxIterations`, without issuing
|
|
364
|
+
* a query, when the shard has already read {@link MAX_LOOP_ITERATIONS} pages —
|
|
365
|
+
* a listing fails rather than hand back a partial shard; whatever the query
|
|
366
|
+
* throws, including an `ABORTED` error.
|
|
367
|
+
*/
|
|
368
|
+
async function readShardPage(options, reader, before, limit) {
|
|
369
|
+
if (reader.pages >= paginate_1.MAX_LOOP_ITERATIONS) {
|
|
370
|
+
throw (0, errors_1.resultTruncatedError)('maxIterations', paginate_1.MAX_LOOP_ITERATIONS);
|
|
371
|
+
}
|
|
372
|
+
const result = await (0, retry_1.withDynamoDBRetry)((request) => options.client.query(shardQuery(options, reader, before, limit), request), { ...options.retry, signal: options.signal });
|
|
373
|
+
reader.pages += 1;
|
|
374
|
+
reader.buffer = (result.Items ?? []).slice().reverse();
|
|
375
|
+
reader.startKey = result.LastEvaluatedKey;
|
|
376
|
+
reader.exhausted = reader.startKey === undefined;
|
|
377
|
+
}
|
|
@@ -1,18 +1,286 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Hides when and how a failed request is retried (record 14).
|
|
3
|
+
*
|
|
4
|
+
* Which failures are transient — read from an error's whole cause chain, its
|
|
5
|
+
* HTTP status and its retryable trait, and from a cancelled transaction's
|
|
6
|
+
* reasons — the full-jitter backoff schedule, the attempt budget and the
|
|
7
|
+
* deadline that can cut it short, and the policy an adapter resolves from its
|
|
8
|
+
* options at construction are one decision. Every DynamoDB call goes through
|
|
9
|
+
* it, and so does an S3 object upload and download; the bucket lifecycle calls
|
|
10
|
+
* (`maxAttempts: 1` on the S3 client) and orphan release, which retries on its
|
|
11
|
+
* own loop, do not.
|
|
12
|
+
*/
|
|
13
|
+
import type { Logger } from '../logging/logger';
|
|
14
|
+
/** Starting delay for UnprocessedItems / UnprocessedKeys backoff loops. */
|
|
15
|
+
export declare const INITIAL_BACKOFF_DELAY_MS = 100;
|
|
16
|
+
/** Maximum backoff delay for retry loops. */
|
|
17
|
+
export declare const MAX_BACKOFF_DELAY_MS = 5000;
|
|
18
|
+
/** Default maximum attempts for transient-error retries. */
|
|
19
|
+
export declare const DEFAULT_RETRY_MAX_ATTEMPTS = 5;
|
|
20
|
+
/**
|
|
21
|
+
* How long DynamoDB treats a repeated client request token as the same request
|
|
22
|
+
* rather than a new one, so re-sending a tokened write is deduplicated instead
|
|
23
|
+
* of applied twice (10 minutes). Recorded as its own constant so the margin
|
|
24
|
+
* {@link MAX_WRITE_LIFETIME_MS} keeps under it is legible.
|
|
25
|
+
*/
|
|
26
|
+
export declare const TOKEN_IDEMPOTENCY_WINDOW_MS = 600000;
|
|
27
|
+
/**
|
|
28
|
+
* Longest one token-carrying write may keep retrying (5 minutes): half of
|
|
29
|
+
* {@link TOKEN_IDEMPOTENCY_WINDOW_MS}. The other half absorbs the attempt
|
|
30
|
+
* still in flight when the budget ends, clock skew between this client's own
|
|
31
|
+
* clock and DynamoDB's timer, and SDK-internal queueing, so a write that
|
|
32
|
+
* retries to the end still finishes well inside the window its token is
|
|
33
|
+
* honoured for. Its own literal rather than a division of the window:
|
|
34
|
+
* aliasing them would move one whenever the other is retuned (see
|
|
35
|
+
* `LIST_SCAN_WARN_THRESHOLD` (`src/shared/dynamodb/paginate.ts`)).
|
|
36
|
+
*/
|
|
37
|
+
export declare const MAX_WRITE_LIFETIME_MS = 300000;
|
|
38
|
+
/**
|
|
39
|
+
* The per-request options one attempt hands to the SDK call it makes.
|
|
40
|
+
*
|
|
41
|
+
* It is the AWS SDK's own second argument (`HttpHandlerOptions` from
|
|
42
|
+
* `@smithy/types`) narrowed to the single field this library sets, so a call
|
|
43
|
+
* site forwards the value it was given instead of assembling one — the
|
|
44
|
+
* difference between `client.get(params, request)` at every site and thirty
|
|
45
|
+
* chances to write `{ signal }` where the SDK reads `abortSignal`.
|
|
46
|
+
*
|
|
47
|
+
* `DynamoDBDocumentLike` picks its members off the real `DynamoDBDocument`, so
|
|
48
|
+
* every method already accepts this as its optional second argument and no
|
|
49
|
+
* type had to move to make room for it.
|
|
50
|
+
*/
|
|
51
|
+
export interface SdkRequestOptions {
|
|
52
|
+
abortSignal?: AbortSignal;
|
|
53
|
+
}
|
|
54
|
+
/** What {@link RetryOptions.onRetry} learns before each backoff sleep. */
|
|
55
|
+
export interface RetryAttemptInfo {
|
|
56
|
+
attempt: number;
|
|
57
|
+
delayMs: number;
|
|
58
|
+
error: Error;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* How a failed request is retried: how many attempts, how long each wait, and
|
|
62
|
+
* which failures qualify.
|
|
63
|
+
*/
|
|
2
64
|
export interface RetryOptions {
|
|
3
65
|
maxAttempts?: number;
|
|
4
66
|
baseDelayMs?: number;
|
|
5
67
|
maxDelayMs?: number;
|
|
6
68
|
retryableErrors?: readonly string[];
|
|
69
|
+
/**
|
|
70
|
+
* Decides retryability instead of `retryableErrors`: called with each failed
|
|
71
|
+
* attempt's error, it retries when it returns `true`.
|
|
72
|
+
*/
|
|
73
|
+
isRetryable?: (error: Error) => boolean;
|
|
74
|
+
/** Called before every backoff sleep, so retries are visible before the budget is exhausted. */
|
|
75
|
+
onRetry?: (info: RetryAttemptInfo) => void;
|
|
7
76
|
signal?: AbortSignal;
|
|
8
77
|
rng?: () => number;
|
|
9
78
|
}
|
|
10
79
|
/**
|
|
11
|
-
* Run `fn`, retrying
|
|
12
|
-
*
|
|
13
|
-
* {@link
|
|
80
|
+
* Run `fn`, retrying transient failures with full-jitter exponential backoff.
|
|
81
|
+
*
|
|
82
|
+
* Accepts: `fn` — given the {@link SdkRequestOptions} for the attempt, to pass
|
|
83
|
+
* as the second argument of the SDK call it makes. That argument is what
|
|
84
|
+
* carries `options.signal` into the request, and it is the only way a call
|
|
85
|
+
* site can: `fn` closes over its own parameters, so nothing else reaches it.
|
|
86
|
+
* An `fn` that makes no cancellable call ignores the parameter and is written
|
|
87
|
+
* exactly as it was, since a zero-argument function still satisfies the type.
|
|
88
|
+
*
|
|
89
|
+
* Accepts: `options.maxAttempts` — total attempts including the first, default
|
|
90
|
+
* {@link DEFAULT_RETRY_MAX_ATTEMPTS}; at least 1, which `assertRetryPolicy`
|
|
91
|
+
* enforces for every caller-supplied policy. `options.baseDelayMs` /
|
|
92
|
+
* `maxDelayMs` — the backoff schedule. `options.isRetryable` — replaces
|
|
93
|
+
* `retryableErrors` entirely, so a call site can share one classifier with
|
|
94
|
+
* paths that do not go through here. `options.signal` — checked before the
|
|
95
|
+
* first attempt, handed to every attempt as `abortSignal` so the request in
|
|
96
|
+
* flight is cancelled rather than merely awaited, checked again when an
|
|
97
|
+
* attempt fails, and honoured during every backoff wait. `options.onRetry` —
|
|
98
|
+
* called synchronously before each wait; an exception from it is not caught
|
|
99
|
+
* and ends the operation. `options.deadlineAt` — an internal bound on the
|
|
100
|
+
* whole budget rather than on one attempt: the wait that would carry the
|
|
101
|
+
* operation past it is never started, and the budget ends there instead.
|
|
102
|
+
* Without it the schedule, the attempt count and every error are unchanged.
|
|
103
|
+
*
|
|
104
|
+
* Returns: whatever `fn` resolves to, from the first attempt that succeeds.
|
|
105
|
+
*
|
|
106
|
+
* Throws: the error itself, unchanged, when it is not retryable — a
|
|
107
|
+
* `ValidationException` or a permission failure is never retried;
|
|
108
|
+
* `ABORTED` when the signal fires, including during a wait and
|
|
109
|
+
* including while a request is in flight — the SDK rejects the cancelled
|
|
110
|
+
* request with an error of its own, and a failed attempt whose signal has
|
|
111
|
+
* fired is reported as the cancel it is rather than being classified, retried
|
|
112
|
+
* or wrapped; `RETRY_EXHAUSTED` once the budget ends, carrying the attempt
|
|
113
|
+
* actually reached — not the attempts configured — and the last error as
|
|
114
|
+
* `cause`. Its message quotes the last error **redacted**, because it reaches
|
|
115
|
+
* `err.message`, which an application may print without a redacting logger.
|
|
116
|
+
*
|
|
117
|
+
* A deadline that ends the budget is reported exactly as a spent one, by the
|
|
118
|
+
* same error with the same code: a caller cannot tell the two apart, and
|
|
119
|
+
* nothing needs to, since the handling of both is identical — read the row
|
|
120
|
+
* back, and release only what is confirmed not to have landed.
|
|
121
|
+
*
|
|
122
|
+
* A cancelled wait is also an abort no longer observed. The signal is read
|
|
123
|
+
* before the first attempt, after every failed one, and inside each wait, so
|
|
124
|
+
* ending the budget in place of a wait drops only that last observation point:
|
|
125
|
+
* a signal that fires *after* the deadline has already refused the wait, in
|
|
126
|
+
* the window where the wait would have been running, surfaces as
|
|
127
|
+
* `RETRY_EXHAUSTED` rather than `ABORTED`. One already set
|
|
128
|
+
* at entry, fired during an attempt, or fired during an earlier wait, is still
|
|
129
|
+
* caught.
|
|
130
|
+
*
|
|
131
|
+
* Guarantees: `fn` is called at least once and at most `maxAttempts` times. A
|
|
132
|
+
* thrown non-`Error` is wrapped, so what a caller catches is always an `Error`.
|
|
133
|
+
*/
|
|
134
|
+
export declare function withRetry<T>(fn: (request: SdkRequestOptions) => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
135
|
+
/**
|
|
136
|
+
* {@link withRetry} with this package's DynamoDB defaults.
|
|
137
|
+
*
|
|
138
|
+
* Accepts: `overrides` — merged over `maxAttempts:`
|
|
139
|
+
* {@link DEFAULT_RETRY_MAX_ATTEMPTS}, so an adapter's resolved policy wins.
|
|
140
|
+
*
|
|
141
|
+
* Returns: as {@link withRetry}.
|
|
142
|
+
*
|
|
143
|
+
* Throws: as {@link withRetry}.
|
|
144
|
+
*/
|
|
145
|
+
export declare function withDynamoDBRetry<T>(fn: (request: SdkRequestOptions) => Promise<T>, overrides?: Partial<RetryOptions>): Promise<T>;
|
|
146
|
+
/**
|
|
147
|
+
* Whether `error`, or any cause in its chain, is transient.
|
|
148
|
+
*
|
|
149
|
+
* Accepts: `error` — an `Error`; its `cause` chain is walked to
|
|
150
|
+
* {@link MAX_CAUSE_DEPTH}, and a cycle in it terminates the walk rather than
|
|
151
|
+
* looping. Anything else a `throw` can produce carries no node to walk and is
|
|
152
|
+
* not retryable. `retryableErrors` — the signal tokens to match; an empty list
|
|
153
|
+
* still admits the trait and status rules below.
|
|
154
|
+
*
|
|
155
|
+
* Returns: true when any of these holds, in this order —
|
|
156
|
+
* 1. the error is a transaction cancellation and **every** reason it carries is
|
|
157
|
+
* transient. This verdict is final either way: a permanent reason arrives
|
|
158
|
+
* with the same HTTP status as a transient one, so the later rules cannot be
|
|
159
|
+
* allowed to overturn it. A cancellation carrying no reasons is not retried.
|
|
160
|
+
* 2. any node carries the SDK's `$retryable` trait;
|
|
161
|
+
* 3. any node's HTTP status is in {@link TRANSIENT_HTTP_STATUSES} — which is
|
|
162
|
+
* what classifies a failure the SDK could not map to a modeled exception,
|
|
163
|
+
* arriving as `name: 'Unknown'` with only a status;
|
|
164
|
+
* 4. any node's `name`, `code`, `errno` or `syscall` equals a token in
|
|
165
|
+
* `retryableErrors`.
|
|
166
|
+
*
|
|
167
|
+
* The token match is exact, never substring: these fields are whole tokens, and
|
|
168
|
+
* a substring rule would let an unrelated name that merely contains one ride
|
|
169
|
+
* along.
|
|
170
|
+
*
|
|
171
|
+
* Throws: **nothing**, for any value a `throw` can produce — see
|
|
172
|
+
* {@link transientCancellation}, which the first rule reads through.
|
|
173
|
+
*/
|
|
174
|
+
export declare function isRetryableError(error: Error, retryableErrors: readonly string[]): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Caller-facing retry tunables for every DynamoDB call an adapter makes. The
|
|
177
|
+
* schedule is full-jitter exponential backoff: `baseDelayMs` doubling per
|
|
178
|
+
* attempt, capped at `maxDelayMs`, for `maxAttempts` attempts. The
|
|
179
|
+
* message-append path never goes below its own contention floor.
|
|
180
|
+
*/
|
|
181
|
+
export interface RetryPolicy {
|
|
182
|
+
/** Attempts per call before `RETRY_EXHAUSTED` (default 5). */
|
|
183
|
+
maxAttempts?: number;
|
|
184
|
+
/** First backoff delay in milliseconds (default 100). */
|
|
185
|
+
baseDelayMs?: number;
|
|
186
|
+
/** Cap on a single backoff delay in milliseconds (default 5000). */
|
|
187
|
+
maxDelayMs?: number;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Resolve an adapter's retry policy once, at construction.
|
|
191
|
+
*
|
|
192
|
+
* Accepts: `policy` — the caller's, already validated, or nothing. `logger` —
|
|
193
|
+
* the adapter's resolved logger.
|
|
194
|
+
*
|
|
195
|
+
* Returns: the options every DynamoDB call of that adapter uses, with each
|
|
196
|
+
* field defaulted and the logger attached, so every retry is visible at `debug`
|
|
197
|
+
* (the attempt, the delay about to be slept, the error's name) instead of only
|
|
198
|
+
* surfacing once the budget is exhausted.
|
|
199
|
+
*
|
|
200
|
+
* Accepts: `attemptFloor` — the lowest attempt count this adapter will actually
|
|
201
|
+
* use, when it raises a caller's below its own. The budget is warned about at
|
|
202
|
+
* that number rather than at the caller's, because it is the one the writes
|
|
203
|
+
* will really spend; an adapter that honours the caller's count passes none.
|
|
204
|
+
*
|
|
205
|
+
* Throws: nothing; the policy was validated where it was given. A policy whose
|
|
206
|
+
* nominal budget outlives {@link MAX_WRITE_LIFETIME_MS} is warned about rather
|
|
207
|
+
* than refused, once per adapter constructed — three adapters built from one
|
|
208
|
+
* long policy each say so for themselves — see
|
|
209
|
+
* {@link warnIfOutlivesWriteLifetime}. The defaults are far inside it and say
|
|
210
|
+
* nothing.
|
|
211
|
+
*/
|
|
212
|
+
export declare function resolveRetryPolicy(policy: RetryPolicy | undefined, logger: Logger, attemptFloor?: number): RetryOptions;
|
|
213
|
+
/**
|
|
214
|
+
* The context's retry options plus a per-call cancellation signal.
|
|
215
|
+
*
|
|
216
|
+
* Accepts: `context.retry` — the adapter's resolved policy. `signal` — the
|
|
217
|
+
* caller's, when the call takes one.
|
|
218
|
+
*
|
|
219
|
+
* Returns: the adapter's options untouched when there is no signal — the same
|
|
220
|
+
* object, so no per-call allocation on the common path — and a copy carrying it
|
|
221
|
+
* when there is.
|
|
222
|
+
*
|
|
223
|
+
* Throws: nothing.
|
|
224
|
+
*/
|
|
225
|
+
export declare function retryFor(context: {
|
|
226
|
+
retry?: RetryOptions;
|
|
227
|
+
}, signal?: AbortSignal): RetryOptions | undefined;
|
|
228
|
+
/**
|
|
229
|
+
* Wait `ms` milliseconds, cancellable.
|
|
230
|
+
*
|
|
231
|
+
* Accepts: `ms` — the delay. `signal` — omitted waits uninterruptibly; already
|
|
232
|
+
* aborted rejects before any timer is set; aborting while pending rejects at
|
|
233
|
+
* that moment and clears the timer.
|
|
234
|
+
*
|
|
235
|
+
* Returns: a promise resolving when the delay elapses.
|
|
236
|
+
*
|
|
237
|
+
* Throws: an `ABORTED` error however the signal was aborted —
|
|
238
|
+
* with a `DOMException`, a string or a custom reason (see
|
|
239
|
+
* {@link abortErrorFrom}).
|
|
240
|
+
*
|
|
241
|
+
* Guarantees: exactly one of resolve and reject runs, and neither the timer nor
|
|
242
|
+
* the abort listener outlives the call. The listener is attached before the
|
|
243
|
+
* timer is armed, so a signal whose `addEventListener` throws rejects the wait
|
|
244
|
+
* with nothing left behind — armed first, the timer outlived that rejection
|
|
245
|
+
* and later called `removeEventListener` outside any promise. A listener that
|
|
246
|
+
* runs while it is being attached settles the wait before any timer exists.
|
|
247
|
+
*/
|
|
248
|
+
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
249
|
+
/**
|
|
250
|
+
* The next exponential-backoff delay.
|
|
251
|
+
*
|
|
252
|
+
* Accepts: `currentMs` — the delay just used; at least 1, since doubling 0
|
|
253
|
+
* never grows. `maxMs` — the ceiling, default {@link MAX_BACKOFF_DELAY_MS}.
|
|
254
|
+
*
|
|
255
|
+
* Returns: `min(currentMs * 2, maxMs)`.
|
|
256
|
+
*
|
|
257
|
+
* Throws: nothing.
|
|
258
|
+
*/
|
|
259
|
+
export declare function nextBackoffDelay(currentMs: number, maxMs?: number): number;
|
|
260
|
+
/**
|
|
261
|
+
* AWS's full jitter over a backoff delay.
|
|
262
|
+
*
|
|
263
|
+
* Accepts: `delayMs` — the unjittered delay. `rng` — a seam returning
|
|
264
|
+
* `[0, 1)`, default `Math.random`; tests inject a fixed one.
|
|
265
|
+
*
|
|
266
|
+
* Returns: a value in `[0, delayMs)`, so two clients retrying the same failure
|
|
267
|
+
* do not retry together
|
|
268
|
+
* (https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/).
|
|
269
|
+
*
|
|
270
|
+
* Throws: nothing.
|
|
271
|
+
*/
|
|
272
|
+
export declare function fullJitter(delayMs: number, rng?: () => number): number;
|
|
273
|
+
/**
|
|
274
|
+
* Whether `error` is a transient S3 failure worth retrying.
|
|
275
|
+
*
|
|
276
|
+
* Accepts: `error` — any error, including one carrying no name or code, and
|
|
277
|
+
* equally anything else a `throw` can produce.
|
|
278
|
+
*
|
|
279
|
+
* Returns: {@link isRetryableError} over the shared default tokens, which hold
|
|
280
|
+
* S3's own transient names (`SlowDown`, `InternalError`,
|
|
281
|
+
* `ConditionalRequestConflict`) alongside DynamoDB's — one list, so the two
|
|
282
|
+
* services cannot drift apart on what is transient.
|
|
283
|
+
*
|
|
284
|
+
* Throws: **nothing**, for any value; {@link isRetryableError} is total.
|
|
14
285
|
*/
|
|
15
|
-
export declare function
|
|
16
|
-
/** {@link withRetry} preset for DynamoDB operations. */
|
|
17
|
-
export declare function withDynamoDBRetry<T>(fn: () => Promise<T>, overrides?: Partial<RetryOptions>): Promise<T>;
|
|
18
|
-
//# sourceMappingURL=retry.d.ts.map
|
|
286
|
+
export declare function isTransientS3Error(error: Error): boolean;
|