@farukada/aws-langgraph-dynamodb-ts 0.8.0 → 1.0.0-rc.1
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 +282 -49
- package/dist/checkpointer/actions/delete-thread.d.ts +3 -2
- package/dist/checkpointer/actions/delete-thread.js +5 -2
- package/dist/checkpointer/actions/get-tuple.d.ts +3 -2
- package/dist/checkpointer/actions/get-tuple.js +10 -4
- package/dist/checkpointer/actions/list.d.ts +14 -4
- package/dist/checkpointer/actions/list.js +94 -61
- package/dist/checkpointer/actions/put-writes.d.ts +5 -5
- package/dist/checkpointer/actions/put-writes.js +12 -40
- package/dist/checkpointer/actions/put.d.ts +10 -3
- package/dist/checkpointer/actions/put.js +42 -12
- package/dist/checkpointer/internal/assemble.d.ts +10 -3
- package/dist/checkpointer/internal/assemble.js +7 -6
- package/dist/checkpointer/internal/checkpoint-write-verify.d.ts +24 -0
- package/dist/checkpointer/internal/checkpoint-write-verify.js +67 -0
- package/dist/checkpointer/internal/configurable.d.ts +0 -1
- package/dist/checkpointer/internal/configurable.js +10 -9
- package/dist/checkpointer/internal/fetch.d.ts +14 -5
- package/dist/checkpointer/internal/fetch.js +56 -14
- package/dist/checkpointer/internal/filter-match.d.ts +3 -2
- package/dist/checkpointer/internal/filter-match.js +4 -3
- package/dist/checkpointer/internal/item-reader.d.ts +31 -6
- package/dist/checkpointer/internal/item-reader.js +54 -15
- package/dist/checkpointer/internal/item-writer.d.ts +12 -3
- package/dist/checkpointer/internal/item-writer.js +26 -10
- package/dist/checkpointer/internal/keys.d.ts +11 -1
- package/dist/checkpointer/internal/keys.js +33 -3
- package/dist/checkpointer/internal/list-scope.d.ts +61 -0
- package/dist/checkpointer/internal/list-scope.js +108 -0
- package/dist/checkpointer/internal/pending-sends.d.ts +13 -0
- package/dist/checkpointer/internal/pending-sends.js +29 -0
- package/dist/checkpointer/internal/query.d.ts +2 -1
- package/dist/checkpointer/internal/query.js +9 -3
- package/dist/checkpointer/internal/regular-write.d.ts +28 -0
- package/dist/checkpointer/internal/regular-write.js +66 -0
- package/dist/checkpointer/internal/setup.d.ts +3 -1
- package/dist/checkpointer/internal/setup.js +10 -8
- package/dist/checkpointer/internal/special-write-cas.d.ts +29 -0
- package/dist/checkpointer/internal/special-write-cas.js +104 -0
- package/dist/checkpointer/internal/special-write-cleanup.d.ts +19 -14
- package/dist/checkpointer/internal/special-write-cleanup.js +35 -87
- package/dist/checkpointer/internal/special-write-verify.d.ts +53 -0
- package/dist/checkpointer/internal/special-write-verify.js +80 -0
- package/dist/checkpointer/internal/stored-channels.d.ts +31 -0
- package/dist/checkpointer/internal/stored-channels.js +70 -0
- package/dist/checkpointer/internal/validation.d.ts +11 -6
- package/dist/checkpointer/internal/validation.js +19 -9
- package/dist/checkpointer/internal/write-guard.d.ts +8 -9
- package/dist/checkpointer/internal/write-guard.js +16 -16
- package/dist/checkpointer/internal/write-index.d.ts +8 -1
- package/dist/checkpointer/internal/write-index.js +6 -3
- package/dist/checkpointer/saver.d.ts +50 -10
- package/dist/checkpointer/saver.js +59 -17
- package/dist/checkpointer/types.d.ts +14 -1
- package/dist/checkpointer/types.js +0 -1
- package/dist/factory/factory.d.ts +22 -25
- package/dist/factory/factory.js +58 -18
- package/dist/factory/types.d.ts +57 -0
- package/dist/factory/types.js +2 -0
- package/dist/history/actions/add-messages.d.ts +1 -2
- package/dist/history/actions/add-messages.js +4 -4
- package/dist/history/actions/clear.d.ts +3 -2
- package/dist/history/actions/clear.js +5 -2
- package/dist/history/actions/get-messages.d.ts +13 -6
- package/dist/history/actions/get-messages.js +63 -42
- package/dist/history/actions/list-sessions.d.ts +1 -1
- package/dist/history/actions/list-sessions.js +8 -12
- package/dist/history/actions/reconcile-count.d.ts +1 -2
- package/dist/history/actions/reconcile-count.js +20 -7
- package/dist/history/chat-message-history.d.ts +51 -26
- package/dist/history/chat-message-history.js +60 -30
- package/dist/history/internal/append-saga.d.ts +7 -2
- package/dist/history/internal/append-saga.js +58 -14
- package/dist/history/internal/compensation.d.ts +6 -2
- package/dist/history/internal/compensation.js +14 -6
- package/dist/history/internal/item-mapper.d.ts +0 -3
- package/dist/history/internal/item-mapper.js +2 -8
- package/dist/history/internal/keys.d.ts +0 -1
- package/dist/history/internal/keys.js +0 -1
- package/dist/history/internal/message-chunker.d.ts +0 -1
- package/dist/history/internal/message-chunker.js +0 -1
- package/dist/history/internal/message-transaction.d.ts +0 -1
- package/dist/history/internal/message-transaction.js +3 -2
- package/dist/history/internal/message-window.d.ts +17 -0
- package/dist/history/internal/message-window.js +49 -0
- package/dist/history/internal/query.d.ts +16 -3
- package/dist/history/internal/query.js +13 -5
- package/dist/history/internal/session-count.d.ts +8 -2
- package/dist/history/internal/session-count.js +14 -8
- package/dist/history/internal/session-title.d.ts +0 -1
- package/dist/history/internal/session-title.js +1 -2
- package/dist/history/internal/session-update.d.ts +0 -1
- package/dist/history/internal/session-update.js +0 -1
- package/dist/history/internal/setup.d.ts +3 -1
- package/dist/history/internal/setup.js +16 -8
- package/dist/history/internal/title-generator.d.ts +0 -1
- package/dist/history/internal/title-generator.js +19 -3
- package/dist/history/internal/ttl-anchor.d.ts +1 -2
- package/dist/history/internal/ttl-anchor.js +5 -5
- package/dist/history/internal/validation.d.ts +19 -3
- package/dist/history/internal/validation.js +41 -4
- package/dist/history/session-adapter.d.ts +9 -3
- package/dist/history/session-adapter.js +6 -3
- package/dist/history/types.d.ts +23 -2
- package/dist/history/types.js +0 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js +5 -3
- package/dist/shared/clock.d.ts +6 -1
- package/dist/shared/clock.js +9 -1
- package/dist/shared/codec/codec.d.ts +26 -17
- package/dist/shared/codec/codec.js +46 -24
- package/dist/shared/codec/compression.d.ts +1 -2
- package/dist/shared/codec/compression.js +2 -3
- package/dist/shared/codec/descriptor-keys.d.ts +11 -3
- package/dist/shared/codec/descriptor-keys.js +2 -2
- package/dist/shared/codec/encode.d.ts +13 -0
- package/dist/shared/codec/encode.js +43 -0
- package/dist/shared/codec/json-serde.d.ts +0 -1
- package/dist/shared/codec/json-serde.js +0 -1
- package/dist/shared/codec/payload-loss.d.ts +12 -0
- package/dist/shared/codec/payload-loss.js +38 -0
- package/dist/shared/codec/s3/adapter-config.d.ts +13 -0
- package/dist/shared/codec/s3/adapter-config.js +22 -0
- package/dist/shared/codec/s3/bounded-body.d.ts +14 -0
- package/dist/shared/codec/s3/bounded-body.js +47 -0
- package/dist/shared/codec/s3/client-types.d.ts +34 -0
- package/dist/shared/codec/s3/client-types.js +7 -0
- package/dist/shared/codec/s3/client.d.ts +11 -5
- package/dist/shared/codec/s3/client.js +25 -3
- package/dist/shared/codec/s3/config.d.ts +32 -5
- package/dist/shared/codec/s3/config.js +37 -5
- package/dist/shared/codec/s3/delete.d.ts +0 -1
- package/dist/shared/codec/s3/delete.js +0 -1
- package/dist/shared/codec/s3/key-scope.d.ts +23 -0
- package/dist/shared/codec/s3/key-scope.js +44 -0
- package/dist/shared/codec/s3/lifecycle.d.ts +11 -5
- package/dist/shared/codec/s3/lifecycle.js +32 -16
- package/dist/shared/codec/s3/offloader.d.ts +6 -2
- package/dist/shared/codec/s3/offloader.js +21 -3
- package/dist/shared/codec/s3/orphans.d.ts +6 -1
- package/dist/shared/codec/s3/orphans.js +15 -2
- package/dist/shared/codec/s3/read-write.d.ts +7 -3
- package/dist/shared/codec/s3/read-write.js +16 -8
- package/dist/shared/codec/s3/retry.d.ts +4 -4
- package/dist/shared/codec/s3/retry.js +13 -16
- package/dist/shared/concurrency.d.ts +6 -0
- package/dist/shared/concurrency.js +30 -0
- package/dist/shared/constants.d.ts +68 -5
- package/dist/shared/constants.js +70 -7
- package/dist/shared/dynamodb/abort.d.ts +9 -0
- package/dist/shared/dynamodb/abort.js +27 -0
- package/dist/shared/dynamodb/backoff.d.ts +4 -4
- package/dist/shared/dynamodb/backoff.js +7 -7
- package/dist/shared/dynamodb/batch-write.d.ts +0 -1
- package/dist/shared/dynamodb/batch-write.js +0 -1
- package/dist/shared/dynamodb/cancellation.d.ts +0 -1
- package/dist/shared/dynamodb/cancellation.js +0 -1
- package/dist/shared/dynamodb/client.d.ts +9 -2
- package/dist/shared/dynamodb/client.js +24 -1
- package/dist/shared/dynamodb/conditional-put.d.ts +67 -0
- package/dist/shared/dynamodb/conditional-put.js +76 -0
- package/dist/shared/dynamodb/drain-unprocessed.d.ts +3 -1
- package/dist/shared/dynamodb/drain-unprocessed.js +1 -2
- package/dist/shared/dynamodb/expiry.d.ts +16 -0
- package/dist/shared/dynamodb/expiry.js +29 -0
- package/dist/shared/dynamodb/paginate-core.d.ts +5 -3
- package/dist/shared/dynamodb/paginate-core.js +47 -17
- package/dist/shared/dynamodb/paginate.d.ts +0 -1
- package/dist/shared/dynamodb/paginate.js +1 -2
- package/dist/shared/dynamodb/partition-delete.d.ts +7 -1
- package/dist/shared/dynamodb/partition-delete.js +4 -3
- package/dist/shared/dynamodb/retry-classifier.d.ts +10 -2
- package/dist/shared/dynamodb/retry-classifier.js +42 -11
- package/dist/shared/dynamodb/retry-policy.d.ts +26 -0
- package/dist/shared/dynamodb/retry-policy.js +22 -0
- package/dist/shared/dynamodb/retry.d.ts +14 -1
- package/dist/shared/dynamodb/retry.js +11 -7
- package/dist/shared/dynamodb/scan.d.ts +0 -1
- package/dist/shared/dynamodb/scan.js +1 -2
- package/dist/shared/dynamodb/types.d.ts +1 -2
- package/dist/shared/dynamodb/types.js +0 -1
- package/dist/shared/errors/base-error.d.ts +14 -6
- package/dist/shared/errors/base-error.js +8 -9
- package/dist/shared/errors/boundary.d.ts +18 -0
- package/dist/shared/errors/boundary.js +46 -0
- package/dist/shared/errors/error-code.d.ts +2 -2
- package/dist/shared/errors/error-code.js +1 -1
- package/dist/shared/errors/errors.d.ts +13 -13
- package/dist/shared/errors/errors.js +18 -16
- package/dist/shared/errors/upstream-error.d.ts +16 -0
- package/dist/shared/errors/upstream-error.js +27 -0
- package/dist/shared/errors/wrap-error.d.ts +0 -9
- package/dist/shared/errors/wrap-error.js +0 -15
- package/dist/shared/logging/logger.d.ts +6 -2
- package/dist/shared/logging/logger.js +0 -1
- package/dist/shared/logging/redaction-walk.d.ts +2 -2
- package/dist/shared/logging/redaction-walk.js +38 -18
- package/dist/shared/logging/redaction.d.ts +14 -6
- package/dist/shared/logging/redaction.js +19 -4
- package/dist/shared/logging/secret-patterns.d.ts +54 -3
- package/dist/shared/logging/secret-patterns.js +67 -8
- package/dist/shared/options.d.ts +9 -4
- package/dist/shared/options.js +0 -1
- package/dist/shared/ulid.d.ts +15 -2
- package/dist/shared/ulid.js +35 -3
- package/dist/shared/validation/options.d.ts +8 -0
- package/dist/shared/validation/options.js +90 -0
- package/dist/shared/validation/primitives.d.ts +14 -10
- package/dist/shared/validation/primitives.js +23 -25
- package/dist/shared/validation/ttl.d.ts +14 -7
- package/dist/shared/validation/ttl.js +29 -11
- package/dist/store/actions/get.d.ts +11 -3
- package/dist/store/actions/get.js +52 -14
- package/dist/store/actions/list-namespaces.d.ts +0 -1
- package/dist/store/actions/list-namespaces.js +10 -6
- package/dist/store/actions/put.d.ts +0 -1
- package/dist/store/actions/put.js +27 -28
- package/dist/store/actions/reconcile-vector-index.d.ts +3 -2
- package/dist/store/actions/reconcile-vector-index.js +2 -3
- package/dist/store/actions/search.d.ts +1 -2
- package/dist/store/actions/search.js +11 -38
- package/dist/store/internal/backend-search.d.ts +1 -2
- package/dist/store/internal/backend-search.js +14 -7
- package/dist/store/internal/batch-plan.d.ts +11 -0
- package/dist/store/internal/batch-plan.js +52 -0
- package/dist/store/internal/candidates.d.ts +23 -0
- package/dist/store/internal/candidates.js +94 -0
- package/dist/store/internal/filter.d.ts +0 -1
- package/dist/store/internal/filter.js +25 -6
- package/dist/store/internal/index-reconcile.d.ts +5 -6
- package/dist/store/internal/index-reconcile.js +32 -13
- package/dist/store/internal/index-sync.d.ts +0 -1
- package/dist/store/internal/index-sync.js +0 -1
- package/dist/store/internal/item-mapper.d.ts +6 -3
- package/dist/store/internal/item-mapper.js +16 -6
- package/dist/store/internal/keys.d.ts +0 -1
- package/dist/store/internal/keys.js +0 -1
- package/dist/store/internal/namespace-match.d.ts +0 -1
- package/dist/store/internal/namespace-match.js +0 -1
- package/dist/store/internal/option-validation.d.ts +13 -0
- package/dist/store/internal/option-validation.js +77 -0
- package/dist/store/internal/overwrite-swap.d.ts +32 -0
- package/dist/store/internal/overwrite-swap.js +68 -0
- package/dist/store/internal/persist.d.ts +24 -7
- package/dist/store/internal/persist.js +49 -19
- package/dist/store/internal/query.d.ts +6 -1
- package/dist/store/internal/query.js +17 -1
- package/dist/store/internal/ranker.d.ts +7 -2
- package/dist/store/internal/ranker.js +10 -2
- package/dist/store/internal/read-existing.d.ts +23 -0
- package/dist/store/internal/read-existing.js +41 -0
- package/dist/store/internal/score-direction.d.ts +31 -0
- package/dist/store/internal/score-direction.js +38 -0
- package/dist/store/internal/search-filter.d.ts +0 -1
- package/dist/store/internal/search-filter.js +0 -1
- package/dist/store/internal/semantic-search.d.ts +26 -5
- package/dist/store/internal/semantic-search.js +59 -19
- package/dist/store/internal/setup.d.ts +6 -12
- package/dist/store/internal/setup.js +12 -24
- package/dist/store/internal/text-path.d.ts +17 -0
- package/dist/store/internal/text-path.js +147 -0
- package/dist/store/internal/validation.d.ts +8 -3
- package/dist/store/internal/validation.js +21 -5
- package/dist/store/internal/write-verify.d.ts +27 -9
- package/dist/store/internal/write-verify.js +35 -19
- package/dist/store/store.d.ts +37 -9
- package/dist/store/store.js +52 -17
- package/dist/store/types.d.ts +22 -2
- package/dist/store/types.js +0 -1
- package/dist/store/vector-backend.d.ts +6 -7
- package/dist/store/vector-backend.js +0 -1
- package/package.json +21 -15
- 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.map +0 -1
- package/dist/checkpointer/internal/assemble.js.map +0 -1
- package/dist/checkpointer/internal/configurable.d.ts.map +0 -1
- package/dist/checkpointer/internal/configurable.js.map +0 -1
- package/dist/checkpointer/internal/fetch.d.ts.map +0 -1
- package/dist/checkpointer/internal/fetch.js.map +0 -1
- package/dist/checkpointer/internal/filter-match.d.ts.map +0 -1
- package/dist/checkpointer/internal/filter-match.js.map +0 -1
- package/dist/checkpointer/internal/item-reader.d.ts.map +0 -1
- package/dist/checkpointer/internal/item-reader.js.map +0 -1
- package/dist/checkpointer/internal/item-writer.d.ts.map +0 -1
- package/dist/checkpointer/internal/item-writer.js.map +0 -1
- package/dist/checkpointer/internal/keys.d.ts.map +0 -1
- package/dist/checkpointer/internal/keys.js.map +0 -1
- package/dist/checkpointer/internal/query.d.ts.map +0 -1
- 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-cleanup.d.ts.map +0 -1
- package/dist/checkpointer/internal/special-write-cleanup.js.map +0 -1
- package/dist/checkpointer/internal/validation.d.ts.map +0 -1
- package/dist/checkpointer/internal/validation.js.map +0 -1
- package/dist/checkpointer/internal/write-guard.d.ts.map +0 -1
- package/dist/checkpointer/internal/write-guard.js.map +0 -1
- package/dist/checkpointer/internal/write-index.d.ts.map +0 -1
- 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.map +0 -1
- package/dist/history/internal/append-saga.js.map +0 -1
- package/dist/history/internal/compensation.d.ts.map +0 -1
- package/dist/history/internal/compensation.js.map +0 -1
- package/dist/history/internal/item-mapper.d.ts.map +0 -1
- package/dist/history/internal/item-mapper.js.map +0 -1
- package/dist/history/internal/keys.d.ts.map +0 -1
- package/dist/history/internal/keys.js.map +0 -1
- package/dist/history/internal/message-chunker.d.ts.map +0 -1
- package/dist/history/internal/message-chunker.js.map +0 -1
- package/dist/history/internal/message-transaction.d.ts.map +0 -1
- package/dist/history/internal/message-transaction.js.map +0 -1
- package/dist/history/internal/query.d.ts.map +0 -1
- package/dist/history/internal/query.js.map +0 -1
- package/dist/history/internal/session-count.d.ts.map +0 -1
- package/dist/history/internal/session-count.js.map +0 -1
- package/dist/history/internal/session-title.d.ts.map +0 -1
- package/dist/history/internal/session-title.js.map +0 -1
- package/dist/history/internal/session-update.d.ts.map +0 -1
- 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.map +0 -1
- package/dist/history/internal/title-generator.js.map +0 -1
- package/dist/history/internal/ttl-anchor.d.ts.map +0 -1
- package/dist/history/internal/ttl-anchor.js.map +0 -1
- package/dist/history/internal/validation.d.ts.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- package/dist/shared/codec/s3/orphans.js.map +0 -1
- package/dist/shared/codec/s3/read-write.d.ts.map +0 -1
- package/dist/shared/codec/s3/read-write.js.map +0 -1
- package/dist/shared/codec/s3/retry.d.ts.map +0 -1
- package/dist/shared/codec/s3/retry.js.map +0 -1
- package/dist/shared/constants.d.ts.map +0 -1
- package/dist/shared/constants.js.map +0 -1
- package/dist/shared/dynamodb/backoff.d.ts.map +0 -1
- 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/drain-unprocessed.d.ts.map +0 -1
- package/dist/shared/dynamodb/drain-unprocessed.js.map +0 -1
- package/dist/shared/dynamodb/paginate-core.d.ts.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- package/dist/shared/dynamodb/scan.js.map +0 -1
- package/dist/shared/dynamodb/types.d.ts.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- package/dist/store/internal/index-reconcile.js.map +0 -1
- package/dist/store/internal/index-sync.d.ts.map +0 -1
- package/dist/store/internal/index-sync.js.map +0 -1
- package/dist/store/internal/item-mapper.d.ts.map +0 -1
- package/dist/store/internal/item-mapper.js.map +0 -1
- package/dist/store/internal/keys.d.ts.map +0 -1
- package/dist/store/internal/keys.js.map +0 -1
- package/dist/store/internal/namespace-match.d.ts.map +0 -1
- package/dist/store/internal/namespace-match.js.map +0 -1
- package/dist/store/internal/persist.d.ts.map +0 -1
- package/dist/store/internal/persist.js.map +0 -1
- package/dist/store/internal/query.d.ts.map +0 -1
- package/dist/store/internal/query.js.map +0 -1
- package/dist/store/internal/ranker.d.ts.map +0 -1
- package/dist/store/internal/ranker.js.map +0 -1
- package/dist/store/internal/search-filter.d.ts.map +0 -1
- 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.map +0 -1
- package/dist/store/internal/validation.js.map +0 -1
- package/dist/store/internal/write-verify.d.ts.map +0 -1
- 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,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oversizedObjectError = oversizedObjectError;
|
|
4
|
+
exports.readBodyBounded = readBodyBounded;
|
|
5
|
+
const base_error_1 = require("../../errors/base-error");
|
|
6
|
+
const error_code_1 = require("../../errors/error-code");
|
|
7
|
+
/** The typed error for an object over the download cap. */
|
|
8
|
+
function oversizedObjectError(key, bytes, maxBytes) {
|
|
9
|
+
return new base_error_1.DynamoDBLangGraphError(`S3 object ${key} exceeds the ${maxBytes}-byte maxDownloadBytes cap ` +
|
|
10
|
+
`(${bytes} bytes declared or read)`, error_code_1.ErrorCode.S3_OFFLOAD_FAILED, { operation: 'download', key });
|
|
11
|
+
}
|
|
12
|
+
function concat(chunks, total) {
|
|
13
|
+
const out = new Uint8Array(total);
|
|
14
|
+
let offset = 0;
|
|
15
|
+
for (const chunk of chunks) {
|
|
16
|
+
out.set(chunk, offset);
|
|
17
|
+
offset += chunk.length;
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Buffer an S3 body without ever holding more than `maxBytes` of it. A
|
|
23
|
+
* streaming body is consumed chunk by chunk and abandoned the moment the
|
|
24
|
+
* running total passes the cap; a body that only offers
|
|
25
|
+
* `transformToByteArray()` is read whole and then checked.
|
|
26
|
+
*/
|
|
27
|
+
async function readBodyBounded(body, key, maxBytes) {
|
|
28
|
+
const streaming = body;
|
|
29
|
+
const iterate = streaming[Symbol.asyncIterator];
|
|
30
|
+
if (typeof iterate !== 'function') {
|
|
31
|
+
const whole = new Uint8Array(await body.transformToByteArray());
|
|
32
|
+
if (whole.length > maxBytes)
|
|
33
|
+
throw oversizedObjectError(key, whole.length, maxBytes);
|
|
34
|
+
return whole;
|
|
35
|
+
}
|
|
36
|
+
const chunks = [];
|
|
37
|
+
let total = 0;
|
|
38
|
+
for await (const chunk of { [Symbol.asyncIterator]: iterate.bind(streaming) }) {
|
|
39
|
+
total += chunk.length;
|
|
40
|
+
if (total > maxBytes) {
|
|
41
|
+
streaming.destroy?.();
|
|
42
|
+
throw oversizedObjectError(key, total, maxBytes);
|
|
43
|
+
}
|
|
44
|
+
chunks.push(chunk);
|
|
45
|
+
}
|
|
46
|
+
return concat(chunks, total);
|
|
47
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** A region as the SDK accepts it: a string or a provider resolving to one. */
|
|
2
|
+
export type S3RegionLike = string | (() => Promise<string>);
|
|
3
|
+
/** A value an S3 client option can hold. */
|
|
4
|
+
export type S3ClientOption = string | number | boolean | object | null | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* The S3 client options this library reads (`region`) or sets (`maxAttempts`),
|
|
7
|
+
* open to every other `S3ClientConfig` key.
|
|
8
|
+
*/
|
|
9
|
+
export interface S3ClientOptions {
|
|
10
|
+
region?: S3RegionLike;
|
|
11
|
+
maxAttempts?: number;
|
|
12
|
+
[option: string]: S3ClientOption;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Structural stand-in for `S3ClientConfig`, so the shipped declarations compile
|
|
16
|
+
* without the optional `@aws-sdk/client-s3` peer installed. A literal gets
|
|
17
|
+
* completion for the options the library uses; a typed `S3ClientConfig`
|
|
18
|
+
* variable is accepted as it is.
|
|
19
|
+
*/
|
|
20
|
+
export type S3ClientConfigLike = S3ClientOptions | object;
|
|
21
|
+
/** The options of a config, read through the structural type. */
|
|
22
|
+
export declare function s3ClientOptions(config: S3ClientConfigLike | undefined): S3ClientOptions;
|
|
23
|
+
/** What every SDK command object carries: its `input`. */
|
|
24
|
+
export interface S3CommandLike {
|
|
25
|
+
input: object;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The S3 client surface this library calls, typed structurally for the same
|
|
29
|
+
* reason. `S3Client` from `@aws-sdk/client-s3` satisfies it.
|
|
30
|
+
*/
|
|
31
|
+
export interface S3ClientLike {
|
|
32
|
+
send(command: S3CommandLike, options?: object): Promise<object>;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import type { S3Client
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import type { S3ClientConfigLike } from './client-types';
|
|
3
|
+
type S3Sdk = typeof import('@aws-sdk/client-s3');
|
|
4
|
+
/**
|
|
5
|
+
* Lazily import the optional `@aws-sdk/client-s3` peer, caching the module. A
|
|
6
|
+
* failed import is not cached, so an install or a fixed bundle can succeed on
|
|
7
|
+
* a later call.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadS3Sdk(): Promise<S3Sdk>;
|
|
4
10
|
/**
|
|
5
11
|
* Construct an `S3Client` from `config` using the lazily-loaded SDK. Defaults
|
|
6
12
|
* `maxAttempts: 1` so the SDK's own internal retries are disabled and this
|
|
@@ -8,5 +14,5 @@ export declare function loadS3Sdk(): Promise<typeof import('@aws-sdk/client-s3')
|
|
|
8
14
|
* matching {@link resolveDynamoDBClient}'s equivalent default; an explicit
|
|
9
15
|
* `maxAttempts` in `config` still wins.
|
|
10
16
|
*/
|
|
11
|
-
export declare function createDefaultS3Client(config:
|
|
12
|
-
|
|
17
|
+
export declare function createDefaultS3Client(config: S3ClientConfigLike): Promise<S3Client>;
|
|
18
|
+
export {};
|
|
@@ -2,11 +2,34 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.loadS3Sdk = loadS3Sdk;
|
|
4
4
|
exports.createDefaultS3Client = createDefaultS3Client;
|
|
5
|
+
const errors_1 = require("../../errors/errors");
|
|
6
|
+
/** Codes Node and bundlers use for an import that cannot be resolved. */
|
|
7
|
+
const MISSING_MODULE_CODES = ['ERR_MODULE_NOT_FOUND', 'MODULE_NOT_FOUND'];
|
|
5
8
|
let sdkPromise;
|
|
6
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Convert a failed import of the optional peer into a typed error that names
|
|
11
|
+
* the remedy. Any other failure (a broken build, a syntax error inside the
|
|
12
|
+
* package) passes through unchanged.
|
|
13
|
+
*/
|
|
14
|
+
function wrapMissingPeer(error) {
|
|
15
|
+
const code = error.code;
|
|
16
|
+
if (code !== undefined && MISSING_MODULE_CODES.includes(code)) {
|
|
17
|
+
throw new errors_1.ValidationError('S3 offload requires the optional peer @aws-sdk/client-s3 (npm install @aws-sdk/client-s3); ' +
|
|
18
|
+
'bundlers must keep it installed or external', 's3', error);
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Lazily import the optional `@aws-sdk/client-s3` peer, caching the module. A
|
|
24
|
+
* failed import is not cached, so an install or a fixed bundle can succeed on
|
|
25
|
+
* a later call.
|
|
26
|
+
*/
|
|
7
27
|
async function loadS3Sdk() {
|
|
8
28
|
if (!sdkPromise) {
|
|
9
|
-
sdkPromise = import('@aws-sdk/client-s3')
|
|
29
|
+
sdkPromise = import('@aws-sdk/client-s3').catch((error) => {
|
|
30
|
+
sdkPromise = undefined;
|
|
31
|
+
return wrapMissingPeer(error);
|
|
32
|
+
});
|
|
10
33
|
}
|
|
11
34
|
return sdkPromise;
|
|
12
35
|
}
|
|
@@ -21,4 +44,3 @@ async function createDefaultS3Client(config) {
|
|
|
21
44
|
const { S3Client: S3ClientCtor } = await loadS3Sdk();
|
|
22
45
|
return new S3ClientCtor({ maxAttempts: 1, ...config });
|
|
23
46
|
}
|
|
24
|
-
//# sourceMappingURL=client.js.map
|
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { S3ClientConfigLike } from './client-types';
|
|
2
2
|
/** Configuration for offloading large payloads to S3. */
|
|
3
3
|
export interface S3OffloadConfig {
|
|
4
4
|
bucketName: string;
|
|
5
5
|
keyPrefix?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Serialized payloads at or above this size are offloaded (default 350 KB).
|
|
8
|
+
* Only the payload counts: the store's inline embedding (about 10 bytes per
|
|
9
|
+
* dimension, so ~10 KB at 1024 dims and ~45 KB at 4096) lives on the same
|
|
10
|
+
* item and is not part of it, so keep `thresholdBytes` plus the embedding
|
|
11
|
+
* under DynamoDB's 400 KB item limit or the put fails with a raw
|
|
12
|
+
* `ValidationException`.
|
|
13
|
+
*/
|
|
6
14
|
thresholdBytes?: number;
|
|
7
15
|
serverSideEncryption?: string;
|
|
8
16
|
sseKmsKeyId?: string;
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
/** Largest object this adapter will buffer from S3 (default 50 MiB). */
|
|
18
|
+
maxDownloadBytes?: number;
|
|
19
|
+
/**
|
|
20
|
+
* S3 client configuration (an `S3ClientConfig`). `region` defaults to the
|
|
21
|
+
* adapter's DynamoDB region.
|
|
22
|
+
*/
|
|
23
|
+
clientConfig?: S3ClientConfigLike;
|
|
11
24
|
}
|
|
12
25
|
/**
|
|
13
26
|
* Build a fully-qualified S3 key: `${prefix}${parts, each base64url-encoded,
|
|
@@ -15,10 +28,24 @@ export interface S3OffloadConfig {
|
|
|
15
28
|
* `parts` arrays never collide, since a namespace element or key is allowed
|
|
16
29
|
* to contain '/' (only the DynamoDB '#' separator is forbidden at the
|
|
17
30
|
* validation layer) and base64url's output alphabet never contains '/'.
|
|
31
|
+
*
|
|
32
|
+
* The produced key is checked against S3's 1024-byte object-key cap: the
|
|
33
|
+
* encoding grows every part by a third, so identifiers that each pass their
|
|
34
|
+
* own length rule can still compose a key S3 would reject with a raw error.
|
|
18
35
|
*/
|
|
19
36
|
export declare function buildS3Key(prefix: string, parts: readonly string[]): string;
|
|
20
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* The key prefix doubles as the S3 lifecycle rule's `Filter.Prefix`. An empty
|
|
39
|
+
* or root prefix would make that rule expire the whole bucket, and a prefix
|
|
40
|
+
* without a trailing `/` (`app/langgraph`) would also match every sibling
|
|
41
|
+
* object that merely starts with the same characters (`app/langgraph-other/`).
|
|
42
|
+
*/
|
|
43
|
+
export declare function assertScopedKeyPrefix(keyPrefix: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Build a deterministic, TTL-independent lifecycle rule id from the prefix.
|
|
46
|
+
* Trailing slashes are trimmed with a loop rather than `/\/+$/`, whose
|
|
47
|
+
* backtracking is quadratic in the number of slashes.
|
|
48
|
+
*/
|
|
21
49
|
export declare function buildLifecycleRuleId(prefix: string): string;
|
|
22
50
|
/** An adapter's default S3 key prefix: the shared base plus its own segment. */
|
|
23
51
|
export declare function defaultAdapterKeyPrefix(base: string, adapter: string): string;
|
|
24
|
-
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1,26 +1,58 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildS3Key = buildS3Key;
|
|
4
|
+
exports.assertScopedKeyPrefix = assertScopedKeyPrefix;
|
|
4
5
|
exports.buildLifecycleRuleId = buildLifecycleRuleId;
|
|
5
6
|
exports.defaultAdapterKeyPrefix = defaultAdapterKeyPrefix;
|
|
7
|
+
const constants_1 = require("../../constants");
|
|
8
|
+
const errors_1 = require("../../errors/errors");
|
|
9
|
+
const key_scope_1 = require("./key-scope");
|
|
6
10
|
/**
|
|
7
11
|
* Build a fully-qualified S3 key: `${prefix}${parts, each base64url-encoded,
|
|
8
12
|
* joined with '/'}.bin`. Encoding (not rejecting) is what makes two distinct
|
|
9
13
|
* `parts` arrays never collide, since a namespace element or key is allowed
|
|
10
14
|
* to contain '/' (only the DynamoDB '#' separator is forbidden at the
|
|
11
15
|
* validation layer) and base64url's output alphabet never contains '/'.
|
|
16
|
+
*
|
|
17
|
+
* The produced key is checked against S3's 1024-byte object-key cap: the
|
|
18
|
+
* encoding grows every part by a third, so identifiers that each pass their
|
|
19
|
+
* own length rule can still compose a key S3 would reject with a raw error.
|
|
12
20
|
*/
|
|
13
21
|
function buildS3Key(prefix, parts) {
|
|
14
|
-
const encoded = parts.map(
|
|
15
|
-
|
|
22
|
+
const encoded = parts.map(key_scope_1.encodeKeyPart);
|
|
23
|
+
const key = `${prefix}${encoded.join('/')}.bin`;
|
|
24
|
+
const bytes = Buffer.byteLength(key, 'utf8');
|
|
25
|
+
if (bytes > constants_1.MAX_S3_KEY_BYTES) {
|
|
26
|
+
throw new errors_1.ValidationError(`the offloaded S3 object key would be ${bytes} bytes; S3 caps keys at ` +
|
|
27
|
+
`${constants_1.MAX_S3_KEY_BYTES} — shorten the identifiers or the keyPrefix`, 's3Key');
|
|
28
|
+
}
|
|
29
|
+
return key;
|
|
16
30
|
}
|
|
17
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* The key prefix doubles as the S3 lifecycle rule's `Filter.Prefix`. An empty
|
|
33
|
+
* or root prefix would make that rule expire the whole bucket, and a prefix
|
|
34
|
+
* without a trailing `/` (`app/langgraph`) would also match every sibling
|
|
35
|
+
* object that merely starts with the same characters (`app/langgraph-other/`).
|
|
36
|
+
*/
|
|
37
|
+
function assertScopedKeyPrefix(keyPrefix) {
|
|
38
|
+
if (keyPrefix === '' || keyPrefix === '/' || !keyPrefix.endsWith('/')) {
|
|
39
|
+
throw new errors_1.ValidationError('s3.keyPrefix must be a non-empty path that ends with "/" (for example "langgraph/"): ' +
|
|
40
|
+
'it scopes both the offloaded objects and the S3 lifecycle rule', 's3.keyPrefix');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a deterministic, TTL-independent lifecycle rule id from the prefix.
|
|
45
|
+
* Trailing slashes are trimmed with a loop rather than `/\/+$/`, whose
|
|
46
|
+
* backtracking is quadratic in the number of slashes.
|
|
47
|
+
*/
|
|
18
48
|
function buildLifecycleRuleId(prefix) {
|
|
19
|
-
|
|
49
|
+
let trimmed = prefix;
|
|
50
|
+
while (trimmed.endsWith('/'))
|
|
51
|
+
trimmed = trimmed.slice(0, -1);
|
|
52
|
+
const slug = trimmed.replace(/[^a-zA-Z0-9-]/g, '-') || 'default';
|
|
20
53
|
return `langgraph-ttl-${slug}`;
|
|
21
54
|
}
|
|
22
55
|
/** An adapter's default S3 key prefix: the shared base plus its own segment. */
|
|
23
56
|
function defaultAdapterKeyPrefix(base, adapter) {
|
|
24
57
|
return `${base}${adapter}/`;
|
|
25
58
|
}
|
|
26
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** base64url-encode one key part; the output alphabet never contains `/` or `.`. */
|
|
2
|
+
export declare function encodeKeyPart(part: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* The path every key `buildS3Key(prefix, [...parts, ...more])` shares: the
|
|
5
|
+
* prefix plus the encoded `parts` joined by `/`, with neither `.bin` nor a
|
|
6
|
+
* trailing `/`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function s3KeyScope(prefix: string, parts: readonly string[]): string;
|
|
9
|
+
/**
|
|
10
|
+
* True when `key` was produced by `buildS3Key` from exactly `parts`
|
|
11
|
+
* (`<scope>.bin`) or from `parts` plus further parts (`<scope>/…`). An empty
|
|
12
|
+
* `parts` degrades to a prefix-only check. Because parts are base64url-encoded
|
|
13
|
+
* and joined by `/`, an identifier sharing a leading substring with another
|
|
14
|
+
* (`t` and `t1`) never matches its scope.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isKeyInScope(key: string, prefix: string, parts: readonly string[]): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Refuse a row-sourced `s3Key` that lies outside the path the row's own
|
|
19
|
+
* identifiers produce. A row is trusted for its shape, not for the object it
|
|
20
|
+
* points at: a writer able to place one row in a partition must not be able
|
|
21
|
+
* to make this library download or delete another tenant's object.
|
|
22
|
+
*/
|
|
23
|
+
export declare function assertKeyInScope(key: string, prefix: string, parts: readonly string[]): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeKeyPart = encodeKeyPart;
|
|
4
|
+
exports.s3KeyScope = s3KeyScope;
|
|
5
|
+
exports.isKeyInScope = isKeyInScope;
|
|
6
|
+
exports.assertKeyInScope = assertKeyInScope;
|
|
7
|
+
const errors_1 = require("../../errors/errors");
|
|
8
|
+
/** base64url-encode one key part; the output alphabet never contains `/` or `.`. */
|
|
9
|
+
function encodeKeyPart(part) {
|
|
10
|
+
return Buffer.from(part, 'utf8').toString('base64url');
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The path every key `buildS3Key(prefix, [...parts, ...more])` shares: the
|
|
14
|
+
* prefix plus the encoded `parts` joined by `/`, with neither `.bin` nor a
|
|
15
|
+
* trailing `/`.
|
|
16
|
+
*/
|
|
17
|
+
function s3KeyScope(prefix, parts) {
|
|
18
|
+
return `${prefix}${parts.map(encodeKeyPart).join('/')}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* True when `key` was produced by `buildS3Key` from exactly `parts`
|
|
22
|
+
* (`<scope>.bin`) or from `parts` plus further parts (`<scope>/…`). An empty
|
|
23
|
+
* `parts` degrades to a prefix-only check. Because parts are base64url-encoded
|
|
24
|
+
* and joined by `/`, an identifier sharing a leading substring with another
|
|
25
|
+
* (`t` and `t1`) never matches its scope.
|
|
26
|
+
*/
|
|
27
|
+
function isKeyInScope(key, prefix, parts) {
|
|
28
|
+
const scope = s3KeyScope(prefix, parts);
|
|
29
|
+
if (parts.length === 0)
|
|
30
|
+
return key.startsWith(scope);
|
|
31
|
+
return key === `${scope}.bin` || key.startsWith(`${scope}/`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Refuse a row-sourced `s3Key` that lies outside the path the row's own
|
|
35
|
+
* identifiers produce. A row is trusted for its shape, not for the object it
|
|
36
|
+
* points at: a writer able to place one row in a partition must not be able
|
|
37
|
+
* to make this library download or delete another tenant's object.
|
|
38
|
+
*/
|
|
39
|
+
function assertKeyInScope(key, prefix, parts) {
|
|
40
|
+
if (isKeyInScope(key, prefix, parts))
|
|
41
|
+
return;
|
|
42
|
+
throw new errors_1.ValidationError(`s3Key "${key}" lies outside the S3 path this row may reference ` +
|
|
43
|
+
`("${s3KeyScope(prefix, parts)}"); refusing to touch an object the row does not own`, 's3Key');
|
|
44
|
+
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { S3Client } from '@aws-sdk/client-s3';
|
|
2
2
|
/**
|
|
3
|
-
* Idempotently ensure a
|
|
4
|
-
* `prefix`. Reads existing rules, preserves user-defined ones
|
|
5
|
-
*
|
|
3
|
+
* Idempotently ensure a `days`-day expiration lifecycle rule exists for
|
|
4
|
+
* `prefix`. Reads existing rules, preserves user-defined ones and the
|
|
5
|
+
* bucket-level `TransitionDefaultMinimumObjectSize` (a Put replaces the whole
|
|
6
|
+
* configuration, so dropping it would reset the bucket to the default), and
|
|
7
|
+
* only adds/updates the library's prefix-scoped rule.
|
|
8
|
+
*
|
|
9
|
+
* Noncurrent versions expire after the same number of days, so a versioned
|
|
10
|
+
* bucket does not retain every superseded payload forever; the field is inert
|
|
11
|
+
* on an unversioned bucket. The prefix is re-checked here because this rule is
|
|
12
|
+
* the one place an unscoped prefix would destroy data outside this library's.
|
|
6
13
|
*/
|
|
7
|
-
export declare function ensureLifecycleRule(client: S3Client, bucket: string, prefix: string,
|
|
8
|
-
//# sourceMappingURL=lifecycle.d.ts.map
|
|
14
|
+
export declare function ensureLifecycleRule(client: S3Client, bucket: string, prefix: string, days: number): Promise<void>;
|
|
@@ -3,45 +3,61 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ensureLifecycleRule = ensureLifecycleRule;
|
|
4
4
|
const client_1 = require("./client");
|
|
5
5
|
const config_1 = require("./config");
|
|
6
|
-
async function
|
|
6
|
+
async function readState(client, bucket) {
|
|
7
7
|
const { GetBucketLifecycleConfigurationCommand } = await (0, client_1.loadS3Sdk)();
|
|
8
8
|
try {
|
|
9
9
|
const existing = await client.send(new GetBucketLifecycleConfigurationCommand({ Bucket: bucket }));
|
|
10
|
-
return
|
|
10
|
+
return {
|
|
11
|
+
rules: existing.Rules ?? [],
|
|
12
|
+
transitionDefaultMinimumObjectSize: existing.TransitionDefaultMinimumObjectSize,
|
|
13
|
+
};
|
|
11
14
|
}
|
|
12
15
|
catch (error) {
|
|
13
16
|
if (error.name === 'NoSuchLifecycleConfiguration')
|
|
14
|
-
return [];
|
|
17
|
+
return { rules: [] };
|
|
15
18
|
throw error;
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
|
-
function alreadyCorrect(rule,
|
|
19
|
-
return rule?.Status === 'Enabled' &&
|
|
21
|
+
function alreadyCorrect(rule, days) {
|
|
22
|
+
return (rule?.Status === 'Enabled' &&
|
|
23
|
+
rule.Expiration?.Days === days &&
|
|
24
|
+
rule.NoncurrentVersionExpiration?.NoncurrentDays === days);
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
|
-
* Idempotently ensure a
|
|
23
|
-
* `prefix`. Reads existing rules, preserves user-defined ones
|
|
24
|
-
*
|
|
27
|
+
* Idempotently ensure a `days`-day expiration lifecycle rule exists for
|
|
28
|
+
* `prefix`. Reads existing rules, preserves user-defined ones and the
|
|
29
|
+
* bucket-level `TransitionDefaultMinimumObjectSize` (a Put replaces the whole
|
|
30
|
+
* configuration, so dropping it would reset the bucket to the default), and
|
|
31
|
+
* only adds/updates the library's prefix-scoped rule.
|
|
32
|
+
*
|
|
33
|
+
* Noncurrent versions expire after the same number of days, so a versioned
|
|
34
|
+
* bucket does not retain every superseded payload forever; the field is inert
|
|
35
|
+
* on an unversioned bucket. The prefix is re-checked here because this rule is
|
|
36
|
+
* the one place an unscoped prefix would destroy data outside this library's.
|
|
25
37
|
*/
|
|
26
|
-
async function ensureLifecycleRule(client, bucket, prefix,
|
|
38
|
+
async function ensureLifecycleRule(client, bucket, prefix, days) {
|
|
39
|
+
(0, config_1.assertScopedKeyPrefix)(prefix);
|
|
27
40
|
const ruleId = (0, config_1.buildLifecycleRuleId)(prefix);
|
|
28
|
-
const
|
|
29
|
-
const existing = rules.find((rule) => rule.ID === ruleId);
|
|
30
|
-
if (alreadyCorrect(existing,
|
|
41
|
+
const state = await readState(client, bucket);
|
|
42
|
+
const existing = state.rules.find((rule) => rule.ID === ruleId);
|
|
43
|
+
if (alreadyCorrect(existing, days))
|
|
31
44
|
return;
|
|
32
45
|
const newRule = {
|
|
33
46
|
ID: ruleId,
|
|
34
47
|
Filter: { Prefix: prefix },
|
|
35
48
|
Status: 'Enabled',
|
|
36
|
-
Expiration: { Days:
|
|
49
|
+
Expiration: { Days: days },
|
|
50
|
+
NoncurrentVersionExpiration: { NoncurrentDays: days },
|
|
37
51
|
};
|
|
38
52
|
const merged = existing
|
|
39
|
-
? rules.map((rule) => (rule.ID === ruleId ? newRule : rule))
|
|
40
|
-
: [...rules, newRule];
|
|
53
|
+
? state.rules.map((rule) => (rule.ID === ruleId ? newRule : rule))
|
|
54
|
+
: [...state.rules, newRule];
|
|
41
55
|
const { PutBucketLifecycleConfigurationCommand } = await (0, client_1.loadS3Sdk)();
|
|
42
56
|
await client.send(new PutBucketLifecycleConfigurationCommand({
|
|
43
57
|
Bucket: bucket,
|
|
44
58
|
LifecycleConfiguration: { Rules: merged },
|
|
59
|
+
...(state.transitionDefaultMinimumObjectSize === undefined
|
|
60
|
+
? {}
|
|
61
|
+
: { TransitionDefaultMinimumObjectSize: state.transitionDefaultMinimumObjectSize }),
|
|
45
62
|
}));
|
|
46
63
|
}
|
|
47
|
-
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -12,6 +12,7 @@ export declare class S3Offloader {
|
|
|
12
12
|
private readonly thresholdBytes;
|
|
13
13
|
private readonly sse;
|
|
14
14
|
private readonly sseKmsKeyId?;
|
|
15
|
+
private readonly maxDownloadBytes;
|
|
15
16
|
private readonly config;
|
|
16
17
|
constructor(config: S3OffloadConfig);
|
|
17
18
|
private getClient;
|
|
@@ -21,9 +22,13 @@ export declare class S3Offloader {
|
|
|
21
22
|
buildKey(parts: readonly string[]): string;
|
|
22
23
|
/** The configured key prefix. */
|
|
23
24
|
getKeyPrefix(): string;
|
|
25
|
+
/** True when `key` lies under this offloader's prefix and the `scope` parts' path. */
|
|
26
|
+
ownsKey(key: string, scope: readonly string[]): boolean;
|
|
27
|
+
/** Refuse a row-sourced key outside the row's own path (see {@link assertKeyInScope}). */
|
|
28
|
+
assertOwnedKey(key: string, scope: readonly string[]): void;
|
|
24
29
|
/** Upload `data` under `key`, returning the key. */
|
|
25
30
|
upload(key: string, data: Uint8Array): Promise<string>;
|
|
26
|
-
/** Download the bytes stored under `key`. */
|
|
31
|
+
/** Download the bytes stored under `key`, refusing objects over `maxDownloadBytes`. */
|
|
27
32
|
download(key: string): Promise<Uint8Array>;
|
|
28
33
|
/** Delete `keys`, returning the keys S3 reported as failed. */
|
|
29
34
|
deleteBatch(keys: string[]): Promise<string[]>;
|
|
@@ -37,4 +42,3 @@ export declare class S3Offloader {
|
|
|
37
42
|
*/
|
|
38
43
|
destroy(): void;
|
|
39
44
|
}
|
|
40
|
-
//# sourceMappingURL=offloader.d.ts.map
|
|
@@ -5,6 +5,7 @@ const constants_1 = require("../../constants");
|
|
|
5
5
|
const client_1 = require("./client");
|
|
6
6
|
const config_1 = require("./config");
|
|
7
7
|
const delete_1 = require("./delete");
|
|
8
|
+
const key_scope_1 = require("./key-scope");
|
|
8
9
|
const lifecycle_1 = require("./lifecycle");
|
|
9
10
|
const read_write_1 = require("./read-write");
|
|
10
11
|
/**
|
|
@@ -20,6 +21,7 @@ class S3Offloader {
|
|
|
20
21
|
thresholdBytes;
|
|
21
22
|
sse;
|
|
22
23
|
sseKmsKeyId;
|
|
24
|
+
maxDownloadBytes;
|
|
23
25
|
config;
|
|
24
26
|
constructor(config) {
|
|
25
27
|
this.config = config;
|
|
@@ -28,10 +30,19 @@ class S3Offloader {
|
|
|
28
30
|
this.thresholdBytes = config.thresholdBytes ?? constants_1.DEFAULT_S3_THRESHOLD_BYTES;
|
|
29
31
|
this.sse = config.serverSideEncryption ?? constants_1.DEFAULT_S3_SSE;
|
|
30
32
|
this.sseKmsKeyId = config.sseKmsKeyId;
|
|
33
|
+
this.maxDownloadBytes = config.maxDownloadBytes ?? constants_1.DEFAULT_MAX_S3_DOWNLOAD_BYTES;
|
|
34
|
+
/**
|
|
35
|
+
* Warm the optional peer's import so a missing `@aws-sdk/client-s3`
|
|
36
|
+
* surfaces on the very first S3 operation, typed, rather than on the first
|
|
37
|
+
* oversize payload days later. The rejection is handled here; whichever
|
|
38
|
+
* operation runs first re-raises it through its own `loadS3Sdk()` call.
|
|
39
|
+
*/
|
|
40
|
+
void (0, client_1.loadS3Sdk)().catch(() => undefined);
|
|
31
41
|
}
|
|
32
42
|
getClient() {
|
|
33
43
|
if (!this.clientPromise) {
|
|
34
44
|
const cfg = this.config.clientConfig ?? {};
|
|
45
|
+
/** The hook is typed structurally for consumers; the runtime modules use the real SDK client. */
|
|
35
46
|
this.clientPromise = (this.config.createS3Client
|
|
36
47
|
? Promise.resolve(this.config.createS3Client({ maxAttempts: 1, ...cfg }))
|
|
37
48
|
: (0, client_1.createDefaultS3Client)(cfg)).then((client) => {
|
|
@@ -62,6 +73,14 @@ class S3Offloader {
|
|
|
62
73
|
getKeyPrefix() {
|
|
63
74
|
return this.keyPrefix;
|
|
64
75
|
}
|
|
76
|
+
/** True when `key` lies under this offloader's prefix and the `scope` parts' path. */
|
|
77
|
+
ownsKey(key, scope) {
|
|
78
|
+
return (0, key_scope_1.isKeyInScope)(key, this.keyPrefix, scope);
|
|
79
|
+
}
|
|
80
|
+
/** Refuse a row-sourced key outside the row's own path (see {@link assertKeyInScope}). */
|
|
81
|
+
assertOwnedKey(key, scope) {
|
|
82
|
+
(0, key_scope_1.assertKeyInScope)(key, this.keyPrefix, scope);
|
|
83
|
+
}
|
|
65
84
|
/** Upload `data` under `key`, returning the key. */
|
|
66
85
|
async upload(key, data) {
|
|
67
86
|
await (0, read_write_1.uploadObject)(await this.getClient(), {
|
|
@@ -73,9 +92,9 @@ class S3Offloader {
|
|
|
73
92
|
});
|
|
74
93
|
return key;
|
|
75
94
|
}
|
|
76
|
-
/** Download the bytes stored under `key`. */
|
|
95
|
+
/** Download the bytes stored under `key`, refusing objects over `maxDownloadBytes`. */
|
|
77
96
|
async download(key) {
|
|
78
|
-
return (0, read_write_1.downloadObject)(await this.getClient(), this.bucketName, key);
|
|
97
|
+
return (0, read_write_1.downloadObject)(await this.getClient(), this.bucketName, key, this.maxDownloadBytes);
|
|
79
98
|
}
|
|
80
99
|
/** Delete `keys`, returning the keys S3 reported as failed. */
|
|
81
100
|
async deleteBatch(keys) {
|
|
@@ -97,4 +116,3 @@ class S3Offloader {
|
|
|
97
116
|
}
|
|
98
117
|
}
|
|
99
118
|
exports.S3Offloader = S3Offloader;
|
|
100
|
-
//# sourceMappingURL=offloader.js.map
|
|
@@ -5,6 +5,12 @@ export interface OrphanCleanupOptions {
|
|
|
5
5
|
rng?: () => number;
|
|
6
6
|
maxAttempts?: number;
|
|
7
7
|
signal?: AbortSignal;
|
|
8
|
+
/**
|
|
9
|
+
* The row's own leading key parts when `keys` were read back from a row.
|
|
10
|
+
* A key outside the path they produce is never deleted, only reported; own
|
|
11
|
+
* uploads (built by this call) pass no scope.
|
|
12
|
+
*/
|
|
13
|
+
scope?: readonly string[];
|
|
8
14
|
}
|
|
9
15
|
/**
|
|
10
16
|
* Best-effort delete of S3 objects orphaned by a failed DynamoDB write. Retries
|
|
@@ -15,4 +21,3 @@ export interface OrphanCleanupOptions {
|
|
|
15
21
|
* `ensureS3LifecycleRule()`, which is opt-in.
|
|
16
22
|
*/
|
|
17
23
|
export declare function cleanUpS3Orphans(offloader: S3Offloader, keys: ReadonlyArray<string | undefined>, context: string, logger: Logger, options?: OrphanCleanupOptions): Promise<void>;
|
|
18
|
-
//# sourceMappingURL=orphans.d.ts.map
|
|
@@ -19,6 +19,20 @@ async function backoffSleep(delayMs, options) {
|
|
|
19
19
|
return true;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
/** Drop every key outside the row's scope, reporting each one. */
|
|
23
|
+
function ownedOnly(offloader, keys, scope, context, logger) {
|
|
24
|
+
return keys.filter((key) => {
|
|
25
|
+
if (offloader.ownsKey(key, scope))
|
|
26
|
+
return true;
|
|
27
|
+
logger.warn(`${context}: refusing to delete an S3 object outside this row's scope`, { key });
|
|
28
|
+
return false;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** The non-empty keys, restricted to the row's scope when one is given. */
|
|
32
|
+
function selectOrphans(offloader, keys, context, logger, options) {
|
|
33
|
+
const present = keys.filter((key) => typeof key === 'string' && key.length > 0);
|
|
34
|
+
return options.scope ? ownedOnly(offloader, present, options.scope, context, logger) : present;
|
|
35
|
+
}
|
|
22
36
|
/**
|
|
23
37
|
* Best-effort delete of S3 objects orphaned by a failed DynamoDB write. Retries
|
|
24
38
|
* transient errors with full-jitter backoff; on persistent failure or when S3
|
|
@@ -28,7 +42,7 @@ async function backoffSleep(delayMs, options) {
|
|
|
28
42
|
* `ensureS3LifecycleRule()`, which is opt-in.
|
|
29
43
|
*/
|
|
30
44
|
async function cleanUpS3Orphans(offloader, keys, context, logger, options = {}) {
|
|
31
|
-
const orphans =
|
|
45
|
+
const orphans = selectOrphans(offloader, keys, context, logger, options);
|
|
32
46
|
if (orphans.length === 0)
|
|
33
47
|
return;
|
|
34
48
|
const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
@@ -55,4 +69,3 @@ async function cleanUpS3Orphans(offloader, keys, context, logger, options = {})
|
|
|
55
69
|
message: lastError.message,
|
|
56
70
|
});
|
|
57
71
|
}
|
|
58
|
-
//# sourceMappingURL=orphans.js.map
|
|
@@ -9,6 +9,10 @@ export interface UploadParams {
|
|
|
9
9
|
}
|
|
10
10
|
/** Upload `data` to S3, wrapping failures as `S3_OFFLOAD_FAILED`. */
|
|
11
11
|
export declare function uploadObject(client: S3Client, params: UploadParams): Promise<void>;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Download an object's bytes, wrapping failures/empty bodies as
|
|
14
|
+
* `S3_OFFLOAD_FAILED`. An object over `maxBytes` is refused from its declared
|
|
15
|
+
* `ContentLength` before the body is touched, or while streaming when the
|
|
16
|
+
* length is unknown, so a replaced or hostile object can never exhaust memory.
|
|
17
|
+
*/
|
|
18
|
+
export declare function downloadObject(client: S3Client, bucket: string, key: string, maxBytes: number): Promise<Uint8Array>;
|