@backblaze-labs/b2-sdk 0.2.0 → 0.3.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/CHANGELOG.md +42 -1
- package/README.md +20 -2
- package/dist/_virtual/_b2-sdk-version-json.cjs +1 -1
- package/dist/_virtual/_b2-sdk-version-json.js +1 -1
- package/dist/auth/file.cjs.map +1 -1
- package/dist/backup/client.cjs +206 -0
- package/dist/backup/client.cjs.map +1 -0
- package/dist/backup/client.d.cts +238 -0
- package/dist/backup/client.d.cts.map +1 -0
- package/dist/backup/client.d.ts +238 -0
- package/dist/backup/client.d.ts.map +1 -0
- package/dist/backup/client.js +206 -0
- package/dist/backup/client.js.map +1 -0
- package/dist/backup/index.cjs +15 -0
- package/dist/backup/index.d.cts +22 -0
- package/dist/backup/index.d.cts.map +1 -0
- package/dist/backup/index.d.ts +22 -0
- package/dist/backup/index.d.ts.map +1 -0
- package/dist/backup/index.js +7 -0
- package/dist/backup/raw.cjs +146 -0
- package/dist/backup/raw.cjs.map +1 -0
- package/dist/backup/raw.d.cts +122 -0
- package/dist/backup/raw.d.cts.map +1 -0
- package/dist/backup/raw.d.ts +122 -0
- package/dist/backup/raw.d.ts.map +1 -0
- package/dist/backup/raw.js +146 -0
- package/dist/backup/raw.js.map +1 -0
- package/dist/bucket.cjs +2 -1
- package/dist/bucket.cjs.map +1 -1
- package/dist/bucket.js +2 -1
- package/dist/bucket.js.map +1 -1
- package/dist/copy/large.cjs +5 -3
- package/dist/copy/large.cjs.map +1 -1
- package/dist/copy/large.d.cts.map +1 -1
- package/dist/copy/large.d.ts.map +1 -1
- package/dist/copy/large.js +5 -3
- package/dist/copy/large.js.map +1 -1
- package/dist/download/checksum.cjs +6 -2
- package/dist/download/checksum.cjs.map +1 -1
- package/dist/download/checksum.js +6 -2
- package/dist/download/checksum.js.map +1 -1
- package/dist/download/parallel.cjs +52 -15
- package/dist/download/parallel.cjs.map +1 -1
- package/dist/download/parallel.d.cts +8 -1
- package/dist/download/parallel.d.cts.map +1 -1
- package/dist/download/parallel.d.ts +8 -1
- package/dist/download/parallel.d.ts.map +1 -1
- package/dist/download/parallel.js +52 -15
- package/dist/download/parallel.js.map +1 -1
- package/dist/download/single.cjs +141 -6
- package/dist/download/single.cjs.map +1 -1
- package/dist/download/single.d.cts.map +1 -1
- package/dist/download/single.d.ts.map +1 -1
- package/dist/download/single.js +141 -6
- package/dist/download/single.js.map +1 -1
- package/dist/errors/index.cjs +173 -3
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +119 -0
- package/dist/errors/index.d.cts.map +1 -1
- package/dist/errors/index.d.ts +119 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +161 -4
- package/dist/errors/index.js.map +1 -1
- package/dist/http/retry.cjs +1 -1
- package/dist/http/retry.cjs.map +1 -1
- package/dist/http/retry.js +1 -1
- package/dist/http/retry.js.map +1 -1
- package/dist/http/transport.cjs +61 -23
- package/dist/http/transport.cjs.map +1 -1
- package/dist/http/transport.d.cts +25 -3
- package/dist/http/transport.d.cts.map +1 -1
- package/dist/http/transport.d.ts +25 -3
- package/dist/http/transport.d.ts.map +1 -1
- package/dist/http/transport.js +59 -22
- package/dist/http/transport.js.map +1 -1
- package/dist/index.cjs +25 -2
- package/dist/index.d.cts +6 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/object.cjs +1 -1
- package/dist/object.cjs.map +1 -1
- package/dist/object.d.cts +4 -2
- package/dist/object.d.cts.map +1 -1
- package/dist/object.d.ts +4 -2
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +1 -1
- package/dist/object.js.map +1 -1
- package/dist/partner/account-info.d.cts +43 -0
- package/dist/partner/account-info.d.cts.map +1 -0
- package/dist/partner/account-info.d.ts +43 -0
- package/dist/partner/account-info.d.ts.map +1 -0
- package/dist/partner/auth-clone.cjs +64 -0
- package/dist/partner/auth-clone.cjs.map +1 -0
- package/dist/partner/auth-clone.d.cts +27 -0
- package/dist/partner/auth-clone.d.cts.map +1 -0
- package/dist/partner/auth-clone.d.ts +27 -0
- package/dist/partner/auth-clone.d.ts.map +1 -0
- package/dist/partner/auth-clone.js +63 -0
- package/dist/partner/auth-clone.js.map +1 -0
- package/dist/partner/auth-core.cjs +175 -0
- package/dist/partner/auth-core.cjs.map +1 -0
- package/dist/partner/auth-core.d.cts +111 -0
- package/dist/partner/auth-core.d.cts.map +1 -0
- package/dist/partner/auth-core.d.ts +111 -0
- package/dist/partner/auth-core.d.ts.map +1 -0
- package/dist/partner/auth-core.js +175 -0
- package/dist/partner/auth-core.js.map +1 -0
- package/dist/partner/auth-shape.cjs +36 -0
- package/dist/partner/auth-shape.cjs.map +1 -0
- package/dist/partner/auth-shape.d.cts +12 -0
- package/dist/partner/auth-shape.d.cts.map +1 -0
- package/dist/partner/auth-shape.d.ts +12 -0
- package/dist/partner/auth-shape.d.ts.map +1 -0
- package/dist/partner/auth-shape.js +36 -0
- package/dist/partner/auth-shape.js.map +1 -0
- package/dist/partner/client.cjs +255 -0
- package/dist/partner/client.cjs.map +1 -0
- package/dist/partner/client.d.cts +335 -0
- package/dist/partner/client.d.cts.map +1 -0
- package/dist/partner/client.d.ts +335 -0
- package/dist/partner/client.d.ts.map +1 -0
- package/dist/partner/client.js +255 -0
- package/dist/partner/client.js.map +1 -0
- package/dist/partner/endpoint-url.cjs +108 -0
- package/dist/partner/endpoint-url.cjs.map +1 -0
- package/dist/partner/endpoint-url.d.cts +72 -0
- package/dist/partner/endpoint-url.d.cts.map +1 -0
- package/dist/partner/endpoint-url.d.ts +72 -0
- package/dist/partner/endpoint-url.d.ts.map +1 -0
- package/dist/partner/endpoint-url.js +105 -0
- package/dist/partner/endpoint-url.js.map +1 -0
- package/dist/partner/in-memory.cjs +135 -0
- package/dist/partner/in-memory.cjs.map +1 -0
- package/dist/partner/in-memory.d.cts +99 -0
- package/dist/partner/in-memory.d.cts.map +1 -0
- package/dist/partner/in-memory.d.ts +99 -0
- package/dist/partner/in-memory.d.ts.map +1 -0
- package/dist/partner/in-memory.js +135 -0
- package/dist/partner/in-memory.js.map +1 -0
- package/dist/partner/index.cjs +18 -0
- package/dist/partner/index.d.cts +23 -0
- package/dist/partner/index.d.cts.map +1 -0
- package/dist/partner/index.d.ts +23 -0
- package/dist/partner/index.d.ts.map +1 -0
- package/dist/partner/index.js +7 -0
- package/dist/partner/raw.cjs +392 -0
- package/dist/partner/raw.cjs.map +1 -0
- package/dist/partner/raw.d.cts +223 -0
- package/dist/partner/raw.d.cts.map +1 -0
- package/dist/partner/raw.d.ts +223 -0
- package/dist/partner/raw.d.ts.map +1 -0
- package/dist/partner/raw.js +390 -0
- package/dist/partner/raw.js.map +1 -0
- package/dist/partner/redaction-placeholders.cjs +10 -0
- package/dist/partner/redaction-placeholders.cjs.map +1 -0
- package/dist/partner/redaction-placeholders.d.cts +5 -0
- package/dist/partner/redaction-placeholders.d.cts.map +1 -0
- package/dist/partner/redaction-placeholders.d.ts +5 -0
- package/dist/partner/redaction-placeholders.d.ts.map +1 -0
- package/dist/partner/redaction-placeholders.js +9 -0
- package/dist/partner/redaction-placeholders.js.map +1 -0
- package/dist/partner/redaction.cjs +267 -0
- package/dist/partner/redaction.cjs.map +1 -0
- package/dist/partner/redaction.d.cts +124 -0
- package/dist/partner/redaction.d.cts.map +1 -0
- package/dist/partner/redaction.d.ts +124 -0
- package/dist/partner/redaction.d.ts.map +1 -0
- package/dist/partner/redaction.js +257 -0
- package/dist/partner/redaction.js.map +1 -0
- package/dist/raw/index.cjs +81 -19
- package/dist/raw/index.cjs.map +1 -1
- package/dist/raw/index.d.cts +6 -2
- package/dist/raw/index.d.cts.map +1 -1
- package/dist/raw/index.d.ts +6 -2
- package/dist/raw/index.d.ts.map +1 -1
- package/dist/raw/index.js +81 -19
- package/dist/raw/index.js.map +1 -1
- package/dist/raw/url.cjs +111 -0
- package/dist/raw/url.cjs.map +1 -0
- package/dist/raw/url.d.cts +41 -0
- package/dist/raw/url.d.cts.map +1 -0
- package/dist/raw/url.d.ts +41 -0
- package/dist/raw/url.d.ts.map +1 -0
- package/dist/raw/url.js +110 -0
- package/dist/raw/url.js.map +1 -0
- package/dist/s3/sigv4.cjs +15 -10
- package/dist/s3/sigv4.cjs.map +1 -1
- package/dist/s3/sigv4.js +15 -10
- package/dist/s3/sigv4.js.map +1 -1
- package/dist/simulator/index.cjs +1197 -206
- package/dist/simulator/index.cjs.map +1 -1
- package/dist/simulator/index.d.cts +109 -11
- package/dist/simulator/index.d.cts.map +1 -1
- package/dist/simulator/index.d.ts +109 -11
- package/dist/simulator/index.d.ts.map +1 -1
- package/dist/simulator/index.js +1196 -209
- package/dist/simulator/index.js.map +1 -1
- package/dist/simulator/partner.cjs +719 -0
- package/dist/simulator/partner.cjs.map +1 -0
- package/dist/simulator/partner.d.cts +183 -0
- package/dist/simulator/partner.d.cts.map +1 -0
- package/dist/simulator/partner.d.ts +183 -0
- package/dist/simulator/partner.d.ts.map +1 -0
- package/dist/simulator/partner.js +718 -0
- package/dist/simulator/partner.js.map +1 -0
- package/dist/simulator/validation.cjs +577 -0
- package/dist/simulator/validation.cjs.map +1 -1
- package/dist/simulator/validation.d.cts +117 -0
- package/dist/simulator/validation.d.cts.map +1 -1
- package/dist/simulator/validation.d.ts +117 -0
- package/dist/simulator/validation.d.ts.map +1 -1
- package/dist/simulator/validation.js +563 -1
- package/dist/simulator/validation.js.map +1 -1
- package/dist/streams/file-source.cjs +1 -1
- package/dist/streams/file-source.cjs.map +1 -1
- package/dist/streams/file-source.js +1 -1
- package/dist/streams/file-source.js.map +1 -1
- package/dist/streams/index.cjs +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/streams/source.cjs +2 -1
- package/dist/streams/source.cjs.map +1 -1
- package/dist/streams/source.js +2 -1
- package/dist/streams/source.js.map +1 -1
- package/dist/sync/b2-sha1-reader.cjs +6 -2
- package/dist/sync/b2-sha1-reader.cjs.map +1 -1
- package/dist/sync/b2-sha1-reader.d.cts.map +1 -1
- package/dist/sync/b2-sha1-reader.d.ts.map +1 -1
- package/dist/sync/b2-sha1-reader.js +6 -2
- package/dist/sync/b2-sha1-reader.js.map +1 -1
- package/dist/sync/download-staging.cjs +11 -10
- package/dist/sync/download-staging.cjs.map +1 -1
- package/dist/sync/download-staging.d.cts +2 -1
- package/dist/sync/download-staging.d.cts.map +1 -1
- package/dist/sync/download-staging.d.ts +2 -1
- package/dist/sync/download-staging.d.ts.map +1 -1
- package/dist/sync/download-staging.js +11 -10
- package/dist/sync/download-staging.js.map +1 -1
- package/dist/sync/filters.cjs.map +1 -1
- package/dist/sync/filters.js.map +1 -1
- package/dist/sync/local-file-io.cjs +11 -6
- package/dist/sync/local-file-io.cjs.map +1 -1
- package/dist/sync/local-file-io.d.cts +1 -0
- package/dist/sync/local-file-io.d.cts.map +1 -1
- package/dist/sync/local-file-io.d.ts +1 -0
- package/dist/sync/local-file-io.d.ts.map +1 -1
- package/dist/sync/local-file-io.js +11 -6
- package/dist/sync/local-file-io.js.map +1 -1
- package/dist/sync/local-sha1.cjs +6 -15
- package/dist/sync/local-sha1.cjs.map +1 -1
- package/dist/sync/local-sha1.d.cts +0 -8
- package/dist/sync/local-sha1.d.cts.map +1 -1
- package/dist/sync/local-sha1.d.ts +0 -8
- package/dist/sync/local-sha1.d.ts.map +1 -1
- package/dist/sync/local-sha1.js +7 -15
- package/dist/sync/local-sha1.js.map +1 -1
- package/dist/sync/policies/compare.cjs +5 -3
- package/dist/sync/policies/compare.cjs.map +1 -1
- package/dist/sync/policies/compare.d.cts.map +1 -1
- package/dist/sync/policies/compare.d.ts.map +1 -1
- package/dist/sync/policies/compare.js +6 -4
- package/dist/sync/policies/compare.js.map +1 -1
- package/dist/sync/policies/index.cjs +4 -10
- package/dist/sync/policies/index.cjs.map +1 -1
- package/dist/sync/policies/index.js +4 -10
- package/dist/sync/policies/index.js.map +1 -1
- package/dist/sync/scanners/b2.cjs +2 -2
- package/dist/sync/scanners/b2.cjs.map +1 -1
- package/dist/sync/scanners/b2.js +2 -2
- package/dist/sync/scanners/b2.js.map +1 -1
- package/dist/sync/scanners/local.cjs.map +1 -1
- package/dist/sync/scanners/local.js.map +1 -1
- package/dist/sync/synchronizer.cjs +3 -2
- package/dist/sync/synchronizer.cjs.map +1 -1
- package/dist/sync/synchronizer.js +3 -2
- package/dist/sync/synchronizer.js.map +1 -1
- package/dist/types/auth.cjs +4 -0
- package/dist/types/auth.cjs.map +1 -1
- package/dist/types/auth.d.cts +4 -0
- package/dist/types/auth.d.cts.map +1 -1
- package/dist/types/auth.d.ts +4 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +4 -0
- package/dist/types/auth.js.map +1 -1
- package/dist/types/backup.d.cts +80 -0
- package/dist/types/backup.d.cts.map +1 -0
- package/dist/types/backup.d.ts +80 -0
- package/dist/types/backup.d.ts.map +1 -0
- package/dist/types/bucket.cjs.map +1 -1
- package/dist/types/bucket.d.cts +4 -2
- package/dist/types/bucket.d.cts.map +1 -1
- package/dist/types/bucket.d.ts +4 -2
- package/dist/types/bucket.d.ts.map +1 -1
- package/dist/types/bucket.js.map +1 -1
- package/dist/types/download.cjs +62 -0
- package/dist/types/download.cjs.map +1 -0
- package/dist/types/download.d.cts +98 -0
- package/dist/types/download.d.cts.map +1 -1
- package/dist/types/download.d.ts +98 -0
- package/dist/types/download.d.ts.map +1 -1
- package/dist/types/download.js +61 -0
- package/dist/types/download.js.map +1 -0
- package/dist/types/encryption.cjs +58 -229
- package/dist/types/encryption.cjs.map +1 -1
- package/dist/types/encryption.d.cts +32 -0
- package/dist/types/encryption.d.cts.map +1 -1
- package/dist/types/encryption.d.ts +32 -0
- package/dist/types/encryption.d.ts.map +1 -1
- package/dist/types/encryption.js +56 -229
- package/dist/types/encryption.js.map +1 -1
- package/dist/types/errors.cjs +9 -0
- package/dist/types/errors.cjs.map +1 -1
- package/dist/types/errors.d.cts +1 -1
- package/dist/types/errors.d.cts.map +1 -1
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +9 -0
- package/dist/types/errors.js.map +1 -1
- package/dist/types/file.cjs.map +1 -1
- package/dist/types/file.d.cts +15 -2
- package/dist/types/file.d.cts.map +1 -1
- package/dist/types/file.d.ts +15 -2
- package/dist/types/file.d.ts.map +1 -1
- package/dist/types/file.js.map +1 -1
- package/dist/types/ids.cjs +30 -0
- package/dist/types/ids.cjs.map +1 -1
- package/dist/types/ids.d.cts +32 -0
- package/dist/types/ids.d.cts.map +1 -1
- package/dist/types/ids.d.ts +32 -0
- package/dist/types/ids.d.ts.map +1 -1
- package/dist/types/ids.js +28 -1
- package/dist/types/ids.js.map +1 -1
- package/dist/types/index.d.cts +10 -6
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +10 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lock.cjs.map +1 -1
- package/dist/types/lock.d.cts +14 -0
- package/dist/types/lock.d.cts.map +1 -1
- package/dist/types/lock.d.ts +14 -0
- package/dist/types/lock.d.ts.map +1 -1
- package/dist/types/lock.js.map +1 -1
- package/dist/types/notifications.cjs +1 -1
- package/dist/types/notifications.cjs.map +1 -1
- package/dist/types/notifications.d.cts +5 -3
- package/dist/types/notifications.d.cts.map +1 -1
- package/dist/types/notifications.d.ts +5 -3
- package/dist/types/notifications.d.ts.map +1 -1
- package/dist/types/notifications.js +1 -1
- package/dist/types/notifications.js.map +1 -1
- package/dist/types/partner.cjs +32 -0
- package/dist/types/partner.cjs.map +1 -0
- package/dist/types/partner.d.cts +394 -0
- package/dist/types/partner.d.cts.map +1 -0
- package/dist/types/partner.d.ts +394 -0
- package/dist/types/partner.d.ts.map +1 -0
- package/dist/types/partner.js +29 -0
- package/dist/types/partner.js.map +1 -0
- package/dist/types/upload.d.cts +31 -18
- package/dist/types/upload.d.cts.map +1 -1
- package/dist/types/upload.d.ts +31 -18
- package/dist/types/upload.d.ts.map +1 -1
- package/dist/upload/abort-scope.cjs +0 -45
- package/dist/upload/abort-scope.cjs.map +1 -1
- package/dist/upload/abort-scope.d.cts +0 -22
- package/dist/upload/abort-scope.d.cts.map +1 -1
- package/dist/upload/abort-scope.d.ts +0 -22
- package/dist/upload/abort-scope.d.ts.map +1 -1
- package/dist/upload/abort-scope.js +1 -44
- package/dist/upload/abort-scope.js.map +1 -1
- package/dist/upload/finish.cjs +3 -8
- package/dist/upload/finish.cjs.map +1 -1
- package/dist/upload/finish.d.cts.map +1 -1
- package/dist/upload/finish.d.ts.map +1 -1
- package/dist/upload/finish.js +1 -6
- package/dist/upload/finish.js.map +1 -1
- package/dist/upload/large.cjs +5 -1
- package/dist/upload/large.cjs.map +1 -1
- package/dist/upload/large.d.cts +16 -2
- package/dist/upload/large.d.cts.map +1 -1
- package/dist/upload/large.d.ts +16 -2
- package/dist/upload/large.d.ts.map +1 -1
- package/dist/upload/large.js +5 -1
- package/dist/upload/large.js.map +1 -1
- package/dist/upload/options.cjs.map +1 -1
- package/dist/upload/options.d.cts +12 -0
- package/dist/upload/options.d.cts.map +1 -1
- package/dist/upload/options.d.ts +12 -0
- package/dist/upload/options.d.ts.map +1 -1
- package/dist/upload/options.js.map +1 -1
- package/dist/upload/resume.cjs +2 -1
- package/dist/upload/resume.cjs.map +1 -1
- package/dist/upload/resume.d.cts +3 -1
- package/dist/upload/resume.d.cts.map +1 -1
- package/dist/upload/resume.d.ts +3 -1
- package/dist/upload/resume.d.ts.map +1 -1
- package/dist/upload/resume.js +2 -1
- package/dist/upload/resume.js.map +1 -1
- package/dist/upload/retry.cjs +8 -3
- package/dist/upload/retry.cjs.map +1 -1
- package/dist/upload/retry.js +8 -3
- package/dist/upload/retry.js.map +1 -1
- package/dist/upload/single.cjs +2 -1
- package/dist/upload/single.cjs.map +1 -1
- package/dist/upload/single.d.cts +6 -0
- package/dist/upload/single.d.cts.map +1 -1
- package/dist/upload/single.d.ts +6 -0
- package/dist/upload/single.d.ts.map +1 -1
- package/dist/upload/single.js +2 -1
- package/dist/upload/single.js.map +1 -1
- package/dist/upload/stream.cjs +6 -4
- package/dist/upload/stream.cjs.map +1 -1
- package/dist/upload/stream.d.cts +6 -0
- package/dist/upload/stream.d.cts.map +1 -1
- package/dist/upload/stream.d.ts +6 -0
- package/dist/upload/stream.d.ts.map +1 -1
- package/dist/upload/stream.js +3 -1
- package/dist/upload/stream.js.map +1 -1
- package/dist/util/abort.cjs +114 -0
- package/dist/util/abort.cjs.map +1 -0
- package/dist/util/abort.d.cts +65 -0
- package/dist/util/abort.d.cts.map +1 -0
- package/dist/util/abort.d.ts +65 -0
- package/dist/util/abort.d.ts.map +1 -0
- package/dist/util/abort.js +109 -0
- package/dist/util/abort.js.map +1 -0
- package/dist/util/defaults.cjs +3 -0
- package/dist/util/defaults.cjs.map +1 -1
- package/dist/util/defaults.d.cts +2 -0
- package/dist/util/defaults.d.cts.map +1 -1
- package/dist/util/defaults.d.ts +2 -0
- package/dist/util/defaults.d.ts.map +1 -1
- package/dist/util/defaults.js +3 -1
- package/dist/util/defaults.js.map +1 -1
- package/dist/util/md5.cjs +211 -0
- package/dist/util/md5.cjs.map +1 -0
- package/dist/util/md5.d.cts +43 -0
- package/dist/util/md5.d.cts.map +1 -0
- package/dist/util/md5.d.ts +43 -0
- package/dist/util/md5.d.ts.map +1 -0
- package/dist/util/md5.js +209 -0
- package/dist/util/md5.js.map +1 -0
- package/dist/util/normalize.cjs +5 -5
- package/dist/util/normalize.cjs.map +1 -1
- package/dist/util/normalize.d.cts +7 -7
- package/dist/util/normalize.d.cts.map +1 -1
- package/dist/util/normalize.d.ts +7 -7
- package/dist/util/normalize.d.ts.map +1 -1
- package/dist/util/normalize.js +5 -5
- package/dist/util/normalize.js.map +1 -1
- package/dist/util/paginator.cjs +7 -1
- package/dist/util/paginator.cjs.map +1 -1
- package/dist/util/paginator.d.cts +3 -1
- package/dist/util/paginator.d.cts.map +1 -1
- package/dist/util/paginator.d.ts +3 -1
- package/dist/util/paginator.d.ts.map +1 -1
- package/dist/util/paginator.js +7 -1
- package/dist/util/paginator.js.map +1 -1
- package/package.json +38 -16
package/dist/http/retry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.js","names":[],"sources":["../../src/http/retry.ts"],"sourcesContent":["/** Configuration for retry behavior on transient failures. */\nexport interface RetryOptions {\n /** Maximum number of retry attempts before giving up. */\n readonly maxRetries: number\n /** Upper bound on retry delay in milliseconds, regardless of backoff calculation. */\n readonly maxRetryDelayMs: number\n /** Base delay in milliseconds for the first retry. Doubles on each subsequent attempt. */\n readonly initialRetryDelayMs: number\n /**\n * Optional timeout for each HTTP request attempt. Defaults to 15 minutes\n * when omitted. The timer covers request dispatch, upload bodies, and\n * non-streaming response body reads. For `response.body` streams it is an\n * idle timeout that resets after each received chunk. Set to 0 to disable\n * the SDK timeout and rely only on the caller's AbortSignal.\n */\n readonly requestTimeoutMs?: number\n}\n\n/** Default retry settings: 5 retries, 1s initial delay, 64s max delay, 15 minute timeout. */\nexport const DEFAULT_RETRY_OPTIONS = {\n maxRetries: 5,\n maxRetryDelayMs: 64_000,\n initialRetryDelayMs: 1_000,\n requestTimeoutMs: 15 * 60_000,\n} satisfies Required<RetryOptions>\n\n/**\n * Computes the delay before the next retry using exponential backoff with jitter.\n * If a `Retry-After` value is provided by the server, it takes precedence over\n * the calculated backoff (still capped at {@link RetryOptions.maxRetryDelayMs}).\n *\n * @param attempt - Zero-based retry attempt index.\n * @param options - Retry configuration with delay bounds.\n * @param retryAfter - Server-provided retry delay in seconds, if any.\n *\n * @returns The delay in milliseconds before the next retry attempt.\n */\nexport function computeBackoff(\n attempt: number,\n options: RetryOptions,\n retryAfter?: number,\n): number {\n if (retryAfter !== undefined && retryAfter > 0) {\n return Math.min(retryAfter * 1000, options.maxRetryDelayMs)\n }\n const base = options.initialRetryDelayMs * 2 ** attempt\n const jitter = Math.random() * base * 0.5\n return Math.min(base + jitter, options.maxRetryDelayMs)\n}\n\n/**\n * Returns a promise that resolves after the given delay. Supports cancellation\n * via an optional AbortSignal.\n *\n * @param ms - Delay in milliseconds.\n * @param signal - Optional abort signal to cancel the sleep early.\n *\n * @returns A promise that resolves when the delay elapses or rejects if aborted.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))\n return\n }\n const timer = setTimeout(resolve, ms)\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))\n },\n { once: true },\n )\n })\n}\n"],"mappings":";;AAmBA,IAAa,wBAAwB;CACnC,YAAY;CACZ,iBAAiB;CACjB,qBAAqB;CACrB,kBAAkB
|
|
1
|
+
{"version":3,"file":"retry.js","names":[],"sources":["../../src/http/retry.ts"],"sourcesContent":["/** Configuration for retry behavior on transient failures. */\nexport interface RetryOptions {\n /** Maximum number of retry attempts before giving up. */\n readonly maxRetries: number\n /** Upper bound on retry delay in milliseconds, regardless of backoff calculation. */\n readonly maxRetryDelayMs: number\n /** Base delay in milliseconds for the first retry. Doubles on each subsequent attempt. */\n readonly initialRetryDelayMs: number\n /**\n * Optional timeout for each HTTP request attempt. Defaults to 15 minutes\n * when omitted. The timer covers request dispatch, upload bodies, and\n * non-streaming response body reads. For `response.body` streams it is an\n * idle timeout that resets after each received chunk. Set to 0 to disable\n * the SDK timeout and rely only on the caller's AbortSignal.\n */\n readonly requestTimeoutMs?: number\n}\n\n/** Default retry settings: 5 retries, 1s initial delay, 64s max delay, 15 minute timeout. */\nexport const DEFAULT_RETRY_OPTIONS = {\n maxRetries: 5,\n maxRetryDelayMs: 64_000,\n initialRetryDelayMs: 1_000,\n requestTimeoutMs: 15 * 60_000,\n} satisfies Required<RetryOptions>\n\n/**\n * Computes the delay before the next retry using exponential backoff with jitter.\n * If a `Retry-After` value is provided by the server, it takes precedence over\n * the calculated backoff (still capped at {@link RetryOptions.maxRetryDelayMs}).\n *\n * @param attempt - Zero-based retry attempt index.\n * @param options - Retry configuration with delay bounds.\n * @param retryAfter - Server-provided retry delay in seconds, if any.\n *\n * @returns The delay in milliseconds before the next retry attempt.\n */\nexport function computeBackoff(\n attempt: number,\n options: RetryOptions,\n retryAfter?: number,\n): number {\n if (retryAfter !== undefined && retryAfter > 0) {\n return Math.min(retryAfter * 1000, options.maxRetryDelayMs)\n }\n const base = options.initialRetryDelayMs * 2 ** attempt\n const jitter = Math.random() * base * 0.5\n return Math.min(base + jitter, options.maxRetryDelayMs)\n}\n\n/**\n * Returns a promise that resolves after the given delay. Supports cancellation\n * via an optional AbortSignal.\n *\n * @param ms - Delay in milliseconds.\n * @param signal - Optional abort signal to cancel the sleep early.\n *\n * @returns A promise that resolves when the delay elapses or rejects if aborted.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))\n return\n }\n const timer = setTimeout(resolve, ms)\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))\n },\n { once: true },\n )\n })\n}\n"],"mappings":";;AAmBA,IAAa,wBAAwB;CACnC,YAAY;CACZ,iBAAiB;CACjB,qBAAqB;CACrB,kBAAkB;AACpB;;;;;;;;;;;;AAaA,SAAgB,eACd,SACA,SACA,YACQ;CACR,IAAI,eAAe,KAAA,KAAa,aAAa,GAC3C,OAAO,KAAK,IAAI,aAAa,KAAM,QAAQ,eAAe;CAE5D,MAAM,OAAO,QAAQ,sBAAsB,KAAK;CAChD,MAAM,SAAS,KAAK,OAAO,IAAI,OAAO;CACtC,OAAO,KAAK,IAAI,OAAO,QAAQ,QAAQ,eAAe;AACxD;;;;;;;;;;AAWA,SAAgB,MAAM,IAAY,QAAqC;CACrE,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAI,QAAQ,SAAS;GACnB,OAAO,OAAO,UAAU,IAAI,aAAa,WAAW,YAAY,CAAC;GACjE;EACF;EACA,MAAM,QAAQ,WAAW,SAAS,EAAE;EACpC,QAAQ,iBACN,eACM;GACJ,aAAa,KAAK;GAClB,OAAO,OAAO,UAAU,IAAI,aAAa,WAAW,YAAY,CAAC;EACnE,GACA,EAAE,MAAM,KAAK,CACf;CACF,CAAC;AACH"}
|
package/dist/http/transport.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_errors_index = require("../errors/index.cjs");
|
|
2
|
+
const require_abort = require("../util/abort.cjs");
|
|
2
3
|
const require_retry = require("./retry.cjs");
|
|
3
4
|
const require_url_guard = require("./url-guard.cjs");
|
|
4
5
|
const require_user_agent = require("./user-agent.cjs");
|
|
@@ -12,6 +13,18 @@ var REDIRECT_STATUSES = /* @__PURE__ */ new Set([
|
|
|
12
13
|
]);
|
|
13
14
|
var MAX_SAME_ORIGIN_REDIRECTS = 5;
|
|
14
15
|
/**
|
|
16
|
+
* Returns the URL guard exposed by `transport`, if it implements
|
|
17
|
+
* {@link UrlGuardedTransport}.
|
|
18
|
+
*
|
|
19
|
+
* @param transport - Transport to inspect.
|
|
20
|
+
*
|
|
21
|
+
* @returns The exposed URL guard, or undefined for unguarded transports.
|
|
22
|
+
*/
|
|
23
|
+
function getTransportUrlGuard(transport) {
|
|
24
|
+
const candidate = transport;
|
|
25
|
+
return candidate.urlGuard instanceof require_url_guard.UrlGuard ? candidate.urlGuard : void 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
15
28
|
* Default transport implementation using the global `fetch` API.
|
|
16
29
|
* Automatically sets the User-Agent header on each request and applies the
|
|
17
30
|
* SSRF {@link UrlGuard} (if configured) before opening the connection.
|
|
@@ -218,17 +231,16 @@ function createTimedResponseBody(body, timeoutScope) {
|
|
|
218
231
|
async function raceBodyReadWithAbort(timeoutScope, read, abortCleanup) {
|
|
219
232
|
const signal = timeoutScope.signal;
|
|
220
233
|
if (signal === void 0) return read;
|
|
221
|
-
const abortReason = () => signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
222
234
|
if (signal.aborted) {
|
|
223
235
|
read.catch(() => {});
|
|
224
|
-
const reason = abortReason();
|
|
236
|
+
const reason = require_abort.abortReason(signal);
|
|
225
237
|
await runAbortCleanup(abortCleanup, reason);
|
|
226
238
|
throw reason;
|
|
227
239
|
}
|
|
228
240
|
let removeAbortListener;
|
|
229
241
|
const abort = new Promise((_, reject) => {
|
|
230
242
|
const onAbort = () => {
|
|
231
|
-
const reason = abortReason();
|
|
243
|
+
const reason = require_abort.abortReason(signal);
|
|
232
244
|
read.catch(() => {});
|
|
233
245
|
reject(reason);
|
|
234
246
|
runAbortCleanup(abortCleanup, reason);
|
|
@@ -277,16 +289,38 @@ function isUploadEndpoint(url) {
|
|
|
277
289
|
function isFinishLargeFileEndpoint(url) {
|
|
278
290
|
return b2ApiEndpointName(url) === "b2_finish_large_file";
|
|
279
291
|
}
|
|
292
|
+
function isAuthorizeEndpoint(url) {
|
|
293
|
+
return b2ApiEndpointName(url) === "b2_authorize_account";
|
|
294
|
+
}
|
|
280
295
|
function isStartLargeFileEndpoint(url) {
|
|
281
296
|
return b2ApiEndpointName(url) === "b2_start_large_file";
|
|
282
297
|
}
|
|
298
|
+
function isPartnerMutationEndpoint(url) {
|
|
299
|
+
const endpoint = b2ApiEndpointName(url);
|
|
300
|
+
return endpoint === "b2_create_group_member" || endpoint === "b2_eject_group_member" || endpoint === "b2_reserve_trial_create_account";
|
|
301
|
+
}
|
|
302
|
+
function isBackupMutationEndpoint(url) {
|
|
303
|
+
return backupApiEndpointName(url) === "bz_delete_computer";
|
|
304
|
+
}
|
|
305
|
+
function isNonIdempotentMutationRequest(request) {
|
|
306
|
+
return request.method === "POST" && (isPartnerMutationEndpoint(request.url) || isBackupMutationEndpoint(request.url));
|
|
307
|
+
}
|
|
283
308
|
function b2ApiEndpointName(url) {
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
return
|
|
309
|
+
const segments = new URL(url).pathname.split("/").filter((segment) => segment.length > 0);
|
|
310
|
+
const apiRootIndex = segments.lastIndexOf("b2api");
|
|
311
|
+
if (apiRootIndex === -1) return void 0;
|
|
312
|
+
return segments[apiRootIndex + 2];
|
|
287
313
|
}
|
|
288
|
-
function
|
|
289
|
-
|
|
314
|
+
function backupApiEndpointName(url) {
|
|
315
|
+
const segments = new URL(url).pathname.split("/").filter((segment) => segment.length > 0);
|
|
316
|
+
const apiRootIndex = segments.lastIndexOf("api");
|
|
317
|
+
if (apiRootIndex === -1 || segments[apiRootIndex + 1] !== "backup") return void 0;
|
|
318
|
+
if (!/^v\d+$/.test(segments[apiRootIndex + 2] ?? "")) return void 0;
|
|
319
|
+
return segments[apiRootIndex + 3];
|
|
320
|
+
}
|
|
321
|
+
function isReplayUnsafePostRequest(request) {
|
|
322
|
+
if (request.method !== "POST") return false;
|
|
323
|
+
return isUploadEndpoint(request.url) || isStartLargeFileEndpoint(request.url) || isFinishLargeFileEndpoint(request.url) || isNonIdempotentMutationRequest(request);
|
|
290
324
|
}
|
|
291
325
|
/**
|
|
292
326
|
* Decide whether a classified error should be retried in place for `url`.
|
|
@@ -295,15 +329,17 @@ function isReplayUnsafePostEndpoint(url) {
|
|
|
295
329
|
* upload URL only amplifies the rate limit.
|
|
296
330
|
*
|
|
297
331
|
* @param error - The classified, retryability-tagged error.
|
|
298
|
-
* @param
|
|
332
|
+
* @param request - The request being considered for in-place retry.
|
|
299
333
|
*
|
|
300
334
|
* @returns Whether to retry the request in place.
|
|
301
335
|
*/
|
|
302
|
-
function shouldRetryInPlace(error,
|
|
336
|
+
function shouldRetryInPlace(error, request) {
|
|
303
337
|
if (!error.retryable) return false;
|
|
304
|
-
if (
|
|
305
|
-
if (
|
|
306
|
-
if (
|
|
338
|
+
if (isAuthorizeEndpoint(request.url) && error instanceof require_errors_index.ExpiredAuthTokenError) return false;
|
|
339
|
+
if (isNonIdempotentMutationRequest(request)) return false;
|
|
340
|
+
if (isStartLargeFileEndpoint(request.url) || isFinishLargeFileEndpoint(request.url)) return false;
|
|
341
|
+
if (isUploadEndpoint(request.url) && error.status === 429) return true;
|
|
342
|
+
if (isUploadEndpoint(request.url)) return false;
|
|
307
343
|
return true;
|
|
308
344
|
}
|
|
309
345
|
function isRequestTimeoutError(err) {
|
|
@@ -324,6 +360,8 @@ function isTerminalTransportError(err) {
|
|
|
324
360
|
* retry so account-level throttling does not trigger extra upload URL fetches.
|
|
325
361
|
*/
|
|
326
362
|
var RetryTransport = class {
|
|
363
|
+
/** URL guard from the wrapped transport, when the transport exposes one. */
|
|
364
|
+
urlGuard;
|
|
327
365
|
/** The wrapped transport that performs actual HTTP requests. */
|
|
328
366
|
inner;
|
|
329
367
|
/** Resolved retry options (defaults merged with user overrides). */
|
|
@@ -338,6 +376,7 @@ var RetryTransport = class {
|
|
|
338
376
|
*/
|
|
339
377
|
constructor(opts) {
|
|
340
378
|
this.inner = opts.transport;
|
|
379
|
+
this.urlGuard = getTransportUrlGuard(opts.transport);
|
|
341
380
|
this.options = {
|
|
342
381
|
...require_retry.DEFAULT_RETRY_OPTIONS,
|
|
343
382
|
...opts.retry
|
|
@@ -364,7 +403,7 @@ var RetryTransport = class {
|
|
|
364
403
|
let didReauth = false;
|
|
365
404
|
let attempt = 0;
|
|
366
405
|
while (attempt <= retryOptions.maxRetries) {
|
|
367
|
-
throwIfSignalAborted(request.signal);
|
|
406
|
+
require_abort.throwIfSignalAborted(request.signal);
|
|
368
407
|
if (attempt > 0 && lastError) {
|
|
369
408
|
const retryAfter = lastError instanceof require_errors_index.NetworkError ? void 0 : lastError.retryAfter;
|
|
370
409
|
const delay = require_retry.computeBackoff(attempt - 1, retryOptions, retryAfter);
|
|
@@ -395,8 +434,9 @@ var RetryTransport = class {
|
|
|
395
434
|
...retryAfterSec !== void 0 ? { retryAfter: retryAfterSec } : {},
|
|
396
435
|
...requestId !== void 0 ? { requestId } : {}
|
|
397
436
|
});
|
|
398
|
-
if (error instanceof require_errors_index.ExpiredAuthTokenError && this.onReauth && !isUploadEndpoint(request.url) && !didReauth) {
|
|
399
|
-
const freshToken = await this.onReauth();
|
|
437
|
+
if (error instanceof require_errors_index.ExpiredAuthTokenError && this.onReauth && !isAuthorizeEndpoint(request.url) && !isUploadEndpoint(request.url) && !isNonIdempotentMutationRequest(request) && !didReauth) {
|
|
438
|
+
const freshToken = await require_abort.raceWithAbort(this.onReauth(request.signal), request.signal);
|
|
439
|
+
require_abort.throwIfSignalAborted(request.signal);
|
|
400
440
|
request = {
|
|
401
441
|
...request,
|
|
402
442
|
headers: {
|
|
@@ -408,14 +448,14 @@ var RetryTransport = class {
|
|
|
408
448
|
lastError = void 0;
|
|
409
449
|
continue;
|
|
410
450
|
}
|
|
411
|
-
if (!shouldRetryInPlace(error, request
|
|
451
|
+
if (!shouldRetryInPlace(error, request) || attempt === retryOptions.maxRetries) throw error;
|
|
412
452
|
lastError = error;
|
|
413
453
|
attempt += 1;
|
|
414
454
|
} catch (err) {
|
|
415
|
-
throwIfSignalAborted(request.signal);
|
|
455
|
+
require_abort.throwIfSignalAborted(request.signal);
|
|
416
456
|
if (isTerminalTransportError(err)) throw err;
|
|
417
457
|
const networkErr = new require_errors_index.NetworkError(err instanceof Error ? err.message : "Network error", err);
|
|
418
|
-
if (
|
|
458
|
+
if (isReplayUnsafePostRequest(request) || attempt === retryOptions.maxRetries) throw networkErr;
|
|
419
459
|
lastError = networkErr;
|
|
420
460
|
attempt += 1;
|
|
421
461
|
}
|
|
@@ -423,12 +463,9 @@ var RetryTransport = class {
|
|
|
423
463
|
throw lastError ?? new require_errors_index.NetworkError("Max retries exceeded");
|
|
424
464
|
}
|
|
425
465
|
};
|
|
426
|
-
function throwIfSignalAborted(signal) {
|
|
427
|
-
if (signal?.aborted === true) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
428
|
-
}
|
|
429
466
|
async function throwIfSignalAbortedAfterResponse(signal, response) {
|
|
430
467
|
if (signal?.aborted !== true) return;
|
|
431
|
-
const reason =
|
|
468
|
+
const reason = require_abort.abortReason(signal);
|
|
432
469
|
try {
|
|
433
470
|
await response.body?.cancel(reason);
|
|
434
471
|
} catch {}
|
|
@@ -437,5 +474,6 @@ async function throwIfSignalAbortedAfterResponse(signal, response) {
|
|
|
437
474
|
//#endregion
|
|
438
475
|
exports.FetchTransport = FetchTransport;
|
|
439
476
|
exports.RetryTransport = RetryTransport;
|
|
477
|
+
exports.getTransportUrlGuard = getTransportUrlGuard;
|
|
440
478
|
|
|
441
479
|
//# sourceMappingURL=transport.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.cjs","names":[],"sources":["../../src/http/transport.ts"],"sourcesContent":["import {\n B2Error,\n B2RedirectError,\n B2SsrfError,\n classifyError,\n ExpiredAuthTokenError,\n NetworkError,\n} from '../errors/index.ts'\nimport type { B2ErrorResponse } from '../types/errors.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from './retry.ts'\nimport { UrlGuard } from './url-guard.ts'\nimport { getUserAgent } from './user-agent.ts'\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308])\nconst MAX_SAME_ORIGIN_REDIRECTS = 5\n\n/** Describes an outgoing HTTP request to the B2 API. */\nexport interface HttpRequest {\n /** Fully qualified URL to send the request to. */\n readonly url: string\n /** HTTP method. B2 uses GET for downloads (HEAD to fetch only headers) and POST for all other operations. */\n readonly method: 'GET' | 'HEAD' | 'POST'\n /** Request headers. Authorization and content-type are typically included. */\n readonly headers?: Record<string, string>\n /** Request body. Used for POST requests (JSON payloads or file uploads). */\n readonly body?: BodyInit | null\n /** Optional abort signal for request cancellation. */\n readonly signal?: AbortSignal\n /** Optional per-request retry override. */\n readonly retry?: Partial<RetryOptions>\n}\n\n/** Represents a parsed HTTP response from the B2 API. */\nexport interface HttpResponse {\n /** HTTP status code. */\n readonly status: number\n /** Response headers. */\n readonly headers: Headers\n /** Response body as a readable stream, or null for empty responses. */\n readonly body: ReadableStream<Uint8Array> | null\n /** Parses the response body as JSON. */\n json<T>(): Promise<T>\n /** Reads the response body as a UTF-8 string. */\n text(): Promise<string>\n /** Reads the response body as an ArrayBuffer. */\n arrayBuffer(): Promise<ArrayBuffer>\n}\n\n/**\n * Transport layer abstraction for sending HTTP requests.\n * Implementations handle the actual network I/O and can be composed\n * (e.g. wrapping a {@link FetchTransport} with a {@link RetryTransport}).\n */\nexport interface HttpTransport {\n /** Sends an HTTP request and returns the response. */\n send(request: HttpRequest): Promise<HttpResponse>\n}\n\n/**\n * Default transport implementation using the global `fetch` API.\n * Automatically sets the User-Agent header on each request and applies the\n * SSRF {@link UrlGuard} (if configured) before opening the connection.\n * Redirect following is disabled so redirected URLs cannot bypass the guard or\n * receive credential-bearing headers without an explicit checked request.\n */\nexport class FetchTransport implements HttpTransport {\n /** User-Agent string sent with every request. */\n private readonly userAgent: string\n /** Whether same-origin GET/HEAD redirects should be followed after guard checks. */\n private readonly followSameOriginRedirects: boolean\n /** SSRF allow-list applied to every outgoing URL. Mutable so `B2Client.authorize()` can lock it down post-auth. */\n readonly urlGuard: UrlGuard\n\n /**\n * Creates a new FetchTransport.\n * @param options - Optional configuration: custom User-Agent prefix and SSRF guard.\n */\n constructor(options?: {\n userAgent?: string\n urlGuard?: UrlGuard\n /**\n * Follow same-origin GET/HEAD redirects after checking the target with the\n * URL guard. POST redirects are still blocked to avoid replaying\n * credential-bearing payloads to an unexpected endpoint. Defaults to true.\n */\n followSameOriginRedirects?: boolean\n }) {\n this.userAgent = getUserAgent(options?.userAgent)\n this.followSameOriginRedirects = options?.followSameOriginRedirects ?? true\n this.urlGuard = options?.urlGuard ?? new UrlGuard()\n }\n\n /**\n * Sends the request using the global `fetch` function.\n * @param request - The HTTP request to execute.\n *\n * @returns The HTTP response.\n *\n * @throws B2SsrfError when the URL fails the configured SSRF guard.\n * @throws B2RedirectError when a response attempts to redirect.\n */\n async send(request: HttpRequest): Promise<HttpResponse> {\n let currentRequest = request\n let redirectCount = 0\n\n while (true) {\n this.urlGuard.check(currentRequest.url)\n\n const headers = new Headers(currentRequest.headers)\n if (!headers.has('User-Agent')) {\n headers.set('User-Agent', this.userAgent)\n }\n\n const timeoutScope = createRequestTimeoutScope(currentRequest)\n let response: Response\n try {\n response = await fetch(currentRequest.url, {\n method: currentRequest.method,\n headers,\n body: currentRequest.body ?? null,\n redirect: 'manual',\n ...(timeoutScope.signal !== undefined ? { signal: timeoutScope.signal } : {}),\n })\n } catch (err) {\n timeoutScope.dispose()\n if (timeoutScope.timedOut) {\n throw createRequestTimeoutError(timeoutScope)\n }\n throw err\n }\n\n if (isBlockedRedirect(response)) {\n const location = response.headers.get('Location')\n if (\n this.followSameOriginRedirects &&\n location !== null &&\n redirectCount < MAX_SAME_ORIGIN_REDIRECTS &&\n canFollowSameOriginRedirect(currentRequest, location)\n ) {\n const nextUrl = new URL(location, currentRequest.url).toString()\n await cancelResponseBody(response)\n timeoutScope.dispose()\n this.urlGuard.check(nextUrl)\n currentRequest = { ...currentRequest, url: nextUrl }\n redirectCount += 1\n continue\n }\n\n await cancelResponseBody(response)\n timeoutScope.dispose()\n throw new B2RedirectError(currentRequest.url, response.status, location)\n }\n\n return createTimedHttpResponse(response, timeoutScope)\n }\n }\n}\n\ninterface RequestTimeoutScope {\n readonly signal?: AbortSignal\n readonly timeoutMs: number\n readonly timedOut: boolean\n reset(): void\n dispose(): void\n}\n\nfunction createRequestTimeoutScope(request: HttpRequest): RequestTimeoutScope {\n const timeoutMs = request.retry?.requestTimeoutMs ?? DEFAULT_RETRY_OPTIONS.requestTimeoutMs\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n const scope: RequestTimeoutScope = {\n timeoutMs: 0,\n timedOut: false,\n reset() {},\n dispose() {},\n }\n if (request.signal !== undefined) return { ...scope, signal: request.signal }\n return scope\n }\n\n const controller = new AbortController()\n let timedOut = false\n let timer: ReturnType<typeof setTimeout>\n const abortFromUpstream = (): void => {\n clearTimeout(timer)\n controller.abort(request.signal?.reason ?? new DOMException('Aborted', 'AbortError'))\n }\n const armTimer = (): ReturnType<typeof setTimeout> => {\n const nextTimer = setTimeout(() => {\n timedOut = true\n controller.abort(new DOMException('HTTP request timed out', 'TimeoutError'))\n }, timeoutMs)\n unrefTimer(nextTimer)\n return nextTimer\n }\n timer = armTimer()\n\n const reset = (): void => {\n if (timedOut || controller.signal.aborted) return\n clearTimeout(timer)\n timer = armTimer()\n }\n\n if (request.signal?.aborted === true) {\n clearTimeout(timer)\n abortFromUpstream()\n } else {\n request.signal?.addEventListener('abort', abortFromUpstream, { once: true })\n }\n\n return {\n signal: controller.signal,\n timeoutMs,\n get timedOut() {\n return timedOut\n },\n reset,\n dispose() {\n clearTimeout(timer)\n request.signal?.removeEventListener('abort', abortFromUpstream)\n },\n }\n}\n\nfunction unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n const maybeUnref = (timer as { unref?: () => void }).unref\n if (typeof maybeUnref === 'function') maybeUnref.call(timer)\n}\n\nfunction createRequestTimeoutError(scope: RequestTimeoutScope): DOMException {\n return new DOMException(`HTTP request timed out after ${scope.timeoutMs} ms`, 'TimeoutError')\n}\n\nfunction createTimedHttpResponse(\n response: Response,\n timeoutScope: RequestTimeoutScope,\n): HttpResponse {\n const body = response.body\n if (body === null) timeoutScope.dispose()\n let timedBody: ReadableStream<Uint8Array> | undefined\n\n return {\n status: response.status,\n headers: response.headers,\n get body() {\n if (body === null) return null\n timedBody ??= createTimedResponseBody(body, timeoutScope)\n return timedBody\n },\n json: <T>() =>\n readTimedResponseBody(timeoutScope, response, () => response.json() as Promise<T>),\n text: () => readTimedResponseBody(timeoutScope, response, () => response.text()),\n arrayBuffer: () => readTimedResponseBody(timeoutScope, response, () => response.arrayBuffer()),\n }\n}\n\nasync function readTimedResponseBody<T>(\n timeoutScope: RequestTimeoutScope,\n response: Response,\n read: () => Promise<T>,\n): Promise<T> {\n try {\n return await raceBodyReadWithAbort(timeoutScope, read(), (reason) =>\n cancelResponseBody(response, reason),\n )\n } catch (err) {\n if (timeoutScope.timedOut) {\n throw createRequestTimeoutError(timeoutScope)\n }\n throw err\n } finally {\n timeoutScope.dispose()\n }\n}\n\nfunction createTimedResponseBody(\n body: ReadableStream<Uint8Array>,\n timeoutScope: RequestTimeoutScope,\n): ReadableStream<Uint8Array> {\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined\n let disposed = false\n const dispose = (): void => {\n if (disposed) return\n disposed = true\n timeoutScope.dispose()\n }\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n reader ??= body.getReader()\n try {\n const result = await raceBodyReadWithAbort(timeoutScope, reader.read(), (reason) =>\n reader?.cancel(reason),\n )\n if (result.done) {\n dispose()\n controller.close()\n return\n }\n timeoutScope.reset()\n controller.enqueue(result.value)\n } catch (err) {\n dispose()\n if (timeoutScope.timedOut) {\n controller.error(createRequestTimeoutError(timeoutScope))\n return\n }\n controller.error(err)\n }\n },\n async cancel(reason) {\n dispose()\n try {\n if (reader !== undefined) {\n await reader.cancel(reason)\n return\n }\n await body.cancel(reason)\n } catch {\n // Best-effort cleanup when the caller cancels the wrapper body.\n }\n },\n })\n}\n\nasync function raceBodyReadWithAbort<T>(\n timeoutScope: RequestTimeoutScope,\n read: Promise<T>,\n abortCleanup?: ((reason: unknown) => Promise<void> | void) | undefined,\n): Promise<T> {\n const signal = timeoutScope.signal\n if (signal === undefined) return read\n const abortReason = (): unknown => signal.reason ?? new DOMException('Aborted', 'AbortError')\n if (signal.aborted) {\n void read.catch(() => {})\n const reason = abortReason()\n await runAbortCleanup(abortCleanup, reason)\n throw reason\n }\n\n let removeAbortListener: (() => void) | undefined\n const abort = new Promise<never>((_, reject) => {\n const onAbort = (): void => {\n const reason = abortReason()\n void read.catch(() => {})\n reject(reason)\n void runAbortCleanup(abortCleanup, reason)\n }\n signal.addEventListener('abort', onAbort, { once: true })\n removeAbortListener = () => signal.removeEventListener('abort', onAbort)\n })\n\n try {\n return await Promise.race([read, abort])\n } finally {\n removeAbortListener?.()\n }\n}\n\nasync function runAbortCleanup(\n abortCleanup: ((reason: unknown) => Promise<void> | void) | undefined,\n reason: unknown,\n): Promise<void> {\n try {\n await abortCleanup?.(reason)\n } catch {\n // Abort cleanup is best-effort and must not mask the abort reason.\n }\n}\n\nfunction isBlockedRedirect(response: Response): boolean {\n return response.type === 'opaqueredirect' || REDIRECT_STATUSES.has(response.status)\n}\n\nfunction canFollowSameOriginRedirect(request: HttpRequest, location: string): boolean {\n if (request.method !== 'GET' && request.method !== 'HEAD') return false\n try {\n return new URL(request.url).origin === new URL(location, request.url).origin\n } catch {\n return false\n }\n}\n\nasync function cancelResponseBody(response: Response, reason?: unknown): Promise<void> {\n try {\n await response.body?.cancel(reason)\n } catch {\n // Best-effort cleanup before throwing the primary error.\n }\n}\n\n/** Configuration for {@link RetryTransport}. */\nexport interface RetryTransportOptions {\n /** The underlying transport to delegate requests to. */\n readonly transport: HttpTransport\n /** Override default retry settings (max retries, delays). */\n readonly retry?: Partial<RetryOptions>\n /**\n * Callback invoked on expired auth token errors. Must refresh\n * credentials AND return the fresh auth token. The transport\n * substitutes the new token into `request.headers.Authorization`\n * before retrying — without this, the retried request would still\n * carry the expired token captured by the original caller and the\n * loop would never make progress.\n */\n readonly onReauth?: () => Promise<string>\n /**\n * Sleep implementation used between retry attempts. Defaults to the real\n * `sleep` from `./retry.js`. Test code can inject a no-op to avoid real\n * delays without relying on module mocking (which differs across runners).\n *\n * @internal\n */\n readonly sleepImpl?: (ms: number, signal?: AbortSignal) => Promise<void>\n}\n\n/**\n * Decide whether `url` points at a URL-pinned upload POST endpoint.\n *\n * @param url - Request URL to inspect.\n *\n * @returns Whether the request is a direct upload endpoint.\n */\nfunction isUploadEndpoint(url: string): boolean {\n const endpoint = b2ApiEndpointName(url)\n return endpoint === 'b2_upload_file' || endpoint === 'b2_upload_part'\n}\n\nfunction isFinishLargeFileEndpoint(url: string): boolean {\n return b2ApiEndpointName(url) === 'b2_finish_large_file'\n}\n\nfunction isStartLargeFileEndpoint(url: string): boolean {\n return b2ApiEndpointName(url) === 'b2_start_large_file'\n}\n\nfunction b2ApiEndpointName(url: string): string | undefined {\n const [, root, , endpoint] = new URL(url).pathname.split('/')\n if (root !== 'b2api') return undefined\n return endpoint\n}\n\nfunction isReplayUnsafePostEndpoint(url: string): boolean {\n return isUploadEndpoint(url) || isStartLargeFileEndpoint(url) || isFinishLargeFileEndpoint(url)\n}\n\n/**\n * Decide whether a classified error should be retried in place for `url`.\n * Transient errors normally retry; upload endpoints bubble to the upload layer\n * for fresh-URL retry except account-level 429 throttling, where fetching a new\n * upload URL only amplifies the rate limit.\n *\n * @param error - The classified, retryability-tagged error.\n * @param url - The request URL (used to detect upload endpoints).\n *\n * @returns Whether to retry the request in place.\n */\nfunction shouldRetryInPlace(error: B2Error, url: string): boolean {\n if (!error.retryable) return false\n if (isStartLargeFileEndpoint(url) || isFinishLargeFileEndpoint(url)) return false\n if (isUploadEndpoint(url) && error.status === 429) return true\n if (isUploadEndpoint(url)) return false\n return true\n}\n\nfunction isRequestTimeoutError(err: unknown): boolean {\n return err instanceof DOMException && err.name === 'TimeoutError'\n}\n\nfunction isTerminalTransportError(err: unknown): boolean {\n return (\n err instanceof B2Error ||\n err instanceof B2RedirectError ||\n err instanceof NetworkError ||\n err instanceof B2SsrfError ||\n (err instanceof DOMException && err.name === 'AbortError')\n )\n}\n\n/**\n * Transport wrapper that adds automatic retry with exponential backoff.\n * Handles transient errors (408, 429, and the transient 5xx set 500/502/503/504),\n * expired auth tokens, and network failures. Delegates to an inner\n * {@link HttpTransport}.\n *\n * Upload endpoints (`b2_upload_file` / `b2_upload_part`) are URL-pinned. Their\n * retryable pod failures bubble to the upload layer, which evicts the failed\n * URL, fetches a fresh one, and retries there. HTTP 429 remains an in-place\n * retry so account-level throttling does not trigger extra upload URL fetches.\n */\nexport class RetryTransport implements HttpTransport {\n /** The wrapped transport that performs actual HTTP requests. */\n private readonly inner: HttpTransport\n /** Resolved retry options (defaults merged with user overrides). */\n private readonly options: RetryOptions\n /** Optional callback to refresh auth credentials on 401 — returns the fresh token. */\n private readonly onReauth?: () => Promise<string>\n /** Sleep implementation used between retries; injectable for tests. */\n private readonly sleepImpl: (ms: number, signal?: AbortSignal) => Promise<void>\n\n /**\n * Creates a new RetryTransport.\n * @param opts - Retry transport configuration.\n */\n constructor(opts: RetryTransportOptions) {\n this.inner = opts.transport\n this.options = { ...DEFAULT_RETRY_OPTIONS, ...opts.retry }\n if (opts.onReauth !== undefined) this.onReauth = opts.onReauth\n this.sleepImpl = opts.sleepImpl ?? sleep\n }\n\n /**\n * Sends the request with automatic retry on transient failures.\n * On expired auth tokens, calls {@link RetryTransportOptions.onReauth} and retries.\n * @param originalRequest - The HTTP request to execute. The caller's\n * reference is not mutated; on reauth, a copy with a refreshed\n * Authorization header is sent.\n *\n * @returns The HTTP response.\n */\n async send(originalRequest: HttpRequest): Promise<HttpResponse> {\n // `request` is reassigned (not mutated) when reauth produces a\n // fresh Authorization header, so the caller's `originalRequest`\n // stays untouched.\n let request: HttpRequest = originalRequest\n const retryOptions = { ...this.options, ...originalRequest.retry }\n let lastError: B2Error | NetworkError | undefined\n let didReauth = false\n let attempt = 0\n\n while (attempt <= retryOptions.maxRetries) {\n throwIfSignalAborted(request.signal)\n\n if (attempt > 0 && lastError) {\n const retryAfter = lastError instanceof NetworkError ? undefined : lastError.retryAfter\n const delay = computeBackoff(attempt - 1, retryOptions, retryAfter)\n await this.sleepImpl(delay, request.signal)\n }\n\n try {\n const response = await this.inner.send({ ...request, retry: retryOptions })\n await throwIfSignalAbortedAfterResponse(request.signal, response)\n\n if (response.status >= 200 && response.status < 300) {\n return response\n }\n\n let errorBody: B2ErrorResponse\n try {\n errorBody = await response.json<B2ErrorResponse>()\n } catch (err) {\n if (isRequestTimeoutError(err)) throw err\n errorBody = {\n status: response.status,\n code: 'internal_error',\n message: `HTTP ${response.status}`,\n }\n }\n\n const retryAfterHeader = response.headers.get('Retry-After')\n const retryAfterSec = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined\n const requestId = response.headers.get('X-Bz-Request-Id') ?? undefined\n\n const error = classifyError(errorBody, {\n ...(retryAfterSec !== undefined ? { retryAfter: retryAfterSec } : {}),\n ...(requestId !== undefined ? { requestId } : {}),\n })\n\n if (\n error instanceof ExpiredAuthTokenError &&\n this.onReauth &&\n !isUploadEndpoint(request.url) &&\n !didReauth\n ) {\n // Reauth returns the FRESH token; build a new request with a\n // shallow-copied headers object so the Authorization swap\n // doesn't mutate the caller's original request (which they\n // may hold for retry / introspection). Without this swap the\n // retry would carry the expired token captured at\n // request-build time and bounce off the server again,\n // exhausting the retry budget.\n const freshToken = await this.onReauth()\n request = {\n ...request,\n headers: { ...(request.headers ?? {}), Authorization: freshToken },\n }\n didReauth = true\n lastError = undefined\n continue\n }\n\n if (!shouldRetryInPlace(error, request.url) || attempt === retryOptions.maxRetries) {\n throw error\n }\n\n lastError = error\n attempt += 1\n } catch (err) {\n throwIfSignalAborted(request.signal)\n if (isTerminalTransportError(err)) {\n throw err\n }\n\n const networkErr = new NetworkError(\n err instanceof Error ? err.message : 'Network error',\n err,\n )\n\n if (isReplayUnsafePostEndpoint(request.url) || attempt === retryOptions.maxRetries) {\n throw networkErr\n }\n\n lastError = networkErr\n attempt += 1\n }\n }\n\n throw lastError ?? new NetworkError('Max retries exceeded')\n }\n}\n\nfunction throwIfSignalAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) {\n throw signal.reason ?? new DOMException('Aborted', 'AbortError')\n }\n}\n\nasync function throwIfSignalAbortedAfterResponse(\n signal: AbortSignal | undefined,\n response: HttpResponse,\n): Promise<void> {\n if (signal?.aborted !== true) return\n const reason = signal.reason ?? new DOMException('Aborted', 'AbortError')\n try {\n await response.body?.cancel(reason)\n } catch {\n // Best-effort cleanup before preserving the caller's abort reason.\n }\n throw reason\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transport.cjs","names":[],"sources":["../../src/http/transport.ts"],"sourcesContent":["import {\n B2Error,\n B2RedirectError,\n B2SsrfError,\n classifyError,\n ExpiredAuthTokenError,\n NetworkError,\n} from '../errors/index.ts'\nimport type { B2ErrorResponse } from '../types/errors.ts'\nimport { abortReason, raceWithAbort, throwIfSignalAborted } from '../util/abort.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from './retry.ts'\nimport { UrlGuard } from './url-guard.ts'\nimport { getUserAgent } from './user-agent.ts'\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308])\nconst MAX_SAME_ORIGIN_REDIRECTS = 5\n\n/** Describes an outgoing HTTP request to the B2 API. */\nexport interface HttpRequest {\n /** Fully qualified URL to send the request to. */\n readonly url: string\n /** HTTP method. B2 uses GET for downloads (HEAD to fetch only headers) and POST for all other operations. */\n readonly method: 'GET' | 'HEAD' | 'POST'\n /** Request headers. Authorization and content-type are typically included. */\n readonly headers?: Record<string, string>\n /** Request body. Used for POST requests (JSON payloads or file uploads). */\n readonly body?: BodyInit | null\n /** Optional abort signal for request cancellation. */\n readonly signal?: AbortSignal\n /** Optional per-request retry override. */\n readonly retry?: Partial<RetryOptions>\n}\n\n/** Represents a parsed HTTP response from the B2 API. */\nexport interface HttpResponse {\n /** HTTP status code. */\n readonly status: number\n /** Response headers. */\n readonly headers: Headers\n /** Response body as a readable stream, or null for empty responses. */\n readonly body: ReadableStream<Uint8Array> | null\n /** Parses the response body as JSON. */\n json<T>(): Promise<T>\n /** Reads the response body as a UTF-8 string. */\n text(): Promise<string>\n /** Reads the response body as an ArrayBuffer. */\n arrayBuffer(): Promise<ArrayBuffer>\n}\n\n/**\n * Transport layer abstraction for sending HTTP requests.\n * Implementations handle the actual network I/O and can be composed\n * (e.g. wrapping a {@link FetchTransport} with a {@link RetryTransport}).\n */\nexport interface HttpTransport {\n /** Sends an HTTP request and returns the response. */\n send(request: HttpRequest): Promise<HttpResponse>\n}\n\n/**\n * Transport capability for implementations that expose the SSRF URL guard\n * protecting credential-bearing requests. Wrappers that preserve this\n * capability should forward the same `urlGuard` property.\n */\nexport interface UrlGuardedTransport extends HttpTransport {\n /** SSRF allow-list applied to outgoing URLs. */\n readonly urlGuard: UrlGuard\n}\n\n/**\n * Returns the URL guard exposed by `transport`, if it implements\n * {@link UrlGuardedTransport}.\n *\n * @param transport - Transport to inspect.\n *\n * @returns The exposed URL guard, or undefined for unguarded transports.\n */\nexport function getTransportUrlGuard(transport: HttpTransport): UrlGuard | undefined {\n const candidate = transport as Partial<UrlGuardedTransport>\n return candidate.urlGuard instanceof UrlGuard ? candidate.urlGuard : undefined\n}\n\n/**\n * Default transport implementation using the global `fetch` API.\n * Automatically sets the User-Agent header on each request and applies the\n * SSRF {@link UrlGuard} (if configured) before opening the connection.\n * Redirect following is disabled so redirected URLs cannot bypass the guard or\n * receive credential-bearing headers without an explicit checked request.\n */\nexport class FetchTransport implements UrlGuardedTransport {\n /** User-Agent string sent with every request. */\n private readonly userAgent: string\n /** Whether same-origin GET/HEAD redirects should be followed after guard checks. */\n private readonly followSameOriginRedirects: boolean\n /** SSRF allow-list applied to every outgoing URL. Mutable so `B2Client.authorize()` can lock it down post-auth. */\n readonly urlGuard: UrlGuard\n\n /**\n * Creates a new FetchTransport.\n * @param options - Optional configuration: custom User-Agent prefix and SSRF guard.\n */\n constructor(options?: {\n userAgent?: string\n urlGuard?: UrlGuard\n /**\n * Follow same-origin GET/HEAD redirects after checking the target with the\n * URL guard. POST redirects are still blocked to avoid replaying\n * credential-bearing payloads to an unexpected endpoint. Defaults to true.\n */\n followSameOriginRedirects?: boolean\n }) {\n this.userAgent = getUserAgent(options?.userAgent)\n this.followSameOriginRedirects = options?.followSameOriginRedirects ?? true\n this.urlGuard = options?.urlGuard ?? new UrlGuard()\n }\n\n /**\n * Sends the request using the global `fetch` function.\n * @param request - The HTTP request to execute.\n *\n * @returns The HTTP response.\n *\n * @throws B2SsrfError when the URL fails the configured SSRF guard.\n * @throws B2RedirectError when a response attempts to redirect.\n */\n async send(request: HttpRequest): Promise<HttpResponse> {\n let currentRequest = request\n let redirectCount = 0\n\n while (true) {\n this.urlGuard.check(currentRequest.url)\n\n const headers = new Headers(currentRequest.headers)\n if (!headers.has('User-Agent')) {\n headers.set('User-Agent', this.userAgent)\n }\n\n const timeoutScope = createRequestTimeoutScope(currentRequest)\n let response: Response\n try {\n response = await fetch(currentRequest.url, {\n method: currentRequest.method,\n headers,\n body: currentRequest.body ?? null,\n redirect: 'manual',\n ...(timeoutScope.signal !== undefined ? { signal: timeoutScope.signal } : {}),\n })\n } catch (err) {\n timeoutScope.dispose()\n if (timeoutScope.timedOut) {\n throw createRequestTimeoutError(timeoutScope)\n }\n throw err\n }\n\n if (isBlockedRedirect(response)) {\n const location = response.headers.get('Location')\n if (\n this.followSameOriginRedirects &&\n location !== null &&\n redirectCount < MAX_SAME_ORIGIN_REDIRECTS &&\n canFollowSameOriginRedirect(currentRequest, location)\n ) {\n const nextUrl = new URL(location, currentRequest.url).toString()\n await cancelResponseBody(response)\n timeoutScope.dispose()\n this.urlGuard.check(nextUrl)\n currentRequest = { ...currentRequest, url: nextUrl }\n redirectCount += 1\n continue\n }\n\n await cancelResponseBody(response)\n timeoutScope.dispose()\n throw new B2RedirectError(currentRequest.url, response.status, location)\n }\n\n return createTimedHttpResponse(response, timeoutScope)\n }\n }\n}\n\ninterface RequestTimeoutScope {\n readonly signal?: AbortSignal\n readonly timeoutMs: number\n readonly timedOut: boolean\n reset(): void\n dispose(): void\n}\n\nfunction createRequestTimeoutScope(request: HttpRequest): RequestTimeoutScope {\n const timeoutMs = request.retry?.requestTimeoutMs ?? DEFAULT_RETRY_OPTIONS.requestTimeoutMs\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n const scope: RequestTimeoutScope = {\n timeoutMs: 0,\n timedOut: false,\n reset() {},\n dispose() {},\n }\n if (request.signal !== undefined) return { ...scope, signal: request.signal }\n return scope\n }\n\n const controller = new AbortController()\n let timedOut = false\n let timer: ReturnType<typeof setTimeout>\n const abortFromUpstream = (): void => {\n clearTimeout(timer)\n controller.abort(request.signal?.reason ?? new DOMException('Aborted', 'AbortError'))\n }\n const armTimer = (): ReturnType<typeof setTimeout> => {\n const nextTimer = setTimeout(() => {\n timedOut = true\n controller.abort(new DOMException('HTTP request timed out', 'TimeoutError'))\n }, timeoutMs)\n unrefTimer(nextTimer)\n return nextTimer\n }\n timer = armTimer()\n\n const reset = (): void => {\n if (timedOut || controller.signal.aborted) return\n clearTimeout(timer)\n timer = armTimer()\n }\n\n if (request.signal?.aborted === true) {\n clearTimeout(timer)\n abortFromUpstream()\n } else {\n request.signal?.addEventListener('abort', abortFromUpstream, { once: true })\n }\n\n return {\n signal: controller.signal,\n timeoutMs,\n get timedOut() {\n return timedOut\n },\n reset,\n dispose() {\n clearTimeout(timer)\n request.signal?.removeEventListener('abort', abortFromUpstream)\n },\n }\n}\n\nfunction unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n const maybeUnref = (timer as { unref?: () => void }).unref\n if (typeof maybeUnref === 'function') maybeUnref.call(timer)\n}\n\nfunction createRequestTimeoutError(scope: RequestTimeoutScope): DOMException {\n return new DOMException(`HTTP request timed out after ${scope.timeoutMs} ms`, 'TimeoutError')\n}\n\nfunction createTimedHttpResponse(\n response: Response,\n timeoutScope: RequestTimeoutScope,\n): HttpResponse {\n const body = response.body\n if (body === null) timeoutScope.dispose()\n let timedBody: ReadableStream<Uint8Array> | undefined\n\n return {\n status: response.status,\n headers: response.headers,\n get body() {\n if (body === null) return null\n timedBody ??= createTimedResponseBody(body, timeoutScope)\n return timedBody\n },\n json: <T>() =>\n readTimedResponseBody(timeoutScope, response, () => response.json() as Promise<T>),\n text: () => readTimedResponseBody(timeoutScope, response, () => response.text()),\n arrayBuffer: () => readTimedResponseBody(timeoutScope, response, () => response.arrayBuffer()),\n }\n}\n\nasync function readTimedResponseBody<T>(\n timeoutScope: RequestTimeoutScope,\n response: Response,\n read: () => Promise<T>,\n): Promise<T> {\n try {\n return await raceBodyReadWithAbort(timeoutScope, read(), (reason) =>\n cancelResponseBody(response, reason),\n )\n } catch (err) {\n if (timeoutScope.timedOut) {\n throw createRequestTimeoutError(timeoutScope)\n }\n throw err\n } finally {\n timeoutScope.dispose()\n }\n}\n\nfunction createTimedResponseBody(\n body: ReadableStream<Uint8Array>,\n timeoutScope: RequestTimeoutScope,\n): ReadableStream<Uint8Array> {\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined\n let disposed = false\n const dispose = (): void => {\n if (disposed) return\n disposed = true\n timeoutScope.dispose()\n }\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n reader ??= body.getReader()\n try {\n const result = await raceBodyReadWithAbort(timeoutScope, reader.read(), (reason) =>\n reader?.cancel(reason),\n )\n if (result.done) {\n dispose()\n controller.close()\n return\n }\n timeoutScope.reset()\n controller.enqueue(result.value)\n } catch (err) {\n dispose()\n if (timeoutScope.timedOut) {\n controller.error(createRequestTimeoutError(timeoutScope))\n return\n }\n controller.error(err)\n }\n },\n async cancel(reason) {\n dispose()\n try {\n if (reader !== undefined) {\n await reader.cancel(reason)\n return\n }\n await body.cancel(reason)\n } catch {\n // Best-effort cleanup when the caller cancels the wrapper body.\n }\n },\n })\n}\n\nasync function raceBodyReadWithAbort<T>(\n timeoutScope: RequestTimeoutScope,\n read: Promise<T>,\n abortCleanup?: ((reason: unknown) => Promise<void> | void) | undefined,\n): Promise<T> {\n const signal = timeoutScope.signal\n if (signal === undefined) return read\n if (signal.aborted) {\n void read.catch(() => {})\n const reason = abortReason(signal)\n await runAbortCleanup(abortCleanup, reason)\n throw reason\n }\n\n let removeAbortListener: (() => void) | undefined\n const abort = new Promise<never>((_, reject) => {\n const onAbort = (): void => {\n const reason = abortReason(signal)\n void read.catch(() => {})\n reject(reason)\n void runAbortCleanup(abortCleanup, reason)\n }\n signal.addEventListener('abort', onAbort, { once: true })\n removeAbortListener = () => signal.removeEventListener('abort', onAbort)\n })\n\n try {\n return await Promise.race([read, abort])\n } finally {\n removeAbortListener?.()\n }\n}\n\nasync function runAbortCleanup(\n abortCleanup: ((reason: unknown) => Promise<void> | void) | undefined,\n reason: unknown,\n): Promise<void> {\n try {\n await abortCleanup?.(reason)\n } catch {\n // Abort cleanup is best-effort and must not mask the abort reason.\n }\n}\n\nfunction isBlockedRedirect(response: Response): boolean {\n return response.type === 'opaqueredirect' || REDIRECT_STATUSES.has(response.status)\n}\n\nfunction canFollowSameOriginRedirect(request: HttpRequest, location: string): boolean {\n if (request.method !== 'GET' && request.method !== 'HEAD') return false\n try {\n return new URL(request.url).origin === new URL(location, request.url).origin\n } catch {\n return false\n }\n}\n\nasync function cancelResponseBody(response: Response, reason?: unknown): Promise<void> {\n try {\n await response.body?.cancel(reason)\n } catch {\n // Best-effort cleanup before throwing the primary error.\n }\n}\n\n/** Configuration for {@link RetryTransport}. */\nexport interface RetryTransportOptions {\n /** The underlying transport to delegate requests to. */\n readonly transport: HttpTransport\n /** Override default retry settings (max retries, delays). */\n readonly retry?: Partial<RetryOptions>\n /**\n * Callback invoked on expired auth token errors. Must refresh\n * credentials AND return the fresh auth token. The original request's\n * abort signal is forwarded so reauthorization can be cancelled with the\n * operation that triggered it. The transport\n * substitutes the new token into `request.headers.Authorization`\n * before retrying — without this, the retried request would still\n * carry the expired token captured by the original caller and the\n * loop would never make progress.\n */\n readonly onReauth?: (signal?: AbortSignal) => Promise<string>\n /**\n * Sleep implementation used between retry attempts. Defaults to the real\n * `sleep` from `./retry.js`. Test code can inject a no-op to avoid real\n * delays without relying on module mocking (which differs across runners).\n *\n * @internal\n */\n readonly sleepImpl?: (ms: number, signal?: AbortSignal) => Promise<void>\n}\n\n/**\n * Decide whether `url` points at a URL-pinned upload POST endpoint.\n *\n * @param url - Request URL to inspect.\n *\n * @returns Whether the request is a direct upload endpoint.\n */\nfunction isUploadEndpoint(url: string): boolean {\n const endpoint = b2ApiEndpointName(url)\n return endpoint === 'b2_upload_file' || endpoint === 'b2_upload_part'\n}\n\nfunction isFinishLargeFileEndpoint(url: string): boolean {\n return b2ApiEndpointName(url) === 'b2_finish_large_file'\n}\n\nfunction isAuthorizeEndpoint(url: string): boolean {\n return b2ApiEndpointName(url) === 'b2_authorize_account'\n}\n\nfunction isStartLargeFileEndpoint(url: string): boolean {\n return b2ApiEndpointName(url) === 'b2_start_large_file'\n}\n\nfunction isPartnerMutationEndpoint(url: string): boolean {\n const endpoint = b2ApiEndpointName(url)\n return (\n endpoint === 'b2_create_group_member' ||\n endpoint === 'b2_eject_group_member' ||\n endpoint === 'b2_reserve_trial_create_account'\n )\n}\n\nfunction isBackupMutationEndpoint(url: string): boolean {\n return backupApiEndpointName(url) === 'bz_delete_computer'\n}\n\nfunction isNonIdempotentMutationRequest(request: HttpRequest): boolean {\n return (\n request.method === 'POST' &&\n (isPartnerMutationEndpoint(request.url) || isBackupMutationEndpoint(request.url))\n )\n}\n\nfunction b2ApiEndpointName(url: string): string | undefined {\n const segments = new URL(url).pathname.split('/').filter((segment) => segment.length > 0)\n // Partner endpoint base URLs can themselves contain a b2api-looking segment\n // before the SDK appends the real API route. Classify the terminal route.\n const apiRootIndex = segments.lastIndexOf('b2api')\n if (apiRootIndex === -1) return undefined\n return segments[apiRootIndex + 2]\n}\n\nfunction backupApiEndpointName(url: string): string | undefined {\n const segments = new URL(url).pathname.split('/').filter((segment) => segment.length > 0)\n const apiRootIndex = segments.lastIndexOf('api')\n if (apiRootIndex === -1 || segments[apiRootIndex + 1] !== 'backup') return undefined\n if (!/^v\\d+$/.test(segments[apiRootIndex + 2] ?? '')) return undefined\n return segments[apiRootIndex + 3]\n}\n\nfunction isReplayUnsafePostRequest(request: HttpRequest): boolean {\n if (request.method !== 'POST') return false\n return (\n isUploadEndpoint(request.url) ||\n isStartLargeFileEndpoint(request.url) ||\n isFinishLargeFileEndpoint(request.url) ||\n isNonIdempotentMutationRequest(request)\n )\n}\n\n/**\n * Decide whether a classified error should be retried in place for `url`.\n * Transient errors normally retry; upload endpoints bubble to the upload layer\n * for fresh-URL retry except account-level 429 throttling, where fetching a new\n * upload URL only amplifies the rate limit.\n *\n * @param error - The classified, retryability-tagged error.\n * @param request - The request being considered for in-place retry.\n *\n * @returns Whether to retry the request in place.\n */\nfunction shouldRetryInPlace(error: B2Error, request: HttpRequest): boolean {\n if (!error.retryable) return false\n if (isAuthorizeEndpoint(request.url) && error instanceof ExpiredAuthTokenError) return false\n if (isNonIdempotentMutationRequest(request)) return false\n if (isStartLargeFileEndpoint(request.url) || isFinishLargeFileEndpoint(request.url)) return false\n if (isUploadEndpoint(request.url) && error.status === 429) return true\n if (isUploadEndpoint(request.url)) return false\n return true\n}\n\nfunction isRequestTimeoutError(err: unknown): boolean {\n return err instanceof DOMException && err.name === 'TimeoutError'\n}\n\nfunction isTerminalTransportError(err: unknown): boolean {\n return (\n err instanceof B2Error ||\n err instanceof B2RedirectError ||\n err instanceof NetworkError ||\n err instanceof B2SsrfError ||\n (err instanceof DOMException && err.name === 'AbortError')\n )\n}\n\n/**\n * Transport wrapper that adds automatic retry with exponential backoff.\n * Handles transient errors (408, 429, and the transient 5xx set 500/502/503/504),\n * expired auth tokens, and network failures. Delegates to an inner\n * {@link HttpTransport}.\n *\n * Upload endpoints (`b2_upload_file` / `b2_upload_part`) are URL-pinned. Their\n * retryable pod failures bubble to the upload layer, which evicts the failed\n * URL, fetches a fresh one, and retries there. HTTP 429 remains an in-place\n * retry so account-level throttling does not trigger extra upload URL fetches.\n */\nexport class RetryTransport implements HttpTransport {\n /** URL guard from the wrapped transport, when the transport exposes one. */\n readonly urlGuard: UrlGuard | undefined\n /** The wrapped transport that performs actual HTTP requests. */\n private readonly inner: HttpTransport\n /** Resolved retry options (defaults merged with user overrides). */\n private readonly options: RetryOptions\n /** Optional callback to refresh auth credentials on 401 — returns the fresh token. */\n private readonly onReauth?: (signal?: AbortSignal) => Promise<string>\n /** Sleep implementation used between retries; injectable for tests. */\n private readonly sleepImpl: (ms: number, signal?: AbortSignal) => Promise<void>\n\n /**\n * Creates a new RetryTransport.\n * @param opts - Retry transport configuration.\n */\n constructor(opts: RetryTransportOptions) {\n this.inner = opts.transport\n this.urlGuard = getTransportUrlGuard(opts.transport)\n this.options = { ...DEFAULT_RETRY_OPTIONS, ...opts.retry }\n if (opts.onReauth !== undefined) this.onReauth = opts.onReauth\n this.sleepImpl = opts.sleepImpl ?? sleep\n }\n\n /**\n * Sends the request with automatic retry on transient failures.\n * On expired auth tokens, calls {@link RetryTransportOptions.onReauth} and retries.\n * @param originalRequest - The HTTP request to execute. The caller's\n * reference is not mutated; on reauth, a copy with a refreshed\n * Authorization header is sent.\n *\n * @returns The HTTP response.\n */\n async send(originalRequest: HttpRequest): Promise<HttpResponse> {\n // `request` is reassigned (not mutated) when reauth produces a\n // fresh Authorization header, so the caller's `originalRequest`\n // stays untouched.\n let request: HttpRequest = originalRequest\n const retryOptions = { ...this.options, ...originalRequest.retry }\n let lastError: B2Error | NetworkError | undefined\n let didReauth = false\n let attempt = 0\n\n while (attempt <= retryOptions.maxRetries) {\n throwIfSignalAborted(request.signal)\n\n if (attempt > 0 && lastError) {\n const retryAfter = lastError instanceof NetworkError ? undefined : lastError.retryAfter\n const delay = computeBackoff(attempt - 1, retryOptions, retryAfter)\n await this.sleepImpl(delay, request.signal)\n }\n\n try {\n const response = await this.inner.send({ ...request, retry: retryOptions })\n await throwIfSignalAbortedAfterResponse(request.signal, response)\n\n if (response.status >= 200 && response.status < 300) {\n return response\n }\n\n let errorBody: B2ErrorResponse\n try {\n errorBody = await response.json<B2ErrorResponse>()\n } catch (err) {\n if (isRequestTimeoutError(err)) throw err\n errorBody = {\n status: response.status,\n code: 'internal_error',\n message: `HTTP ${response.status}`,\n }\n }\n\n const retryAfterHeader = response.headers.get('Retry-After')\n const retryAfterSec = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined\n const requestId = response.headers.get('X-Bz-Request-Id') ?? undefined\n\n const error = classifyError(errorBody, {\n ...(retryAfterSec !== undefined ? { retryAfter: retryAfterSec } : {}),\n ...(requestId !== undefined ? { requestId } : {}),\n })\n\n if (\n error instanceof ExpiredAuthTokenError &&\n this.onReauth &&\n !isAuthorizeEndpoint(request.url) &&\n !isUploadEndpoint(request.url) &&\n !isNonIdempotentMutationRequest(request) &&\n !didReauth\n ) {\n // Reauth returns the FRESH token; build a new request with a\n // shallow-copied headers object so the Authorization swap\n // doesn't mutate the caller's original request (which they\n // may hold for retry / introspection). Without this swap the\n // retry would carry the expired token captured at\n // request-build time and bounce off the server again,\n // exhausting the retry budget.\n const freshToken = await raceWithAbort(this.onReauth(request.signal), request.signal)\n throwIfSignalAborted(request.signal)\n request = {\n ...request,\n headers: { ...(request.headers ?? {}), Authorization: freshToken },\n }\n didReauth = true\n lastError = undefined\n continue\n }\n\n if (!shouldRetryInPlace(error, request) || attempt === retryOptions.maxRetries) {\n throw error\n }\n\n lastError = error\n attempt += 1\n } catch (err) {\n throwIfSignalAborted(request.signal)\n if (isTerminalTransportError(err)) {\n throw err\n }\n\n const networkErr = new NetworkError(\n err instanceof Error ? err.message : 'Network error',\n err,\n )\n\n if (isReplayUnsafePostRequest(request) || attempt === retryOptions.maxRetries) {\n throw networkErr\n }\n\n lastError = networkErr\n attempt += 1\n }\n }\n\n throw lastError ?? new NetworkError('Max retries exceeded')\n }\n}\n\nasync function throwIfSignalAbortedAfterResponse(\n signal: AbortSignal | undefined,\n response: HttpResponse,\n): Promise<void> {\n if (signal?.aborted !== true) return\n const reason = abortReason(signal)\n try {\n await response.body?.cancel(reason)\n } catch {\n // Best-effort cleanup before preserving the caller's abort reason.\n }\n throw reason\n}\n"],"mappings":"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"}
|
|
@@ -39,6 +39,24 @@ export interface HttpTransport {
|
|
|
39
39
|
/** Sends an HTTP request and returns the response. */
|
|
40
40
|
send(request: HttpRequest): Promise<HttpResponse>;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Transport capability for implementations that expose the SSRF URL guard
|
|
44
|
+
* protecting credential-bearing requests. Wrappers that preserve this
|
|
45
|
+
* capability should forward the same `urlGuard` property.
|
|
46
|
+
*/
|
|
47
|
+
export interface UrlGuardedTransport extends HttpTransport {
|
|
48
|
+
/** SSRF allow-list applied to outgoing URLs. */
|
|
49
|
+
readonly urlGuard: UrlGuard;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the URL guard exposed by `transport`, if it implements
|
|
53
|
+
* {@link UrlGuardedTransport}.
|
|
54
|
+
*
|
|
55
|
+
* @param transport - Transport to inspect.
|
|
56
|
+
*
|
|
57
|
+
* @returns The exposed URL guard, or undefined for unguarded transports.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getTransportUrlGuard(transport: HttpTransport): UrlGuard | undefined;
|
|
42
60
|
/**
|
|
43
61
|
* Default transport implementation using the global `fetch` API.
|
|
44
62
|
* Automatically sets the User-Agent header on each request and applies the
|
|
@@ -46,7 +64,7 @@ export interface HttpTransport {
|
|
|
46
64
|
* Redirect following is disabled so redirected URLs cannot bypass the guard or
|
|
47
65
|
* receive credential-bearing headers without an explicit checked request.
|
|
48
66
|
*/
|
|
49
|
-
export declare class FetchTransport implements
|
|
67
|
+
export declare class FetchTransport implements UrlGuardedTransport {
|
|
50
68
|
/** User-Agent string sent with every request. */
|
|
51
69
|
private readonly userAgent;
|
|
52
70
|
/** Whether same-origin GET/HEAD redirects should be followed after guard checks. */
|
|
@@ -86,13 +104,15 @@ export interface RetryTransportOptions {
|
|
|
86
104
|
readonly retry?: Partial<RetryOptions>;
|
|
87
105
|
/**
|
|
88
106
|
* Callback invoked on expired auth token errors. Must refresh
|
|
89
|
-
* credentials AND return the fresh auth token. The
|
|
107
|
+
* credentials AND return the fresh auth token. The original request's
|
|
108
|
+
* abort signal is forwarded so reauthorization can be cancelled with the
|
|
109
|
+
* operation that triggered it. The transport
|
|
90
110
|
* substitutes the new token into `request.headers.Authorization`
|
|
91
111
|
* before retrying — without this, the retried request would still
|
|
92
112
|
* carry the expired token captured by the original caller and the
|
|
93
113
|
* loop would never make progress.
|
|
94
114
|
*/
|
|
95
|
-
readonly onReauth?: () => Promise<string>;
|
|
115
|
+
readonly onReauth?: (signal?: AbortSignal) => Promise<string>;
|
|
96
116
|
/**
|
|
97
117
|
* Sleep implementation used between retry attempts. Defaults to the real
|
|
98
118
|
* `sleep` from `./retry.js`. Test code can inject a no-op to avoid real
|
|
@@ -114,6 +134,8 @@ export interface RetryTransportOptions {
|
|
|
114
134
|
* retry so account-level throttling does not trigger extra upload URL fetches.
|
|
115
135
|
*/
|
|
116
136
|
export declare class RetryTransport implements HttpTransport {
|
|
137
|
+
/** URL guard from the wrapped transport, when the transport exposes one. */
|
|
138
|
+
readonly urlGuard: UrlGuard | undefined;
|
|
117
139
|
/** The wrapped transport that performs actual HTTP requests. */
|
|
118
140
|
private readonly inner;
|
|
119
141
|
/** Resolved retry options (defaults merged with user overrides). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/http/transport.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/http/transport.js"],"names":[],"mappings":"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"}
|
package/dist/http/transport.d.ts
CHANGED
|
@@ -39,6 +39,24 @@ export interface HttpTransport {
|
|
|
39
39
|
/** Sends an HTTP request and returns the response. */
|
|
40
40
|
send(request: HttpRequest): Promise<HttpResponse>;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Transport capability for implementations that expose the SSRF URL guard
|
|
44
|
+
* protecting credential-bearing requests. Wrappers that preserve this
|
|
45
|
+
* capability should forward the same `urlGuard` property.
|
|
46
|
+
*/
|
|
47
|
+
export interface UrlGuardedTransport extends HttpTransport {
|
|
48
|
+
/** SSRF allow-list applied to outgoing URLs. */
|
|
49
|
+
readonly urlGuard: UrlGuard;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the URL guard exposed by `transport`, if it implements
|
|
53
|
+
* {@link UrlGuardedTransport}.
|
|
54
|
+
*
|
|
55
|
+
* @param transport - Transport to inspect.
|
|
56
|
+
*
|
|
57
|
+
* @returns The exposed URL guard, or undefined for unguarded transports.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getTransportUrlGuard(transport: HttpTransport): UrlGuard | undefined;
|
|
42
60
|
/**
|
|
43
61
|
* Default transport implementation using the global `fetch` API.
|
|
44
62
|
* Automatically sets the User-Agent header on each request and applies the
|
|
@@ -46,7 +64,7 @@ export interface HttpTransport {
|
|
|
46
64
|
* Redirect following is disabled so redirected URLs cannot bypass the guard or
|
|
47
65
|
* receive credential-bearing headers without an explicit checked request.
|
|
48
66
|
*/
|
|
49
|
-
export declare class FetchTransport implements
|
|
67
|
+
export declare class FetchTransport implements UrlGuardedTransport {
|
|
50
68
|
/** User-Agent string sent with every request. */
|
|
51
69
|
private readonly userAgent;
|
|
52
70
|
/** Whether same-origin GET/HEAD redirects should be followed after guard checks. */
|
|
@@ -86,13 +104,15 @@ export interface RetryTransportOptions {
|
|
|
86
104
|
readonly retry?: Partial<RetryOptions>;
|
|
87
105
|
/**
|
|
88
106
|
* Callback invoked on expired auth token errors. Must refresh
|
|
89
|
-
* credentials AND return the fresh auth token. The
|
|
107
|
+
* credentials AND return the fresh auth token. The original request's
|
|
108
|
+
* abort signal is forwarded so reauthorization can be cancelled with the
|
|
109
|
+
* operation that triggered it. The transport
|
|
90
110
|
* substitutes the new token into `request.headers.Authorization`
|
|
91
111
|
* before retrying — without this, the retried request would still
|
|
92
112
|
* carry the expired token captured by the original caller and the
|
|
93
113
|
* loop would never make progress.
|
|
94
114
|
*/
|
|
95
|
-
readonly onReauth?: () => Promise<string>;
|
|
115
|
+
readonly onReauth?: (signal?: AbortSignal) => Promise<string>;
|
|
96
116
|
/**
|
|
97
117
|
* Sleep implementation used between retry attempts. Defaults to the real
|
|
98
118
|
* `sleep` from `./retry.js`. Test code can inject a no-op to avoid real
|
|
@@ -114,6 +134,8 @@ export interface RetryTransportOptions {
|
|
|
114
134
|
* retry so account-level throttling does not trigger extra upload URL fetches.
|
|
115
135
|
*/
|
|
116
136
|
export declare class RetryTransport implements HttpTransport {
|
|
137
|
+
/** URL guard from the wrapped transport, when the transport exposes one. */
|
|
138
|
+
readonly urlGuard: UrlGuard | undefined;
|
|
117
139
|
/** The wrapped transport that performs actual HTTP requests. */
|
|
118
140
|
private readonly inner;
|
|
119
141
|
/** Resolved retry options (defaults merged with user overrides). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/http/transport.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/http/transport.js"],"names":[],"mappings":"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"}
|