@farukada/aws-langgraph-dynamodb-ts 1.0.0-rc.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +390 -193
- package/dist/{backfill → cjs/backfill}/backfill.d.ts +15 -12
- package/dist/cjs/backfill/backfill.js +177 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/delete-thread.d.ts +1 -1
- package/dist/cjs/checkpointer/actions/delete-thread.js +26 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/get-tuple.d.ts +4 -3
- package/dist/cjs/checkpointer/actions/get-tuple.js +22 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/list.d.ts +7 -4
- package/dist/cjs/checkpointer/actions/list.js +70 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/put-writes.d.ts +8 -6
- package/dist/cjs/checkpointer/actions/put-writes.js +21 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/put.d.ts +21 -15
- package/dist/cjs/checkpointer/actions/put.js +79 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/delta-history.d.ts +38 -26
- package/dist/cjs/checkpointer/internal/delta-history.js +131 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/listing.d.ts +4 -4
- package/dist/cjs/checkpointer/internal/listing.js +104 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/parse.d.ts +51 -15
- package/dist/cjs/checkpointer/internal/parse.js +184 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/pending-writes.d.ts +64 -25
- package/dist/cjs/checkpointer/internal/pending-writes.js +241 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/read.d.ts +15 -10
- package/dist/cjs/checkpointer/internal/read.js +132 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/rows.d.ts +94 -21
- package/dist/cjs/checkpointer/internal/rows.js +356 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/setup.d.ts +13 -20
- package/dist/cjs/checkpointer/internal/setup.js +25 -0
- package/dist/{checkpointer → cjs/checkpointer}/saver.d.ts +72 -36
- package/dist/cjs/checkpointer/saver.js +56 -0
- package/dist/{checkpointer → cjs/checkpointer}/types.d.ts +1 -1
- package/dist/cjs/checkpointer/types.js +2 -0
- package/dist/{factory → cjs/factory}/factory.d.ts +25 -20
- package/dist/cjs/factory/factory.js +137 -0
- package/dist/{factory → cjs/factory}/types.d.ts +12 -12
- package/dist/cjs/factory/types.js +2 -0
- package/dist/{history → cjs/history}/actions/add-messages.d.ts +18 -10
- package/dist/cjs/history/actions/add-messages.js +17 -0
- package/dist/{history → cjs/history}/actions/clear.d.ts +1 -1
- package/dist/cjs/history/actions/clear.js +29 -0
- package/dist/{history → cjs/history}/actions/get-messages.d.ts +11 -9
- package/dist/cjs/history/actions/get-messages.js +58 -0
- package/dist/{history → cjs/history}/actions/list-sessions.d.ts +3 -3
- package/dist/cjs/history/actions/list-sessions.js +67 -0
- package/dist/{history → cjs/history}/actions/reconcile-count.d.ts +13 -9
- package/dist/cjs/history/actions/reconcile-count.js +8 -0
- package/dist/{history → cjs/history}/chat-message-history.d.ts +62 -30
- package/dist/cjs/history/chat-message-history.js +61 -0
- package/dist/{history → cjs/history}/internal/append.d.ts +64 -32
- package/dist/cjs/history/internal/append.js +267 -0
- package/dist/{history → cjs/history}/internal/message-read.d.ts +3 -3
- package/dist/cjs/history/internal/message-read.js +93 -0
- package/dist/{history → cjs/history}/internal/parse.d.ts +2 -2
- package/dist/cjs/history/internal/parse.js +113 -0
- package/dist/{history → cjs/history}/internal/rows.d.ts +11 -10
- package/dist/cjs/history/internal/rows.js +96 -0
- package/dist/{history → cjs/history}/internal/session.d.ts +41 -22
- package/dist/cjs/history/internal/session.js +296 -0
- package/dist/{history → cjs/history}/internal/setup.d.ts +2 -2
- package/dist/cjs/history/internal/setup.js +60 -0
- package/dist/{history → cjs/history}/session-adapter.d.ts +0 -6
- package/dist/cjs/history/session-adapter.js +38 -0
- package/dist/{history → cjs/history}/types.d.ts +18 -15
- package/dist/cjs/history/types.js +2 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +27 -27
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/package.json +1 -0
- package/dist/{shared → cjs/shared}/adapter.d.ts +27 -16
- package/dist/cjs/shared/adapter.js +70 -0
- package/dist/cjs/shared/clock.js +14 -0
- package/dist/{shared → cjs/shared}/codec/codec.d.ts +37 -20
- package/dist/cjs/shared/codec/codec.js +162 -0
- package/dist/{shared → cjs/shared}/codec/compression.d.ts +9 -4
- package/dist/cjs/shared/codec/compression.js +45 -0
- package/dist/cjs/shared/codec/json-serde.js +58 -0
- package/dist/{shared → cjs/shared}/codec/s3/client-types.d.ts +2 -1
- package/dist/cjs/shared/codec/s3/client-types.js +6 -0
- package/dist/{shared → cjs/shared}/codec/s3/client.d.ts +25 -7
- package/dist/cjs/shared/codec/s3/client.js +78 -0
- package/dist/{shared → cjs/shared}/codec/s3/config.d.ts +12 -7
- package/dist/cjs/shared/codec/s3/config.js +92 -0
- package/dist/{shared → cjs/shared}/codec/s3/lifecycle.d.ts +71 -17
- package/dist/cjs/shared/codec/s3/lifecycle.js +223 -0
- package/dist/{shared → cjs/shared}/codec/s3/offloader.d.ts +42 -29
- package/dist/cjs/shared/codec/s3/offloader.js +289 -0
- package/dist/cjs/shared/concurrency.js +31 -0
- package/dist/{shared → cjs/shared}/dynamodb/abort.d.ts +2 -2
- package/dist/cjs/shared/dynamodb/abort.js +16 -0
- package/dist/{shared → cjs/shared}/dynamodb/batch-write.d.ts +2 -2
- package/dist/cjs/shared/dynamodb/batch-write.js +79 -0
- package/dist/cjs/shared/dynamodb/cancellation.js +37 -0
- package/dist/{shared → cjs/shared}/dynamodb/client.d.ts +24 -22
- package/dist/cjs/shared/dynamodb/client.js +40 -0
- package/dist/{shared → cjs/shared}/dynamodb/idempotent-write.d.ts +64 -19
- package/dist/cjs/shared/dynamodb/idempotent-write.js +173 -0
- package/dist/{shared → cjs/shared}/dynamodb/paginate.d.ts +2 -2
- package/dist/cjs/shared/dynamodb/paginate.js +90 -0
- package/dist/{shared → cjs/shared}/dynamodb/partition-delete.d.ts +6 -6
- package/dist/cjs/shared/dynamodb/partition-delete.js +177 -0
- package/dist/{shared → cjs/shared}/dynamodb/recency-index.d.ts +27 -15
- package/dist/cjs/shared/dynamodb/recency-index.js +146 -0
- package/dist/{shared → cjs/shared}/dynamodb/retry.d.ts +37 -6
- package/dist/cjs/shared/dynamodb/retry.js +193 -0
- package/dist/cjs/shared/dynamodb/row-size.d.ts +33 -0
- package/dist/cjs/shared/dynamodb/row-size.js +30 -0
- package/dist/{shared → cjs/shared}/dynamodb/table-schema.d.ts +27 -18
- package/dist/cjs/shared/dynamodb/table-schema.js +52 -0
- package/dist/{shared → cjs/shared}/errors/base-error.d.ts +42 -7
- package/dist/cjs/shared/errors/base-error.js +73 -0
- package/dist/{shared → cjs/shared}/errors/boundary.d.ts +29 -14
- package/dist/cjs/shared/errors/boundary.js +61 -0
- package/dist/cjs/shared/errors/classify.d.ts +206 -0
- package/dist/cjs/shared/errors/classify.js +232 -0
- package/dist/{shared → cjs/shared}/errors/error-code.d.ts +17 -10
- package/dist/cjs/shared/errors/error-code.js +27 -0
- package/dist/{shared → cjs/shared}/errors/errors.d.ts +75 -9
- package/dist/cjs/shared/errors/errors.js +123 -0
- package/dist/cjs/shared/logging/logger.js +30 -0
- package/dist/{shared → cjs/shared}/logging/redaction.d.ts +8 -4
- package/dist/cjs/shared/logging/redaction.js +145 -0
- package/dist/{shared → cjs/shared}/logging/secret-patterns.d.ts +30 -7
- package/dist/cjs/shared/logging/secret-patterns.js +93 -0
- package/dist/cjs/shared/logging/truncate.js +31 -0
- package/dist/{shared → cjs/shared}/options.d.ts +27 -11
- package/dist/cjs/shared/options.js +2 -0
- package/dist/cjs/shared/ulid.js +83 -0
- package/dist/{shared → cjs/shared}/validation/collaborators.d.ts +21 -2
- package/dist/cjs/shared/validation/collaborators.js +79 -0
- package/dist/{shared → cjs/shared}/validation/option-shape.d.ts +7 -5
- package/dist/cjs/shared/validation/option-shape.js +31 -0
- package/dist/{shared → cjs/shared}/validation/options.d.ts +4 -4
- package/dist/cjs/shared/validation/options.js +166 -0
- package/dist/cjs/shared/validation/primitives.js +114 -0
- package/dist/{shared → cjs/shared}/validation/ttl.d.ts +26 -9
- package/dist/cjs/shared/validation/ttl.js +52 -0
- package/dist/{store → cjs/store}/actions/list-namespaces.d.ts +5 -5
- package/dist/cjs/store/actions/list-namespaces.js +92 -0
- package/dist/{store → cjs/store}/actions/put.d.ts +11 -4
- package/dist/cjs/store/actions/put.js +49 -0
- package/dist/{store → cjs/store}/actions/reconcile-vector-index.d.ts +5 -5
- package/dist/cjs/store/actions/reconcile-vector-index.js +13 -0
- package/dist/{store → cjs/store}/actions/search.d.ts +2 -2
- package/dist/cjs/store/actions/search.js +26 -0
- package/dist/cjs/store/internal/batch-plan.d.ts +56 -0
- package/dist/cjs/store/internal/batch-plan.js +32 -0
- package/dist/{store → cjs/store}/internal/filter.d.ts +3 -3
- package/dist/cjs/store/internal/filter.js +64 -0
- package/dist/cjs/store/internal/get-item.d.ts +77 -0
- package/dist/cjs/store/internal/get-item.js +58 -0
- package/dist/{store → cjs/store}/internal/item-write.d.ts +72 -32
- package/dist/cjs/store/internal/item-write.js +181 -0
- package/dist/{store → cjs/store}/internal/parse.d.ts +15 -10
- package/dist/cjs/store/internal/parse.js +180 -0
- package/dist/{store → cjs/store}/internal/rows.d.ts +38 -34
- package/dist/cjs/store/internal/rows.js +166 -0
- package/dist/{store → cjs/store}/internal/semantic-search.d.ts +2 -2
- package/dist/cjs/store/internal/semantic-search.js +211 -0
- package/dist/{store → cjs/store}/internal/setup.d.ts +10 -15
- package/dist/cjs/store/internal/setup.js +103 -0
- package/dist/{store → cjs/store}/internal/table-search.d.ts +5 -5
- package/dist/cjs/store/internal/table-search.js +123 -0
- package/dist/{store → cjs/store}/internal/vector-index.d.ts +26 -15
- package/dist/cjs/store/internal/vector-index.js +269 -0
- package/dist/{store → cjs/store}/store.d.ts +82 -39
- package/dist/cjs/store/store.js +97 -0
- package/dist/{store → cjs/store}/types.d.ts +25 -10
- package/dist/cjs/store/types.js +2 -0
- package/dist/cjs/store/vector-backend.js +4 -0
- package/dist/esm/backfill/backfill.d.ts +171 -0
- package/dist/esm/backfill/backfill.js +170 -0
- package/dist/{checkpointer/actions/delete-thread.js → esm/checkpointer/actions/delete-thread.d.ts} +4 -26
- package/dist/esm/checkpointer/actions/delete-thread.js +23 -0
- package/dist/{checkpointer/actions/get-tuple.js → esm/checkpointer/actions/get-tuple.d.ts} +7 -24
- package/dist/esm/checkpointer/actions/get-tuple.js +19 -0
- package/dist/esm/checkpointer/actions/list.d.ts +55 -0
- package/dist/esm/checkpointer/actions/list.js +67 -0
- package/dist/{checkpointer/actions/put-writes.js → esm/checkpointer/actions/put-writes.d.ts} +10 -37
- package/dist/esm/checkpointer/actions/put-writes.js +18 -0
- package/dist/esm/checkpointer/actions/put.d.ts +95 -0
- package/dist/esm/checkpointer/actions/put.js +75 -0
- package/dist/esm/checkpointer/internal/delta-history.d.ts +124 -0
- package/dist/esm/checkpointer/internal/delta-history.js +126 -0
- package/dist/{checkpointer/internal/listing.js → esm/checkpointer/internal/listing.d.ts} +22 -118
- package/dist/esm/checkpointer/internal/listing.js +95 -0
- package/dist/esm/checkpointer/internal/parse.d.ts +298 -0
- package/dist/esm/checkpointer/internal/parse.js +169 -0
- package/dist/esm/checkpointer/internal/pending-writes.d.ts +314 -0
- package/dist/esm/checkpointer/internal/pending-writes.js +229 -0
- package/dist/esm/checkpointer/internal/read.d.ts +135 -0
- package/dist/esm/checkpointer/internal/read.js +125 -0
- package/dist/esm/checkpointer/internal/rows.d.ts +644 -0
- package/dist/esm/checkpointer/internal/rows.js +323 -0
- package/dist/esm/checkpointer/internal/setup.d.ts +47 -0
- package/dist/esm/checkpointer/internal/setup.js +21 -0
- package/dist/{checkpointer/saver.js → esm/checkpointer/saver.d.ts} +84 -87
- package/dist/esm/checkpointer/saver.js +52 -0
- package/dist/esm/checkpointer/types.d.ts +51 -0
- package/dist/esm/checkpointer/types.js +1 -0
- package/dist/esm/factory/factory.d.ts +154 -0
- package/dist/esm/factory/factory.js +133 -0
- package/dist/esm/factory/types.d.ts +76 -0
- package/dist/esm/factory/types.js +1 -0
- package/dist/{history/actions/add-messages.js → esm/history/actions/add-messages.d.ts} +20 -26
- package/dist/esm/history/actions/add-messages.js +14 -0
- package/dist/{history/actions/clear.js → esm/history/actions/clear.d.ts} +4 -35
- package/dist/esm/history/actions/clear.js +26 -0
- package/dist/esm/history/actions/get-messages.d.ts +60 -0
- package/dist/esm/history/actions/get-messages.js +55 -0
- package/dist/esm/history/actions/list-sessions.d.ts +55 -0
- package/dist/esm/history/actions/list-sessions.js +64 -0
- package/dist/{history/actions/reconcile-count.js → esm/history/actions/reconcile-count.d.ts} +14 -16
- package/dist/esm/history/actions/reconcile-count.js +5 -0
- package/dist/{history/chat-message-history.js → esm/history/chat-message-history.d.ts} +76 -87
- package/dist/esm/history/chat-message-history.js +57 -0
- package/dist/esm/history/internal/append.d.ts +244 -0
- package/dist/esm/history/internal/append.js +259 -0
- package/dist/esm/history/internal/message-read.d.ts +84 -0
- package/dist/esm/history/internal/message-read.js +89 -0
- package/dist/esm/history/internal/parse.d.ts +153 -0
- package/dist/esm/history/internal/parse.js +105 -0
- package/dist/{history/internal/rows.js → esm/history/internal/rows.d.ts} +58 -112
- package/dist/esm/history/internal/rows.js +83 -0
- package/dist/esm/history/internal/session.d.ts +350 -0
- package/dist/esm/history/internal/session.js +285 -0
- package/dist/esm/history/internal/setup.d.ts +64 -0
- package/dist/esm/history/internal/setup.js +56 -0
- package/dist/{history/session-adapter.js → esm/history/session-adapter.d.ts} +25 -39
- package/dist/esm/history/session-adapter.js +34 -0
- package/dist/esm/history/types.d.ts +102 -0
- package/dist/esm/history/types.js +1 -0
- package/dist/esm/index.d.ts +53 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/shared/adapter.d.ts +146 -0
- package/dist/esm/shared/adapter.js +65 -0
- package/dist/{shared/clock.js → esm/shared/clock.d.ts} +3 -14
- package/dist/esm/shared/clock.js +9 -0
- package/dist/esm/shared/codec/codec.d.ts +336 -0
- package/dist/esm/shared/codec/codec.js +150 -0
- package/dist/esm/shared/codec/compression.d.ts +66 -0
- package/dist/esm/shared/codec/compression.js +40 -0
- package/dist/esm/shared/codec/json-serde.d.ts +80 -0
- package/dist/esm/shared/codec/json-serde.js +54 -0
- package/dist/esm/shared/codec/s3/client-types.d.ts +54 -0
- package/dist/esm/shared/codec/s3/client-types.js +3 -0
- package/dist/esm/shared/codec/s3/client.d.ts +63 -0
- package/dist/esm/shared/codec/s3/client.js +40 -0
- package/dist/{shared/codec/s3/config.js → esm/shared/codec/s3/config.d.ts} +45 -93
- package/dist/esm/shared/codec/s3/config.js +79 -0
- package/dist/esm/shared/codec/s3/lifecycle.d.ts +220 -0
- package/dist/esm/shared/codec/s3/lifecycle.js +214 -0
- package/dist/esm/shared/codec/s3/offloader.d.ts +428 -0
- package/dist/esm/shared/codec/s3/offloader.js +278 -0
- package/dist/{shared/concurrency.js → esm/shared/concurrency.d.ts} +2 -37
- package/dist/esm/shared/concurrency.js +27 -0
- package/dist/{shared/dynamodb/abort.js → esm/shared/dynamodb/abort.d.ts} +4 -16
- package/dist/esm/shared/dynamodb/abort.js +12 -0
- package/dist/esm/shared/dynamodb/batch-write.d.ts +86 -0
- package/dist/esm/shared/dynamodb/batch-write.js +74 -0
- package/dist/{shared/dynamodb/cancellation.js → esm/shared/dynamodb/cancellation.d.ts} +25 -53
- package/dist/esm/shared/dynamodb/cancellation.js +30 -0
- package/dist/{shared/dynamodb/client.js → esm/shared/dynamodb/client.d.ts} +74 -64
- package/dist/esm/shared/dynamodb/client.js +35 -0
- package/dist/{shared/dynamodb/idempotent-write.js → esm/shared/dynamodb/idempotent-write.d.ts} +172 -169
- package/dist/esm/shared/dynamodb/idempotent-write.js +153 -0
- package/dist/esm/shared/dynamodb/paginate.d.ts +111 -0
- package/dist/esm/shared/dynamodb/paginate.js +84 -0
- package/dist/esm/shared/dynamodb/partition-delete.d.ts +204 -0
- package/dist/esm/shared/dynamodb/partition-delete.js +171 -0
- package/dist/esm/shared/dynamodb/recency-index.d.ts +243 -0
- package/dist/esm/shared/dynamodb/recency-index.js +136 -0
- package/dist/esm/shared/dynamodb/retry.d.ts +317 -0
- package/dist/esm/shared/dynamodb/retry.js +180 -0
- package/dist/esm/shared/dynamodb/row-size.d.ts +33 -0
- package/dist/esm/shared/dynamodb/row-size.js +26 -0
- package/dist/{shared/dynamodb/table-schema.js → esm/shared/dynamodb/table-schema.d.ts} +57 -67
- package/dist/esm/shared/dynamodb/table-schema.js +43 -0
- package/dist/esm/shared/errors/base-error.d.ts +231 -0
- package/dist/esm/shared/errors/base-error.js +64 -0
- package/dist/esm/shared/errors/boundary.d.ts +86 -0
- package/dist/esm/shared/errors/boundary.js +54 -0
- package/dist/esm/shared/errors/classify.d.ts +206 -0
- package/dist/esm/shared/errors/classify.js +220 -0
- package/dist/{shared/errors/error-code.js → esm/shared/errors/error-code.d.ts} +39 -43
- package/dist/esm/shared/errors/error-code.js +24 -0
- package/dist/{shared/errors/errors.js → esm/shared/errors/errors.d.ts} +92 -98
- package/dist/esm/shared/errors/errors.js +110 -0
- package/dist/{shared/logging/logger.js → esm/shared/logging/logger.d.ts} +22 -52
- package/dist/esm/shared/logging/logger.js +25 -0
- package/dist/esm/shared/logging/redaction.d.ts +123 -0
- package/dist/esm/shared/logging/redaction.js +140 -0
- package/dist/{shared/logging/secret-patterns.js → esm/shared/logging/secret-patterns.d.ts} +46 -87
- package/dist/esm/shared/logging/secret-patterns.js +83 -0
- package/dist/{shared/logging/truncate.js → esm/shared/logging/truncate.d.ts} +6 -40
- package/dist/esm/shared/logging/truncate.js +25 -0
- package/dist/esm/shared/options.d.ts +100 -0
- package/dist/esm/shared/options.js +1 -0
- package/dist/{shared/ulid.js → esm/shared/ulid.d.ts} +4 -84
- package/dist/esm/shared/ulid.js +77 -0
- package/dist/{shared/validation/collaborators.js → esm/shared/validation/collaborators.d.ts} +37 -65
- package/dist/esm/shared/validation/collaborators.js +70 -0
- package/dist/{shared/validation/option-shape.js → esm/shared/validation/option-shape.d.ts} +14 -36
- package/dist/esm/shared/validation/option-shape.js +24 -0
- package/dist/esm/shared/validation/options.d.ts +145 -0
- package/dist/esm/shared/validation/options.js +156 -0
- package/dist/{shared/validation/primitives.js → esm/shared/validation/primitives.d.ts} +30 -125
- package/dist/esm/shared/validation/primitives.js +100 -0
- package/dist/esm/shared/validation/ttl.d.ts +94 -0
- package/dist/esm/shared/validation/ttl.js +46 -0
- package/dist/esm/store/actions/list-namespaces.d.ts +79 -0
- package/dist/esm/store/actions/list-namespaces.js +86 -0
- package/dist/esm/store/actions/put.d.ts +43 -0
- package/dist/esm/store/actions/put.js +46 -0
- package/dist/{store/actions/reconcile-vector-index.js → esm/store/actions/reconcile-vector-index.d.ts} +8 -16
- package/dist/esm/store/actions/reconcile-vector-index.js +10 -0
- package/dist/esm/store/actions/search.d.ts +38 -0
- package/dist/esm/store/actions/search.js +23 -0
- package/dist/esm/store/internal/batch-plan.d.ts +56 -0
- package/dist/esm/store/internal/batch-plan.js +28 -0
- package/dist/esm/store/internal/filter.d.ts +43 -0
- package/dist/esm/store/internal/filter.js +60 -0
- package/dist/esm/store/internal/get-item.d.ts +77 -0
- package/dist/esm/store/internal/get-item.js +54 -0
- package/dist/esm/store/internal/item-write.d.ts +270 -0
- package/dist/esm/store/internal/item-write.js +173 -0
- package/dist/esm/store/internal/parse.d.ts +230 -0
- package/dist/esm/store/internal/parse.js +169 -0
- package/dist/{store/internal/rows.js → esm/store/internal/rows.d.ts} +111 -199
- package/dist/esm/store/internal/rows.js +147 -0
- package/dist/esm/store/internal/semantic-search.d.ts +168 -0
- package/dist/esm/store/internal/semantic-search.js +200 -0
- package/dist/esm/store/internal/setup.d.ts +96 -0
- package/dist/esm/store/internal/setup.js +98 -0
- package/dist/esm/store/internal/table-search.d.ts +100 -0
- package/dist/esm/store/internal/table-search.js +119 -0
- package/dist/esm/store/internal/vector-index.d.ts +258 -0
- package/dist/esm/store/internal/vector-index.js +256 -0
- package/dist/{store/store.js → esm/store/store.d.ts} +99 -133
- package/dist/esm/store/store.js +93 -0
- package/dist/esm/store/types.d.ts +111 -0
- package/dist/esm/store/types.js +1 -0
- package/dist/esm/store/vector-backend.d.ts +104 -0
- package/dist/esm/store/vector-backend.js +1 -0
- package/package.json +50 -44
- package/dist/backfill/backfill.js +0 -393
- package/dist/checkpointer/actions/list.js +0 -142
- package/dist/checkpointer/actions/put.js +0 -195
- package/dist/checkpointer/internal/delta-history.js +0 -252
- package/dist/checkpointer/internal/parse.js +0 -372
- package/dist/checkpointer/internal/pending-writes.js +0 -588
- package/dist/checkpointer/internal/read.js +0 -264
- package/dist/checkpointer/internal/rows.js +0 -834
- package/dist/checkpointer/internal/setup.js +0 -72
- package/dist/checkpointer/types.js +0 -12
- package/dist/factory/factory.js +0 -266
- package/dist/factory/types.js +0 -10
- package/dist/history/actions/get-messages.js +0 -141
- package/dist/history/actions/list-sessions.js +0 -156
- package/dist/history/internal/append.js +0 -500
- package/dist/history/internal/message-read.js +0 -204
- package/dist/history/internal/parse.js +0 -252
- package/dist/history/internal/session.js +0 -628
- package/dist/history/internal/setup.js +0 -106
- package/dist/history/types.js +0 -12
- package/dist/index.js +0 -51
- package/dist/shared/adapter.js +0 -143
- package/dist/shared/codec/codec.js +0 -441
- package/dist/shared/codec/compression.js +0 -89
- package/dist/shared/codec/json-serde.js +0 -191
- package/dist/shared/codec/s3/client-types.js +0 -26
- package/dist/shared/codec/s3/client.js +0 -97
- package/dist/shared/codec/s3/lifecycle.js +0 -355
- package/dist/shared/codec/s3/offloader.js +0 -658
- package/dist/shared/dynamodb/batch-write.js +0 -173
- package/dist/shared/dynamodb/paginate.js +0 -188
- package/dist/shared/dynamodb/partition-delete.js +0 -340
- package/dist/shared/dynamodb/recency-index.js +0 -377
- package/dist/shared/dynamodb/retry.js +0 -463
- package/dist/shared/errors/base-error.js +0 -174
- package/dist/shared/errors/boundary.js +0 -143
- package/dist/shared/errors/classify.d.ts +0 -97
- package/dist/shared/errors/classify.js +0 -257
- package/dist/shared/logging/redaction.js +0 -316
- package/dist/shared/options.js +0 -11
- package/dist/shared/validation/options.js +0 -328
- package/dist/shared/validation/ttl.js +0 -132
- package/dist/store/actions/list-namespaces.js +0 -197
- package/dist/store/actions/put.js +0 -78
- package/dist/store/actions/search.js +0 -66
- package/dist/store/internal/batch-plan.d.ts +0 -26
- package/dist/store/internal/batch-plan.js +0 -109
- package/dist/store/internal/filter.js +0 -137
- package/dist/store/internal/get-item.d.ts +0 -45
- package/dist/store/internal/get-item.js +0 -115
- package/dist/store/internal/item-write.js +0 -463
- package/dist/store/internal/parse.js +0 -350
- package/dist/store/internal/semantic-search.js +0 -389
- package/dist/store/internal/setup.js +0 -223
- package/dist/store/internal/table-search.js +0 -213
- package/dist/store/internal/vector-index.js +0 -546
- package/dist/store/types.js +0 -15
- package/dist/store/vector-backend.js +0 -17
- /package/dist/{shared → cjs/shared}/clock.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/codec/json-serde.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/concurrency.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/dynamodb/cancellation.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/logging/logger.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/logging/truncate.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/ulid.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/validation/primitives.d.ts +0 -0
- /package/dist/{store → cjs/store}/vector-backend.d.ts +0 -0
package/dist/{shared/dynamodb/idempotent-write.js → esm/shared/dynamodb/idempotent-write.d.ts}
RENAMED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Hides how a row write whose outcome matters is issued and settled.
|
|
4
3
|
*
|
|
@@ -12,32 +11,34 @@
|
|
|
12
11
|
* whose outcome was lost into one of three verdicts. Whether a write needs the
|
|
13
12
|
* token is the payload descriptor's question, answered here once.
|
|
14
13
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
14
|
+
import { type PayloadDescriptor, type DescriptorRef } from '../codec/codec.js';
|
|
15
|
+
import type { DynamoDBDocumentLike, AttributeMap, TransactAction } from './client.js';
|
|
16
|
+
import type { RetryOptions } from './retry.js';
|
|
17
|
+
import { type RowKey } from './table-schema.js';
|
|
18
|
+
/**
|
|
19
|
+
* What a row write needs of its adapter: the document client, the table, and
|
|
20
|
+
* the retry policy. Every context that writes or reads back a row already
|
|
21
|
+
* carries these three, so a call site passes itself.
|
|
22
|
+
*/
|
|
23
|
+
export interface RowWriteDeps {
|
|
24
|
+
client: DynamoDBDocumentLike;
|
|
25
|
+
tableName: string;
|
|
26
|
+
retry?: RetryOptions;
|
|
27
|
+
}
|
|
28
|
+
/** How one tokened transaction is retried, beyond the adapter's own policy. */
|
|
29
|
+
export interface TokenedWriteOptions {
|
|
30
|
+
/** Cancels the retries. */
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
/** The jitter source, for a caller whose tests need the backoff to take no time. */
|
|
33
|
+
rng?: () => number;
|
|
34
|
+
/** The fewest attempts the write is given, whatever the adapter's policy says. */
|
|
35
|
+
minAttempts?: number;
|
|
36
|
+
}
|
|
37
|
+
/** How one row write is sent: the guard it carries and the signal that cancels it. */
|
|
38
|
+
export interface RowWriteOptions {
|
|
39
|
+
guard?: RevisionGuard;
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}
|
|
41
42
|
/**
|
|
42
43
|
* Whether a payload descriptor names an S3 object, and so whether the write
|
|
43
44
|
* carrying it can strand one.
|
|
@@ -56,9 +57,7 @@ const table_schema_1 = require("./table-schema");
|
|
|
56
57
|
*
|
|
57
58
|
* Throws: nothing.
|
|
58
59
|
*/
|
|
59
|
-
function referencesS3Object(descriptor)
|
|
60
|
-
return descriptor.location === codec_1.PayloadLocation.S3;
|
|
61
|
-
}
|
|
60
|
+
export declare function referencesS3Object(descriptor: DescriptorRef): boolean;
|
|
62
61
|
/**
|
|
63
62
|
* Commit `actions` as one
|
|
64
63
|
* {@link https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html | TransactWriteItems}
|
|
@@ -103,13 +102,14 @@ function referencesS3Object(descriptor) {
|
|
|
103
102
|
* token, which is required rather than merely tidy: the re-pinned request
|
|
104
103
|
* carries a different `ConditionExpression`, and the same token presented with
|
|
105
104
|
* changed parameters inside the window is refused with
|
|
106
|
-
* `IdempotentParameterMismatchException` —
|
|
107
|
-
*
|
|
108
|
-
*
|
|
105
|
+
* `IdempotentParameterMismatchException` — classified as `AWS_REJECTED` and
|
|
106
|
+
* never retried, so reusing a token would fail the caller's write with that
|
|
107
|
+
* error instead of applying the re-pin. That refusal is only observable against real
|
|
109
108
|
* DynamoDB: the local image does not reserve a cancelled token's parameters
|
|
110
|
-
* and simply re-evaluates the changed body, so the
|
|
111
|
-
* can assert only that two re-pins carry different tokens
|
|
112
|
-
*
|
|
109
|
+
* and simply re-evaluates the changed body, so the integration tier, on
|
|
110
|
+
* DynamoDB Local, can assert only that two re-pins carry different tokens —
|
|
111
|
+
* the unit tier mocks the client — and the refusal itself belongs to the
|
|
112
|
+
* tier that runs against AWS.
|
|
113
113
|
*
|
|
114
114
|
* **At most one guarded action, and only ever as many actions as must land
|
|
115
115
|
* together.** A cancellation is read as a guard rejection only while exactly
|
|
@@ -161,23 +161,12 @@ function referencesS3Object(descriptor) {
|
|
|
161
161
|
* signal, and stamping a deadline onto that object would bound every later
|
|
162
162
|
* call of the same adapter by this call's clock.
|
|
163
163
|
*/
|
|
164
|
-
|
|
165
|
-
const input = { TransactItems: actions, ClientRequestToken: (0, node_crypto_1.randomUUID)() };
|
|
166
|
-
const deadlineAt = (0, clock_1.nowMs)() + retry_1.MAX_WRITE_LIFETIME_MS;
|
|
167
|
-
await (0, retry_1.withDynamoDBRetry)((request) => deps.client.transactWrite(input, request), {
|
|
168
|
-
...(0, retry_1.retryFor)(deps, options.signal),
|
|
169
|
-
...(options.minAttempts === undefined
|
|
170
|
-
? {}
|
|
171
|
-
: { maxAttempts: Math.max(options.minAttempts, deps.retry?.maxAttempts ?? 0) }),
|
|
172
|
-
...(options.rng === undefined ? {} : { rng: options.rng }),
|
|
173
|
-
deadlineAt,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
164
|
+
export declare function transactIdempotently(deps: RowWriteDeps, actions: TransactAction[], options?: TokenedWriteOptions): Promise<void>;
|
|
176
165
|
/**
|
|
177
166
|
* Commit one row under a request token; see {@link transactIdempotently} for
|
|
178
167
|
* why the write takes a transaction's shape and what the token buys.
|
|
179
168
|
*
|
|
180
|
-
* Accepts: `deps` — the adapter's client, table and retry policy. `
|
|
169
|
+
* Accepts: `deps` — the adapter's client, table and retry policy. `row` — the
|
|
181
170
|
* row to commit. It is captured by reference and re-sent unchanged on every
|
|
182
171
|
* attempt of the budget, so a caller must not mutate it while this call is in
|
|
183
172
|
* flight: the re-send would carry the same token with different parameters,
|
|
@@ -196,11 +185,7 @@ async function transactIdempotently(deps, actions, options = {}) {
|
|
|
196
185
|
* `rejectedRow`, so a caller reads them the same way. A spent budget
|
|
197
186
|
* throws `RETRY_EXHAUSTED` as any other call does.
|
|
198
187
|
*/
|
|
199
|
-
|
|
200
|
-
await transactIdempotently(deps, [{ Put: { TableName: deps.tableName, Item: item, ...guard } }], {
|
|
201
|
-
signal,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
188
|
+
export declare function putIdempotently(deps: RowWriteDeps, row: AttributeMap, guard?: RevisionGuard, signal?: AbortSignal): Promise<void>;
|
|
204
189
|
/**
|
|
205
190
|
* Remove one row under a request token; see {@link transactIdempotently} for
|
|
206
191
|
* why the delete takes a transaction's shape and what the token buys.
|
|
@@ -231,9 +216,7 @@ async function putIdempotently(deps, item, guard, signal) {
|
|
|
231
216
|
* is very much still there — and a caller that then releases what that row
|
|
232
217
|
* names has deleted an object a live row points at.
|
|
233
218
|
*/
|
|
234
|
-
|
|
235
|
-
await transactIdempotently(deps, [{ Delete: { TableName: deps.tableName, Key: key, ...guard } }], { signal });
|
|
236
|
-
}
|
|
219
|
+
export declare function deleteIdempotently(deps: RowWriteDeps, key: AttributeMap, guard?: RevisionGuard, signal?: AbortSignal): Promise<void>;
|
|
237
220
|
/**
|
|
238
221
|
* Commit one row: as a tokened one-item transaction when it names an S3
|
|
239
222
|
* object, and as a plain `PutItem` otherwise.
|
|
@@ -253,22 +236,33 @@ async function deleteIdempotently(deps, key, guard, signal) {
|
|
|
253
236
|
* answers true for, with the row that turned the write away readable through
|
|
254
237
|
* `rejectedRow`; whatever the write throws once its retries are spent.
|
|
255
238
|
*/
|
|
256
|
-
|
|
257
|
-
if (referencesS3Object(payload)) {
|
|
258
|
-
await putIdempotently(deps, row, options.guard, options.signal);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
await (0, retry_1.withDynamoDBRetry)((request) => deps.client.put({ TableName: deps.tableName, Item: row, ...options.guard }, request), (0, retry_1.retryFor)(deps, options.signal));
|
|
262
|
-
}
|
|
239
|
+
export declare function commitRow(deps: RowWriteDeps, row: AttributeMap, payload: DescriptorRef, options?: RowWriteOptions): Promise<void>;
|
|
263
240
|
/**
|
|
264
241
|
* Compare-and-swap attempts before a caller gives up and overwrites
|
|
265
242
|
* unconditionally. Kept small on purpose: DynamoDB charges write capacity for a
|
|
266
243
|
* *failed* conditional write too, sized on the existing item, so an aggressive
|
|
267
244
|
* loop turns contention into cost. Three attempts settle every realistic race,
|
|
268
|
-
* and the fallback is
|
|
245
|
+
* and the fallback is an unconditional write — one possible orphaned object,
|
|
246
|
+
* reclaimed by the lifecycle rule — rather than an error.
|
|
269
247
|
*/
|
|
270
|
-
|
|
271
|
-
|
|
248
|
+
export declare const OVERWRITE_CAS_MAX_ATTEMPTS = 3;
|
|
249
|
+
/** What a caller saw at the row before it tried to overwrite it. */
|
|
250
|
+
export interface ObservedRow {
|
|
251
|
+
exists: boolean;
|
|
252
|
+
revision?: string;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Condition fragments to spread into a `PutCommand` input. Every guard asks
|
|
256
|
+
* DynamoDB to attach the existing row to a rejection, so a compare-and-swap
|
|
257
|
+
* that loses can re-pin from the exception (see {@link rejectedRow}) instead
|
|
258
|
+
* of spending a second strongly-consistent read.
|
|
259
|
+
*/
|
|
260
|
+
export interface RevisionGuard {
|
|
261
|
+
ConditionExpression: string;
|
|
262
|
+
ExpressionAttributeNames?: Record<string, string>;
|
|
263
|
+
ExpressionAttributeValues?: Record<string, string>;
|
|
264
|
+
ReturnValuesOnConditionCheckFailure: 'ALL_OLD';
|
|
265
|
+
}
|
|
272
266
|
/**
|
|
273
267
|
* Build the condition admitting a write only while the row still holds the
|
|
274
268
|
* revision this caller observed.
|
|
@@ -280,8 +274,9 @@ const RETURN_REJECTED_ROW = { ReturnValuesOnConditionCheckFailure: 'ALL_OLD' };
|
|
|
280
274
|
* because neither writer can learn of an object it never saw; only refusing the
|
|
281
275
|
* second write until it re-reads can.
|
|
282
276
|
*
|
|
283
|
-
* A row with no revision attribute was written before
|
|
284
|
-
*
|
|
277
|
+
* A row with no revision attribute was written before the attribute existed
|
|
278
|
+
* — 0.9.0 for a store row's `rev`, 0.8.0 for a write row's `writeGroup`.
|
|
279
|
+
* Pinning its *absence* is what makes the swap correct across an upgrade: the first writer
|
|
285
280
|
* to touch such a row stamps one, and any racer still holding the pre-upgrade
|
|
286
281
|
* observation is turned away.
|
|
287
282
|
*
|
|
@@ -320,28 +315,9 @@ const RETURN_REJECTED_ROW = { ReturnValuesOnConditionCheckFailure: 'ALL_OLD' };
|
|
|
320
315
|
* retry either, since a rejected attempt commits nothing for a token to be
|
|
321
316
|
* answered from.
|
|
322
317
|
*/
|
|
323
|
-
function revisionGuard(attribute, observed)
|
|
324
|
-
if (!observed.exists)
|
|
325
|
-
return {
|
|
326
|
-
...RETURN_REJECTED_ROW,
|
|
327
|
-
ConditionExpression: `attribute_not_exists(${table_schema_1.PARTITION_KEY_ATTRIBUTE})`,
|
|
328
|
-
};
|
|
329
|
-
if (observed.revision === undefined) {
|
|
330
|
-
return {
|
|
331
|
-
...RETURN_REJECTED_ROW,
|
|
332
|
-
ConditionExpression: 'attribute_not_exists(#rev)',
|
|
333
|
-
ExpressionAttributeNames: { '#rev': attribute },
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
return {
|
|
337
|
-
...RETURN_REJECTED_ROW,
|
|
338
|
-
ConditionExpression: '#rev = :rev',
|
|
339
|
-
ExpressionAttributeNames: { '#rev': attribute },
|
|
340
|
-
ExpressionAttributeValues: { ':rev': observed.revision },
|
|
341
|
-
};
|
|
342
|
-
}
|
|
318
|
+
export declare function revisionGuard(attribute: string, observed: ObservedRow): RevisionGuard;
|
|
343
319
|
/** The field a payload descriptor carries the id of the write that produced it in. */
|
|
344
|
-
|
|
320
|
+
export declare const WRITE_ID_ATTRIBUTE = "writeId";
|
|
345
321
|
/**
|
|
346
322
|
* Build the condition admitting a delete only while the row still carries the
|
|
347
323
|
* per-write id the reader observed on it.
|
|
@@ -379,17 +355,7 @@ exports.WRITE_ID_ATTRIBUTE = 'writeId';
|
|
|
379
355
|
* leaves it in place and reports it rather than re-pinning, because a row it
|
|
380
356
|
* never read is not its to delete.
|
|
381
357
|
*/
|
|
382
|
-
function writeIdGuard(attribute, id, field)
|
|
383
|
-
const names = { '#pin': attribute };
|
|
384
|
-
if (field !== undefined)
|
|
385
|
-
names['#field'] = field;
|
|
386
|
-
return {
|
|
387
|
-
...RETURN_REJECTED_ROW,
|
|
388
|
-
ConditionExpression: field === undefined ? '#pin = :pin' : '#pin.#field = :pin',
|
|
389
|
-
ExpressionAttributeNames: names,
|
|
390
|
-
ExpressionAttributeValues: { ':pin': id },
|
|
391
|
-
};
|
|
392
|
-
}
|
|
358
|
+
export declare function writeIdGuard(attribute: string, id: string, field?: string): RevisionGuard;
|
|
393
359
|
/**
|
|
394
360
|
* Whether a conditional write was turned away by its guard.
|
|
395
361
|
*
|
|
@@ -412,9 +378,7 @@ function writeIdGuard(attribute, id, field) {
|
|
|
412
378
|
* identically, and the two are indistinguishable from the rejection alone —
|
|
413
379
|
* which is why every caller reads the row back before deleting anything.
|
|
414
380
|
*/
|
|
415
|
-
function isConditionalCheckFailed(error)
|
|
416
|
-
return (0, classify_1.classifyAwsError)(error) === error_code_1.ErrorCode.CONDITION_CONFLICT;
|
|
417
|
-
}
|
|
381
|
+
export declare function isConditionalCheckFailed(error: Error): boolean;
|
|
418
382
|
/**
|
|
419
383
|
* The row that turned a conditional write away, when DynamoDB attached it
|
|
420
384
|
* (`ReturnValuesOnConditionCheckFailure: 'ALL_OLD'`). Verified against real
|
|
@@ -437,10 +401,61 @@ function isConditionalCheckFailed(error) {
|
|
|
437
401
|
* Throws: whatever `unmarshall` rejects for an item that is not in
|
|
438
402
|
* AttributeValue form.
|
|
439
403
|
*/
|
|
440
|
-
function rejectedRow(error)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
404
|
+
export declare function rejectedRow(error: Error): AttributeMap | undefined;
|
|
405
|
+
/**
|
|
406
|
+
* What a post-failure read established about a write whose outcome was
|
|
407
|
+
* ambiguous.
|
|
408
|
+
*
|
|
409
|
+
* - `'landed'` — the row holds this write, so it committed server-side and only
|
|
410
|
+
* its acknowledgement was lost.
|
|
411
|
+
* - `'not-landed'` — the row was read and holds something else, or nothing, so
|
|
412
|
+
* this write's own upload is dead and safe to release.
|
|
413
|
+
* - `'unverified'` — the read itself failed, so nothing is established.
|
|
414
|
+
*
|
|
415
|
+
* The third answer is the one that must exist. Folding it into the second made
|
|
416
|
+
* a partition that blocked both the write and this read delete the object a
|
|
417
|
+
* possibly-live row points at, breaking every later read of that item. Leaking
|
|
418
|
+
* one object is recoverable; stranding a live row is not.
|
|
419
|
+
*/
|
|
420
|
+
export type WriteVerdict = 'landed' | 'not-landed' | 'unverified';
|
|
421
|
+
/** Which row to read, and which attributes of it to project. */
|
|
422
|
+
export interface RowRead {
|
|
423
|
+
key: RowKey;
|
|
424
|
+
/** The attribute carrying the row's identity; always projected. */
|
|
425
|
+
attribute: string;
|
|
426
|
+
/** Further attributes to project, when the caller needs the row itself back. */
|
|
427
|
+
also?: readonly string[];
|
|
428
|
+
/**
|
|
429
|
+
* Attributes holding a payload descriptor, projected as its `location` and
|
|
430
|
+
* `s3Key` only. A cleanup decision needs where the payload lives, never its
|
|
431
|
+
* inline bytes, which can run to hundreds of kilobytes. An attribute named
|
|
432
|
+
* here and as `attribute` or in `also` is projected once, as the descriptor,
|
|
433
|
+
* because DynamoDB refuses two overlapping paths in one projection.
|
|
434
|
+
*/
|
|
435
|
+
descriptors?: readonly string[];
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* A read, plus what makes the row *this* write's row.
|
|
439
|
+
*
|
|
440
|
+
* `expected` is the string the row must yield. `undefined` means there is
|
|
441
|
+
* nothing to compare — a record with no revision, a checkpoint with nothing
|
|
442
|
+
* offloaded — and no read is spent: with nothing at stake the answer is
|
|
443
|
+
* `'not-landed'`, which releases nothing that exists.
|
|
444
|
+
*/
|
|
445
|
+
export interface RowProbe extends RowRead {
|
|
446
|
+
/**
|
|
447
|
+
* How the row names the write that holds it: `'attribute'` reads the
|
|
448
|
+
* identity straight out of `attribute`, `'descriptor'` reads the S3 key of
|
|
449
|
+
* the payload descriptor stored there.
|
|
450
|
+
*/
|
|
451
|
+
kind: 'attribute' | 'descriptor';
|
|
452
|
+
expected: string | undefined;
|
|
453
|
+
}
|
|
454
|
+
/** A verification read: what it established, and the row it saw. */
|
|
455
|
+
export interface VerifiedWrite {
|
|
456
|
+
verdict: WriteVerdict;
|
|
457
|
+
/** The row as read. Absent when nothing was read, or no row exists. */
|
|
458
|
+
row?: AttributeMap;
|
|
444
459
|
}
|
|
445
460
|
/**
|
|
446
461
|
* The S3 key an offloaded descriptor points at.
|
|
@@ -452,9 +467,7 @@ function rejectedRow(error) {
|
|
|
452
467
|
*
|
|
453
468
|
* Throws: nothing.
|
|
454
469
|
*/
|
|
455
|
-
function offloadedKey(descriptor)
|
|
456
|
-
return descriptor?.location === codec_1.PayloadLocation.S3 ? descriptor.s3Key : undefined;
|
|
457
|
-
}
|
|
470
|
+
export declare function offloadedKey(descriptor: PayloadDescriptor | undefined): string | undefined;
|
|
458
471
|
/**
|
|
459
472
|
* The identity `row` carries under `probe`.
|
|
460
473
|
*
|
|
@@ -466,12 +479,7 @@ function offloadedKey(descriptor) {
|
|
|
466
479
|
*
|
|
467
480
|
* Throws: nothing.
|
|
468
481
|
*/
|
|
469
|
-
function identityOf(probe, row)
|
|
470
|
-
const stored = row?.[probe.attribute];
|
|
471
|
-
if (probe.kind === 'attribute')
|
|
472
|
-
return stored;
|
|
473
|
-
return offloadedKey(stored);
|
|
474
|
-
}
|
|
482
|
+
export declare function identityOf(probe: RowProbe, row: AttributeMap | undefined): string | undefined;
|
|
475
483
|
/**
|
|
476
484
|
* The verdict for a row already in hand.
|
|
477
485
|
*
|
|
@@ -483,30 +491,52 @@ function identityOf(probe, row) {
|
|
|
483
491
|
*
|
|
484
492
|
* Throws: nothing.
|
|
485
493
|
*/
|
|
486
|
-
function verdictFor(probe, row)
|
|
487
|
-
return identityOf(probe, row) === probe.expected ? 'landed' : 'not-landed';
|
|
488
|
-
}
|
|
494
|
+
export declare function verdictFor(probe: RowProbe, row: AttributeMap | undefined): WriteVerdict;
|
|
489
495
|
/**
|
|
490
|
-
*
|
|
491
|
-
*
|
|
496
|
+
* Whether a write that failed may still commit after its failure was reported.
|
|
497
|
+
*
|
|
498
|
+
* A write the service answered with a definite refusal or a throttle is
|
|
499
|
+
* finished: a strongly consistent read after that answer sees whatever it
|
|
500
|
+
* did. A write is not finished while *any* attempt of it left DynamoDB free to
|
|
501
|
+
* apply it later — not only its last attempt: `TransactWriteItems` is sent
|
|
502
|
+
* under one `ClientRequestToken` for the whole retry budget, and DynamoDB
|
|
503
|
+
* answers a re-send that arrives while an earlier attempt under that same
|
|
504
|
+
* token is still being processed with `TransactionInProgressException` —
|
|
505
|
+
* itself proof that the earlier attempt reached the service and may still
|
|
506
|
+
* land — while the very next attempt can be answered normally. A cancel is
|
|
507
|
+
* the same story from the caller's own side: it stops the client waiting, not
|
|
508
|
+
* the service applying a request it had already received.
|
|
509
|
+
*
|
|
510
|
+
* Accepts: `failure` — what the write threw.
|
|
511
|
+
*
|
|
512
|
+
* Returns: true for `ABORTED`, and for any failure carrying the record
|
|
513
|
+
* `withRetry` kept across every attempt of its budget
|
|
514
|
+
* (`retryBudgetMayStillLand`) — a spent budget, or a refusal that ended one
|
|
515
|
+
* after an attempt that got no answer. Without that record, a spent budget is
|
|
516
|
+
* judged by its last attempt's own failure (`mayStillBeInFlight`), which is
|
|
517
|
+
* what a `RETRY_EXHAUSTED` error built outside `withRetry` falls back to; any
|
|
518
|
+
* other failure is judged by itself the same way.
|
|
519
|
+
*
|
|
520
|
+
* Throws: nothing, for any value.
|
|
492
521
|
*/
|
|
493
|
-
function
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
522
|
+
export declare function mayStillLand(failure: Error): boolean;
|
|
523
|
+
/**
|
|
524
|
+
* The verdict a read-back licenses once the write it judges may still be in flight.
|
|
525
|
+
*
|
|
526
|
+
* Accepts: `verdict` — what the read found. `failure` — what the write threw.
|
|
527
|
+
*
|
|
528
|
+
* Returns: `'unverified'` in place of `'not-landed'` when the write may still
|
|
529
|
+
* commit ({@link mayStillLand}): an absent row is exactly what an attempt still
|
|
530
|
+
* on its way can fill, so the upload it names is not yet dead. Every other
|
|
531
|
+
* verdict is returned unchanged. A caller whose write is pinned to a state the
|
|
532
|
+
* row has already left may skip this, since such a write can no longer apply
|
|
533
|
+
* (the pending-writes verification does); `persistRow` asks it unconditionally,
|
|
534
|
+
* so its upload is kept whether the read found the row absent or holding
|
|
535
|
+
* another revision.
|
|
536
|
+
*
|
|
537
|
+
* Throws: nothing.
|
|
538
|
+
*/
|
|
539
|
+
export declare function settledVerdict(verdict: WriteVerdict, failure: Error): WriteVerdict;
|
|
510
540
|
/**
|
|
511
541
|
* Read the row a probe names, strongly consistently.
|
|
512
542
|
*
|
|
@@ -525,17 +555,7 @@ function projectionOf(read) {
|
|
|
525
555
|
* Guarantees: strongly consistent — a read that may lag is no evidence at all
|
|
526
556
|
* about a write that may have landed.
|
|
527
557
|
*/
|
|
528
|
-
|
|
529
|
-
const { expression, names } = projectionOf(read);
|
|
530
|
-
const result = await (0, retry_1.withDynamoDBRetry)((request) => deps.client.get({
|
|
531
|
-
TableName: deps.tableName,
|
|
532
|
-
Key: read.key,
|
|
533
|
-
ConsistentRead: true,
|
|
534
|
-
ProjectionExpression: expression,
|
|
535
|
-
ExpressionAttributeNames: names,
|
|
536
|
-
}, request), deps.retry);
|
|
537
|
-
return result.Item;
|
|
538
|
-
}
|
|
558
|
+
export declare function readRow(deps: RowWriteDeps, read: RowRead): Promise<AttributeMap | undefined>;
|
|
539
559
|
/**
|
|
540
560
|
* Read one row back to establish what an ambiguous write actually did.
|
|
541
561
|
*
|
|
@@ -556,17 +576,7 @@ async function readRow(deps, read) {
|
|
|
556
576
|
* the caller is already handling a failure and needs a decision, not a second
|
|
557
577
|
* one.
|
|
558
578
|
*/
|
|
559
|
-
|
|
560
|
-
if (probe.expected === undefined)
|
|
561
|
-
return { verdict: 'not-landed' };
|
|
562
|
-
try {
|
|
563
|
-
const row = await readRow(deps, probe);
|
|
564
|
-
return { verdict: verdictFor(probe, row), row };
|
|
565
|
-
}
|
|
566
|
-
catch {
|
|
567
|
-
return { verdict: 'unverified' };
|
|
568
|
-
}
|
|
569
|
-
}
|
|
579
|
+
export declare function verifyRow(deps: RowWriteDeps, probe: RowProbe): Promise<VerifiedWrite>;
|
|
570
580
|
/**
|
|
571
581
|
* Whether a row is confirmed absent right now — what resolves an ambiguous
|
|
572
582
|
* retry-exhausted *delete*, where the delete may well have landed server-side
|
|
@@ -583,11 +593,4 @@ async function verifyRow(deps, probe) {
|
|
|
583
593
|
*
|
|
584
594
|
* Throws: nothing.
|
|
585
595
|
*/
|
|
586
|
-
|
|
587
|
-
try {
|
|
588
|
-
return (await readRow(deps, { key, attribute: table_schema_1.PARTITION_KEY_ATTRIBUTE })) === undefined;
|
|
589
|
-
}
|
|
590
|
-
catch {
|
|
591
|
-
return false;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
596
|
+
export declare function isRowAbsent(deps: RowWriteDeps, key: RowKey): Promise<boolean>;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { unmarshall } from '@aws-sdk/util-dynamodb';
|
|
3
|
+
import { nowMs } from '../clock.js';
|
|
4
|
+
import { PayloadLocation } from '../codec/codec.js';
|
|
5
|
+
import { hasErrorCode } from '../errors/base-error.js';
|
|
6
|
+
import { classifyAwsError, mayStillBeInFlight } from '../errors/classify.js';
|
|
7
|
+
import { ErrorCode } from '../errors/error-code.js';
|
|
8
|
+
import { retryBudgetMayStillLand } from '../errors/errors.js';
|
|
9
|
+
import { isAbortError } from './abort.js';
|
|
10
|
+
import { conditionalCheckFailure } from './cancellation.js';
|
|
11
|
+
import { MAX_WRITE_LIFETIME_MS, withDynamoDBRetry, retryFor } from './retry.js';
|
|
12
|
+
import { PARTITION_KEY_ATTRIBUTE } from './table-schema.js';
|
|
13
|
+
export function referencesS3Object(descriptor) {
|
|
14
|
+
return descriptor.location === PayloadLocation.S3;
|
|
15
|
+
}
|
|
16
|
+
export async function transactIdempotently(deps, actions, options = {}) {
|
|
17
|
+
const input = { TransactItems: actions, ClientRequestToken: randomUUID() };
|
|
18
|
+
const deadlineAt = nowMs() + MAX_WRITE_LIFETIME_MS;
|
|
19
|
+
await withDynamoDBRetry((request) => deps.client.transactWrite(input, request), {
|
|
20
|
+
...retryFor(deps, options.signal),
|
|
21
|
+
...(options.minAttempts === undefined
|
|
22
|
+
? {}
|
|
23
|
+
: { maxAttempts: Math.max(options.minAttempts, deps.retry?.maxAttempts ?? 0) }),
|
|
24
|
+
...(options.rng === undefined ? {} : { rng: options.rng }),
|
|
25
|
+
deadlineAt,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export async function putIdempotently(deps, row, guard, signal) {
|
|
29
|
+
await transactIdempotently(deps, [{ Put: { TableName: deps.tableName, Item: row, ...guard } }], {
|
|
30
|
+
signal,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export async function deleteIdempotently(deps, key, guard, signal) {
|
|
34
|
+
await transactIdempotently(deps, [{ Delete: { TableName: deps.tableName, Key: key, ...guard } }], { signal });
|
|
35
|
+
}
|
|
36
|
+
export async function commitRow(deps, row, payload, options = {}) {
|
|
37
|
+
if (referencesS3Object(payload)) {
|
|
38
|
+
await putIdempotently(deps, row, options.guard, options.signal);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await withDynamoDBRetry((request) => deps.client.put({ TableName: deps.tableName, Item: row, ...options.guard }, request), retryFor(deps, options.signal));
|
|
42
|
+
}
|
|
43
|
+
export const OVERWRITE_CAS_MAX_ATTEMPTS = 3;
|
|
44
|
+
const RETURN_REJECTED_ROW = { ReturnValuesOnConditionCheckFailure: 'ALL_OLD' };
|
|
45
|
+
export function revisionGuard(attribute, observed) {
|
|
46
|
+
if (!observed.exists)
|
|
47
|
+
return {
|
|
48
|
+
...RETURN_REJECTED_ROW,
|
|
49
|
+
ConditionExpression: `attribute_not_exists(${PARTITION_KEY_ATTRIBUTE})`,
|
|
50
|
+
};
|
|
51
|
+
if (observed.revision === undefined) {
|
|
52
|
+
return {
|
|
53
|
+
...RETURN_REJECTED_ROW,
|
|
54
|
+
ConditionExpression: 'attribute_not_exists(#rev)',
|
|
55
|
+
ExpressionAttributeNames: { '#rev': attribute },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
...RETURN_REJECTED_ROW,
|
|
60
|
+
ConditionExpression: '#rev = :rev',
|
|
61
|
+
ExpressionAttributeNames: { '#rev': attribute },
|
|
62
|
+
ExpressionAttributeValues: { ':rev': observed.revision },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export const WRITE_ID_ATTRIBUTE = 'writeId';
|
|
66
|
+
export function writeIdGuard(attribute, id, field) {
|
|
67
|
+
const names = { '#pin': attribute };
|
|
68
|
+
if (field !== undefined)
|
|
69
|
+
names['#field'] = field;
|
|
70
|
+
return {
|
|
71
|
+
...RETURN_REJECTED_ROW,
|
|
72
|
+
ConditionExpression: field === undefined ? '#pin = :pin' : '#pin.#field = :pin',
|
|
73
|
+
ExpressionAttributeNames: names,
|
|
74
|
+
ExpressionAttributeValues: { ':pin': id },
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function isConditionalCheckFailed(error) {
|
|
78
|
+
return classifyAwsError(error) === ErrorCode.CONDITION_CONFLICT;
|
|
79
|
+
}
|
|
80
|
+
export function rejectedRow(error) {
|
|
81
|
+
const attached = error.Item;
|
|
82
|
+
const raw = attached ?? conditionalCheckFailure(error)?.Item;
|
|
83
|
+
return raw === undefined ? undefined : unmarshall(raw);
|
|
84
|
+
}
|
|
85
|
+
export function offloadedKey(descriptor) {
|
|
86
|
+
return descriptor?.location === PayloadLocation.S3 ? descriptor.s3Key : undefined;
|
|
87
|
+
}
|
|
88
|
+
export function identityOf(probe, row) {
|
|
89
|
+
if (probe.kind === 'attribute')
|
|
90
|
+
return row?.[probe.attribute];
|
|
91
|
+
return offloadedKey(row?.[probe.attribute]);
|
|
92
|
+
}
|
|
93
|
+
export function verdictFor(probe, row) {
|
|
94
|
+
return identityOf(probe, row) === probe.expected ? 'landed' : 'not-landed';
|
|
95
|
+
}
|
|
96
|
+
export function mayStillLand(failure) {
|
|
97
|
+
if (isAbortError(failure) || retryBudgetMayStillLand(failure))
|
|
98
|
+
return true;
|
|
99
|
+
if (hasErrorCode(failure, ErrorCode.RETRY_EXHAUSTED)) {
|
|
100
|
+
return mayStillBeInFlight(failure.cause);
|
|
101
|
+
}
|
|
102
|
+
return mayStillBeInFlight(failure);
|
|
103
|
+
}
|
|
104
|
+
export function settledVerdict(verdict, failure) {
|
|
105
|
+
return verdict === 'not-landed' && mayStillLand(failure) ? 'unverified' : verdict;
|
|
106
|
+
}
|
|
107
|
+
function projectionOf(read) {
|
|
108
|
+
const nested = read.descriptors ?? [];
|
|
109
|
+
const whole = [read.attribute, ...(read.also ?? [])].filter((name) => !nested.includes(name));
|
|
110
|
+
const names = {};
|
|
111
|
+
const paths = [];
|
|
112
|
+
whole.forEach((name, index) => {
|
|
113
|
+
names[`#a${index}`] = name;
|
|
114
|
+
paths.push(`#a${index}`);
|
|
115
|
+
});
|
|
116
|
+
nested.forEach((name, index) => {
|
|
117
|
+
names[`#d${index}`] = name;
|
|
118
|
+
paths.push(`#d${index}.#loc`, `#d${index}.#s3k`);
|
|
119
|
+
});
|
|
120
|
+
if (nested.length > 0)
|
|
121
|
+
Object.assign(names, { '#loc': 'location', '#s3k': 's3Key' });
|
|
122
|
+
return { expression: paths.join(', '), names };
|
|
123
|
+
}
|
|
124
|
+
export async function readRow(deps, read) {
|
|
125
|
+
const { expression, names } = projectionOf(read);
|
|
126
|
+
const result = await withDynamoDBRetry((request) => deps.client.get({
|
|
127
|
+
TableName: deps.tableName,
|
|
128
|
+
Key: read.key,
|
|
129
|
+
ConsistentRead: true,
|
|
130
|
+
ProjectionExpression: expression,
|
|
131
|
+
ExpressionAttributeNames: names,
|
|
132
|
+
}, request), deps.retry);
|
|
133
|
+
return result.Item;
|
|
134
|
+
}
|
|
135
|
+
export async function verifyRow(deps, probe) {
|
|
136
|
+
if (probe.expected === undefined)
|
|
137
|
+
return { verdict: 'not-landed' };
|
|
138
|
+
try {
|
|
139
|
+
const row = await readRow(deps, probe);
|
|
140
|
+
return { verdict: verdictFor(probe, row), row };
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return { verdict: 'unverified' };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
export async function isRowAbsent(deps, key) {
|
|
147
|
+
try {
|
|
148
|
+
return (await readRow(deps, { key, attribute: PARTITION_KEY_ATTRIBUTE })) === undefined;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|