@backblaze-labs/b2-sdk 0.1.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 +121 -0
- package/LICENSE +21 -0
- package/README.md +664 -0
- package/dist/auth/account-info.d.cts +51 -0
- package/dist/auth/account-info.d.cts.map +1 -0
- package/dist/auth/account-info.d.ts +51 -0
- package/dist/auth/account-info.d.ts.map +1 -0
- package/dist/auth/file.cjs +210 -0
- package/dist/auth/file.cjs.map +1 -0
- package/dist/auth/file.d.cts +157 -0
- package/dist/auth/file.d.cts.map +1 -0
- package/dist/auth/file.d.ts +157 -0
- package/dist/auth/file.d.ts.map +1 -0
- package/dist/auth/file.js +210 -0
- package/dist/auth/file.js.map +1 -0
- package/dist/auth/in-memory.cjs +184 -0
- package/dist/auth/in-memory.cjs.map +1 -0
- package/dist/auth/in-memory.d.cts +147 -0
- package/dist/auth/in-memory.d.cts.map +1 -0
- package/dist/auth/in-memory.d.ts +147 -0
- package/dist/auth/in-memory.d.ts.map +1 -0
- package/dist/auth/in-memory.js +184 -0
- package/dist/auth/in-memory.js.map +1 -0
- package/dist/auth/index.cjs +10 -0
- package/dist/auth/index.cjs.map +1 -0
- package/dist/auth/index.d.cts +6 -0
- package/dist/auth/index.d.cts.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +10 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/realms.cjs +12 -0
- package/dist/auth/realms.cjs.map +1 -0
- package/dist/auth/realms.d.cts +12 -0
- package/dist/auth/realms.d.cts.map +1 -0
- package/dist/auth/realms.d.ts +12 -0
- package/dist/auth/realms.d.ts.map +1 -0
- package/dist/auth/realms.js +12 -0
- package/dist/auth/realms.js.map +1 -0
- package/dist/auth/upload-url-pool.cjs +52 -0
- package/dist/auth/upload-url-pool.cjs.map +1 -0
- package/dist/auth/upload-url-pool.d.cts +35 -0
- package/dist/auth/upload-url-pool.d.cts.map +1 -0
- package/dist/auth/upload-url-pool.d.ts +35 -0
- package/dist/auth/upload-url-pool.d.ts.map +1 -0
- package/dist/auth/upload-url-pool.js +52 -0
- package/dist/auth/upload-url-pool.js.map +1 -0
- package/dist/bucket.cjs +789 -0
- package/dist/bucket.cjs.map +1 -0
- package/dist/bucket.d.cts +659 -0
- package/dist/bucket.d.cts.map +1 -0
- package/dist/bucket.d.ts +659 -0
- package/dist/bucket.d.ts.map +1 -0
- package/dist/bucket.js +789 -0
- package/dist/bucket.js.map +1 -0
- package/dist/client.cjs +230 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +222 -0
- package/dist/client.d.cts.map +1 -0
- package/dist/client.d.ts +222 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +230 -0
- package/dist/client.js.map +1 -0
- package/dist/copy/large.cjs +74 -0
- package/dist/copy/large.cjs.map +1 -0
- package/dist/copy/large.d.cts +53 -0
- package/dist/copy/large.d.cts.map +1 -0
- package/dist/copy/large.d.ts +53 -0
- package/dist/copy/large.d.ts.map +1 -0
- package/dist/copy/large.js +74 -0
- package/dist/copy/large.js.map +1 -0
- package/dist/download/parallel.cjs +122 -0
- package/dist/download/parallel.cjs.map +1 -0
- package/dist/download/parallel.d.cts +42 -0
- package/dist/download/parallel.d.cts.map +1 -0
- package/dist/download/parallel.d.ts +42 -0
- package/dist/download/parallel.d.ts.map +1 -0
- package/dist/download/parallel.js +122 -0
- package/dist/download/parallel.js.map +1 -0
- package/dist/download/single.cjs +117 -0
- package/dist/download/single.cjs.map +1 -0
- package/dist/download/single.d.cts +152 -0
- package/dist/download/single.d.cts.map +1 -0
- package/dist/download/single.d.ts +152 -0
- package/dist/download/single.d.ts.map +1 -0
- package/dist/download/single.js +117 -0
- package/dist/download/single.js.map +1 -0
- package/dist/errors/index.cjs +268 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.cts +264 -0
- package/dist/errors/index.d.cts.map +1 -0
- package/dist/errors/index.d.ts +264 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +268 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/http/retry.cjs +36 -0
- package/dist/http/retry.cjs.map +1 -0
- package/dist/http/retry.d.cts +34 -0
- package/dist/http/retry.d.cts.map +1 -0
- package/dist/http/retry.d.ts +34 -0
- package/dist/http/retry.d.ts.map +1 -0
- package/dist/http/retry.js +36 -0
- package/dist/http/retry.js.map +1 -0
- package/dist/http/transport.cjs +143 -0
- package/dist/http/transport.cjs.map +1 -0
- package/dist/http/transport.d.cts +122 -0
- package/dist/http/transport.d.cts.map +1 -0
- package/dist/http/transport.d.ts +122 -0
- package/dist/http/transport.d.ts.map +1 -0
- package/dist/http/transport.js +143 -0
- package/dist/http/transport.js.map +1 -0
- package/dist/http/url-guard.cjs +97 -0
- package/dist/http/url-guard.cjs.map +1 -0
- package/dist/http/url-guard.d.cts +88 -0
- package/dist/http/url-guard.d.cts.map +1 -0
- package/dist/http/url-guard.d.ts +88 -0
- package/dist/http/url-guard.d.ts.map +1 -0
- package/dist/http/url-guard.js +97 -0
- package/dist/http/url-guard.js.map +1 -0
- package/dist/http/user-agent.cjs +51 -0
- package/dist/http/user-agent.cjs.map +1 -0
- package/dist/http/user-agent.d.cts +28 -0
- package/dist/http/user-agent.d.cts.map +1 -0
- package/dist/http/user-agent.d.ts +28 -0
- package/dist/http/user-agent.d.ts.map +1 -0
- package/dist/http/user-agent.js +51 -0
- package/dist/http/user-agent.js.map +1 -0
- package/dist/index.cjs +78 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +39 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/index.cjs +7 -0
- package/dist/notifications/index.cjs.map +1 -0
- package/dist/notifications/index.d.cts +3 -0
- package/dist/notifications/index.d.cts.map +1 -0
- package/dist/notifications/index.d.ts +3 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/webhook.cjs +106 -0
- package/dist/notifications/webhook.cjs.map +1 -0
- package/dist/notifications/webhook.d.cts +146 -0
- package/dist/notifications/webhook.d.cts.map +1 -0
- package/dist/notifications/webhook.d.ts +146 -0
- package/dist/notifications/webhook.d.ts.map +1 -0
- package/dist/notifications/webhook.js +106 -0
- package/dist/notifications/webhook.js.map +1 -0
- package/dist/object.cjs +212 -0
- package/dist/object.cjs.map +1 -0
- package/dist/object.d.cts +263 -0
- package/dist/object.d.cts.map +1 -0
- package/dist/object.d.ts +263 -0
- package/dist/object.d.ts.map +1 -0
- package/dist/object.js +212 -0
- package/dist/object.js.map +1 -0
- package/dist/package.json.cjs +9 -0
- package/dist/package.json.cjs.map +1 -0
- package/dist/package.json.js +9 -0
- package/dist/package.json.js.map +1 -0
- package/dist/raw/encoding.cjs +47 -0
- package/dist/raw/encoding.cjs.map +1 -0
- package/dist/raw/encoding.d.cts +46 -0
- package/dist/raw/encoding.d.cts.map +1 -0
- package/dist/raw/encoding.d.ts +46 -0
- package/dist/raw/encoding.d.ts.map +1 -0
- package/dist/raw/encoding.js +47 -0
- package/dist/raw/encoding.js.map +1 -0
- package/dist/raw/index.cjs +600 -0
- package/dist/raw/index.cjs.map +1 -0
- package/dist/raw/index.d.cts +381 -0
- package/dist/raw/index.d.cts.map +1 -0
- package/dist/raw/index.d.ts +381 -0
- package/dist/raw/index.d.ts.map +1 -0
- package/dist/raw/index.js +601 -0
- package/dist/raw/index.js.map +1 -0
- package/dist/s3/index.cjs +23 -0
- package/dist/s3/index.cjs.map +1 -0
- package/dist/s3/index.d.cts +74 -0
- package/dist/s3/index.d.cts.map +1 -0
- package/dist/s3/index.d.ts +74 -0
- package/dist/s3/index.d.ts.map +1 -0
- package/dist/s3/index.js +23 -0
- package/dist/s3/index.js.map +1 -0
- package/dist/simulator/capabilities.cjs +53 -0
- package/dist/simulator/capabilities.cjs.map +1 -0
- package/dist/simulator/capabilities.d.cts +15 -0
- package/dist/simulator/capabilities.d.cts.map +1 -0
- package/dist/simulator/capabilities.d.ts +15 -0
- package/dist/simulator/capabilities.d.ts.map +1 -0
- package/dist/simulator/capabilities.js +53 -0
- package/dist/simulator/capabilities.js.map +1 -0
- package/dist/simulator/index.cjs +1559 -0
- package/dist/simulator/index.cjs.map +1 -0
- package/dist/simulator/index.d.cts +495 -0
- package/dist/simulator/index.d.cts.map +1 -0
- package/dist/simulator/index.d.ts +495 -0
- package/dist/simulator/index.d.ts.map +1 -0
- package/dist/simulator/index.js +1560 -0
- package/dist/simulator/index.js.map +1 -0
- package/dist/simulator/validation.cjs +174 -0
- package/dist/simulator/validation.cjs.map +1 -0
- package/dist/simulator/validation.d.cts +104 -0
- package/dist/simulator/validation.d.cts.map +1 -0
- package/dist/simulator/validation.d.ts +104 -0
- package/dist/simulator/validation.d.ts.map +1 -0
- package/dist/simulator/validation.js +174 -0
- package/dist/simulator/validation.js.map +1 -0
- package/dist/streams/collect.cjs +26 -0
- package/dist/streams/collect.cjs.map +1 -0
- package/dist/streams/collect.d.cts +18 -0
- package/dist/streams/collect.d.cts.map +1 -0
- package/dist/streams/collect.d.ts +18 -0
- package/dist/streams/collect.d.ts.map +1 -0
- package/dist/streams/collect.js +26 -0
- package/dist/streams/collect.js.map +1 -0
- package/dist/streams/hash.cjs +123 -0
- package/dist/streams/hash.cjs.map +1 -0
- package/dist/streams/hash.d.cts +42 -0
- package/dist/streams/hash.d.cts.map +1 -0
- package/dist/streams/hash.d.ts +42 -0
- package/dist/streams/hash.d.ts.map +1 -0
- package/dist/streams/hash.js +101 -0
- package/dist/streams/hash.js.map +1 -0
- package/dist/streams/index.cjs +13 -0
- package/dist/streams/index.cjs.map +1 -0
- package/dist/streams/index.d.cts +7 -0
- package/dist/streams/index.d.cts.map +1 -0
- package/dist/streams/index.d.ts +7 -0
- package/dist/streams/index.d.ts.map +1 -0
- package/dist/streams/index.js +13 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams/progress.cjs +47 -0
- package/dist/streams/progress.cjs.map +1 -0
- package/dist/streams/progress.d.cts +53 -0
- package/dist/streams/progress.d.cts.map +1 -0
- package/dist/streams/progress.d.ts +53 -0
- package/dist/streams/progress.d.ts.map +1 -0
- package/dist/streams/progress.js +47 -0
- package/dist/streams/progress.js.map +1 -0
- package/dist/streams/source.cjs +155 -0
- package/dist/streams/source.cjs.map +1 -0
- package/dist/streams/source.d.cts +140 -0
- package/dist/streams/source.d.cts.map +1 -0
- package/dist/streams/source.d.ts +140 -0
- package/dist/streams/source.d.ts.map +1 -0
- package/dist/streams/source.js +155 -0
- package/dist/streams/source.js.map +1 -0
- package/dist/sync/actions/index.cjs +191 -0
- package/dist/sync/actions/index.cjs.map +1 -0
- package/dist/sync/actions/index.d.cts +167 -0
- package/dist/sync/actions/index.d.cts.map +1 -0
- package/dist/sync/actions/index.d.ts +167 -0
- package/dist/sync/actions/index.d.ts.map +1 -0
- package/dist/sync/actions/index.js +191 -0
- package/dist/sync/actions/index.js.map +1 -0
- package/dist/sync/index.cjs +23 -0
- package/dist/sync/index.cjs.map +1 -0
- package/dist/sync/index.d.cts +21 -0
- package/dist/sync/index.d.cts.map +1 -0
- package/dist/sync/index.d.ts +21 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +23 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/pairing.cjs +31 -0
- package/dist/sync/pairing.cjs.map +1 -0
- package/dist/sync/pairing.d.cts +13 -0
- package/dist/sync/pairing.d.cts.map +1 -0
- package/dist/sync/pairing.d.ts +13 -0
- package/dist/sync/pairing.d.ts.map +1 -0
- package/dist/sync/pairing.js +31 -0
- package/dist/sync/pairing.js.map +1 -0
- package/dist/sync/policies/compare.cjs +14 -0
- package/dist/sync/policies/compare.cjs.map +1 -0
- package/dist/sync/policies/compare.d.cts +13 -0
- package/dist/sync/policies/compare.d.cts.map +1 -0
- package/dist/sync/policies/compare.d.ts +13 -0
- package/dist/sync/policies/compare.d.ts.map +1 -0
- package/dist/sync/policies/compare.js +14 -0
- package/dist/sync/policies/compare.js.map +1 -0
- package/dist/sync/policies/index.cjs +74 -0
- package/dist/sync/policies/index.cjs.map +1 -0
- package/dist/sync/policies/index.d.cts +42 -0
- package/dist/sync/policies/index.d.cts.map +1 -0
- package/dist/sync/policies/index.d.ts +42 -0
- package/dist/sync/policies/index.d.ts.map +1 -0
- package/dist/sync/policies/index.js +74 -0
- package/dist/sync/policies/index.js.map +1 -0
- package/dist/sync/scanners/b2.cjs +57 -0
- package/dist/sync/scanners/b2.cjs.map +1 -0
- package/dist/sync/scanners/b2.d.cts +20 -0
- package/dist/sync/scanners/b2.d.cts.map +1 -0
- package/dist/sync/scanners/b2.d.ts +20 -0
- package/dist/sync/scanners/b2.d.ts.map +1 -0
- package/dist/sync/scanners/b2.js +57 -0
- package/dist/sync/scanners/b2.js.map +1 -0
- package/dist/sync/scanners/local.cjs +58 -0
- package/dist/sync/scanners/local.cjs.map +1 -0
- package/dist/sync/scanners/local.d.cts +24 -0
- package/dist/sync/scanners/local.d.cts.map +1 -0
- package/dist/sync/scanners/local.d.ts +24 -0
- package/dist/sync/scanners/local.d.ts.map +1 -0
- package/dist/sync/scanners/local.js +58 -0
- package/dist/sync/scanners/local.js.map +1 -0
- package/dist/sync/synchronizer.cjs +203 -0
- package/dist/sync/synchronizer.cjs.map +1 -0
- package/dist/sync/synchronizer.d.cts +52 -0
- package/dist/sync/synchronizer.d.cts.map +1 -0
- package/dist/sync/synchronizer.d.ts +52 -0
- package/dist/sync/synchronizer.d.ts.map +1 -0
- package/dist/sync/synchronizer.js +181 -0
- package/dist/sync/synchronizer.js.map +1 -0
- package/dist/sync/types.d.cts +121 -0
- package/dist/sync/types.d.cts.map +1 -0
- package/dist/sync/types.d.ts +121 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/types/auth.cjs +58 -0
- package/dist/types/auth.cjs.map +1 -0
- package/dist/types/auth.d.cts +150 -0
- package/dist/types/auth.d.cts.map +1 -0
- package/dist/types/auth.d.ts +150 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +58 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/bucket.cjs +44 -0
- package/dist/types/bucket.cjs.map +1 -0
- package/dist/types/bucket.d.cts +245 -0
- package/dist/types/bucket.d.cts.map +1 -0
- package/dist/types/bucket.d.ts +245 -0
- package/dist/types/bucket.d.ts.map +1 -0
- package/dist/types/bucket.js +44 -0
- package/dist/types/bucket.js.map +1 -0
- package/dist/types/download.d.cts +110 -0
- package/dist/types/download.d.cts.map +1 -0
- package/dist/types/download.d.ts +110 -0
- package/dist/types/download.d.ts.map +1 -0
- package/dist/types/encryption.cjs +343 -0
- package/dist/types/encryption.cjs.map +1 -0
- package/dist/types/encryption.d.cts +132 -0
- package/dist/types/encryption.d.cts.map +1 -0
- package/dist/types/encryption.d.ts +132 -0
- package/dist/types/encryption.d.ts.map +1 -0
- package/dist/types/encryption.js +321 -0
- package/dist/types/encryption.js.map +1 -0
- package/dist/types/errors.d.cts +16 -0
- package/dist/types/errors.d.cts.map +1 -0
- package/dist/types/errors.d.ts +16 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/file.cjs +23 -0
- package/dist/types/file.cjs.map +1 -0
- package/dist/types/file.d.cts +220 -0
- package/dist/types/file.d.cts.map +1 -0
- package/dist/types/file.d.ts +220 -0
- package/dist/types/file.d.ts.map +1 -0
- package/dist/types/file.js +23 -0
- package/dist/types/file.js.map +1 -0
- package/dist/types/ids.cjs +27 -0
- package/dist/types/ids.cjs.map +1 -0
- package/dist/types/ids.d.cts +84 -0
- package/dist/types/ids.d.cts.map +1 -0
- package/dist/types/ids.d.ts +84 -0
- package/dist/types/ids.d.ts.map +1 -0
- package/dist/types/ids.js +27 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/index.d.cts +25 -0
- package/dist/types/index.d.cts.map +1 -0
- package/dist/types/index.d.ts +25 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/key.d.cts +84 -0
- package/dist/types/key.d.cts.map +1 -0
- package/dist/types/key.d.ts +84 -0
- package/dist/types/key.d.ts.map +1 -0
- package/dist/types/lock.cjs +17 -0
- package/dist/types/lock.cjs.map +1 -0
- package/dist/types/lock.d.cts +92 -0
- package/dist/types/lock.d.cts.map +1 -0
- package/dist/types/lock.d.ts +92 -0
- package/dist/types/lock.d.ts.map +1 -0
- package/dist/types/lock.js +17 -0
- package/dist/types/lock.js.map +1 -0
- package/dist/types/notifications.cjs +24 -0
- package/dist/types/notifications.cjs.map +1 -0
- package/dist/types/notifications.d.cts +97 -0
- package/dist/types/notifications.d.cts.map +1 -0
- package/dist/types/notifications.d.ts +97 -0
- package/dist/types/notifications.d.ts.map +1 -0
- package/dist/types/notifications.js +24 -0
- package/dist/types/notifications.js.map +1 -0
- package/dist/types/replication.d.cts +42 -0
- package/dist/types/replication.d.cts.map +1 -0
- package/dist/types/replication.d.ts +42 -0
- package/dist/types/replication.d.ts.map +1 -0
- package/dist/types/upload.d.cts +219 -0
- package/dist/types/upload.d.cts.map +1 -0
- package/dist/types/upload.d.ts +219 -0
- package/dist/types/upload.d.ts.map +1 -0
- package/dist/upload/cancel.cjs +10 -0
- package/dist/upload/cancel.cjs.map +1 -0
- package/dist/upload/cancel.d.cts +23 -0
- package/dist/upload/cancel.d.cts.map +1 -0
- package/dist/upload/cancel.d.ts +23 -0
- package/dist/upload/cancel.d.ts.map +1 -0
- package/dist/upload/cancel.js +10 -0
- package/dist/upload/cancel.js.map +1 -0
- package/dist/upload/concurrency.cjs +54 -0
- package/dist/upload/concurrency.cjs.map +1 -0
- package/dist/upload/concurrency.d.cts +46 -0
- package/dist/upload/concurrency.d.cts.map +1 -0
- package/dist/upload/concurrency.d.ts +46 -0
- package/dist/upload/concurrency.d.ts.map +1 -0
- package/dist/upload/concurrency.js +54 -0
- package/dist/upload/concurrency.js.map +1 -0
- package/dist/upload/large.cjs +222 -0
- package/dist/upload/large.cjs.map +1 -0
- package/dist/upload/large.d.cts +71 -0
- package/dist/upload/large.d.cts.map +1 -0
- package/dist/upload/large.d.ts +71 -0
- package/dist/upload/large.d.ts.map +1 -0
- package/dist/upload/large.js +222 -0
- package/dist/upload/large.js.map +1 -0
- package/dist/upload/resume.cjs +34 -0
- package/dist/upload/resume.cjs.map +1 -0
- package/dist/upload/resume.d.cts +33 -0
- package/dist/upload/resume.d.cts.map +1 -0
- package/dist/upload/resume.d.ts +33 -0
- package/dist/upload/resume.d.ts.map +1 -0
- package/dist/upload/resume.js +34 -0
- package/dist/upload/resume.js.map +1 -0
- package/dist/upload/single.cjs +47 -0
- package/dist/upload/single.cjs.map +1 -0
- package/dist/upload/single.d.cts +51 -0
- package/dist/upload/single.d.cts.map +1 -0
- package/dist/upload/single.d.ts +51 -0
- package/dist/upload/single.d.ts.map +1 -0
- package/dist/upload/single.js +47 -0
- package/dist/upload/single.js.map +1 -0
- package/dist/upload/stream.cjs +198 -0
- package/dist/upload/stream.cjs.map +1 -0
- package/dist/upload/stream.d.cts +61 -0
- package/dist/upload/stream.d.cts.map +1 -0
- package/dist/upload/stream.d.ts +61 -0
- package/dist/upload/stream.d.ts.map +1 -0
- package/dist/upload/stream.js +198 -0
- package/dist/upload/stream.js.map +1 -0
- package/dist/util/best-effort.cjs +10 -0
- package/dist/util/best-effort.cjs.map +1 -0
- package/dist/util/best-effort.d.cts +31 -0
- package/dist/util/best-effort.d.cts.map +1 -0
- package/dist/util/best-effort.d.ts +31 -0
- package/dist/util/best-effort.d.ts.map +1 -0
- package/dist/util/best-effort.js +10 -0
- package/dist/util/best-effort.js.map +1 -0
- package/dist/util/defaults.cjs +11 -0
- package/dist/util/defaults.cjs.map +1 -0
- package/dist/util/defaults.d.cts +54 -0
- package/dist/util/defaults.d.cts.map +1 -0
- package/dist/util/defaults.d.ts +54 -0
- package/dist/util/defaults.d.ts.map +1 -0
- package/dist/util/defaults.js +11 -0
- package/dist/util/defaults.js.map +1 -0
- package/dist/util/normalize.cjs +16 -0
- package/dist/util/normalize.cjs.map +1 -0
- package/dist/util/normalize.d.cts +62 -0
- package/dist/util/normalize.d.cts.map +1 -0
- package/dist/util/normalize.d.ts +62 -0
- package/dist/util/normalize.d.ts.map +1 -0
- package/dist/util/normalize.js +16 -0
- package/dist/util/normalize.js.map +1 -0
- package/dist/util/paginator.cjs +20 -0
- package/dist/util/paginator.cjs.map +1 -0
- package/dist/util/paginator.d.cts +120 -0
- package/dist/util/paginator.d.cts.map +1 -0
- package/dist/util/paginator.d.ts +120 -0
- package/dist/util/paginator.d.ts.map +1 -0
- package/dist/util/paginator.js +20 -0
- package/dist/util/paginator.js.map +1 -0
- package/dist/util/plan-ranges.cjs +28 -0
- package/dist/util/plan-ranges.cjs.map +1 -0
- package/dist/util/plan-ranges.d.cts +56 -0
- package/dist/util/plan-ranges.d.cts.map +1 -0
- package/dist/util/plan-ranges.d.ts +56 -0
- package/dist/util/plan-ranges.d.ts.map +1 -0
- package/dist/util/plan-ranges.js +28 -0
- package/dist/util/plan-ranges.js.map +1 -0
- package/dist/util/text-codec.cjs +7 -0
- package/dist/util/text-codec.cjs.map +1 -0
- package/dist/util/text-codec.d.cts +26 -0
- package/dist/util/text-codec.d.cts.map +1 -0
- package/dist/util/text-codec.d.ts +26 -0
- package/dist/util/text-codec.d.ts.map +1 -0
- package/dist/util/text-codec.js +7 -0
- package/dist/util/text-codec.js.map +1 -0
- package/dist/util/to-error.cjs +7 -0
- package/dist/util/to-error.cjs.map +1 -0
- package/dist/util/to-error.d.cts +15 -0
- package/dist/util/to-error.d.cts.map +1 -0
- package/dist/util/to-error.d.ts +15 -0
- package/dist/util/to-error.d.ts.map +1 -0
- package/dist/util/to-error.js +7 -0
- package/dist/util/to-error.js.map +1 -0
- package/dist/version.cjs +6 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.d.cts +14 -0
- package/dist/version.d.cts.map +1 -0
- package/dist/version.d.ts +14 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +198 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { EventType } from '../types/notifications.js';
|
|
2
|
+
/**
|
|
3
|
+
* The HTTP header B2 attaches to every event-notification webhook delivery.
|
|
4
|
+
* The value is a versioned HMAC-SHA256 signature of the raw request body:
|
|
5
|
+
* `v1=<lowercase-hex>`.
|
|
6
|
+
*
|
|
7
|
+
* The lowercase form matches Node's `req.headers` normalisation and most
|
|
8
|
+
* server-framework conventions. Producers must compare case-insensitively.
|
|
9
|
+
*/
|
|
10
|
+
export declare const B2_WEBHOOK_SIGNATURE_HEADER = "x-bz-event-notification-signature";
|
|
11
|
+
/**
|
|
12
|
+
* A single event entry inside a B2 webhook payload.
|
|
13
|
+
*
|
|
14
|
+
* The `events` array on the parsed body contains zero or more of these. Most
|
|
15
|
+
* deliveries hold a single event, but B2 may coalesce multiple events from the
|
|
16
|
+
* same bucket into one delivery for efficiency, so callers should iterate.
|
|
17
|
+
*
|
|
18
|
+
* @see https://www.backblaze.com/apidocs/event-notifications-overview
|
|
19
|
+
*/
|
|
20
|
+
export interface WebhookEvent {
|
|
21
|
+
/** Account that owns the bucket the event fired on. */
|
|
22
|
+
readonly accountId: string;
|
|
23
|
+
/** Bucket ID the event fired on. */
|
|
24
|
+
readonly bucketId: string;
|
|
25
|
+
/** Bucket name at the moment the event fired. */
|
|
26
|
+
readonly bucketName: string;
|
|
27
|
+
/** Globally unique event identifier (useful for idempotency on the receiver). */
|
|
28
|
+
readonly eventId: string;
|
|
29
|
+
/** Event time in UNIX milliseconds (UTC). */
|
|
30
|
+
readonly eventTimestamp: number;
|
|
31
|
+
/** Specific event type, e.g. `'b2:ObjectCreated:Upload'`. */
|
|
32
|
+
readonly eventType: EventType;
|
|
33
|
+
/** Schema version of the event payload. Currently `1`. */
|
|
34
|
+
readonly eventVersion: number;
|
|
35
|
+
/** Name of the `EventNotificationRule` on the bucket that matched. */
|
|
36
|
+
readonly matchedRuleName: string;
|
|
37
|
+
/** B2 file name of the affected object. */
|
|
38
|
+
readonly objectName: string;
|
|
39
|
+
/** Affected object's size in bytes, when present (absent for some delete events). */
|
|
40
|
+
readonly objectSize?: number;
|
|
41
|
+
/** Specific file version ID, when applicable. */
|
|
42
|
+
readonly objectVersionId?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The complete JSON body B2 POSTs to a webhook endpoint after signature
|
|
46
|
+
* verification succeeds. See {@link verifyWebhookSignature}.
|
|
47
|
+
*/
|
|
48
|
+
export interface WebhookPayload {
|
|
49
|
+
/** One or more event entries. Always non-empty on real deliveries. */
|
|
50
|
+
readonly events: readonly WebhookEvent[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Options for {@link verifyWebhookSignature} and {@link requireValidWebhook}.
|
|
54
|
+
*/
|
|
55
|
+
export interface VerifyWebhookOptions {
|
|
56
|
+
/**
|
|
57
|
+
* The raw request body B2 sent. MUST be the exact bytes received: any
|
|
58
|
+
* JSON re-serialisation or whitespace normalisation will break the HMAC.
|
|
59
|
+
*
|
|
60
|
+
* Pass a `Uint8Array` whenever the surrounding framework gives you raw
|
|
61
|
+
* bytes (e.g. `req.rawBody` in fastify, `req.arrayBuffer()` in Hono /
|
|
62
|
+
* Workers). The string overload is provided for convenience when a
|
|
63
|
+
* framework already decoded the body as UTF-8.
|
|
64
|
+
*/
|
|
65
|
+
readonly body: string | Uint8Array;
|
|
66
|
+
/**
|
|
67
|
+
* Value of the {@link B2_WEBHOOK_SIGNATURE_HEADER} header.
|
|
68
|
+
*
|
|
69
|
+
* Accepts a single string or an array (Node's `req.headers` returns
|
|
70
|
+
* `string | string[] | undefined`). When an array is supplied, the first
|
|
71
|
+
* non-empty element is used: B2 only ever sends one value, and rejecting
|
|
72
|
+
* the multi-value case prevents callers from accidentally trusting a
|
|
73
|
+
* spoofed second header injected by a buggy reverse proxy.
|
|
74
|
+
*/
|
|
75
|
+
readonly signature: string | readonly string[] | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* The signing secret from `EventNotificationRule.targetConfiguration.hmacSha256SigningSecret`.
|
|
78
|
+
*
|
|
79
|
+
* This is the exact string B2 returned in the `b2_set_bucket_notification_rules`
|
|
80
|
+
* response. Do NOT base64-decode or otherwise transform it.
|
|
81
|
+
*/
|
|
82
|
+
readonly secret: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Outcome of {@link verifyWebhookSignature}.
|
|
86
|
+
*
|
|
87
|
+
* The verifier never throws; instead it returns a discriminated result so
|
|
88
|
+
* callers can branch on `valid` and log `reason` without try/catch noise.
|
|
89
|
+
* Use {@link requireValidWebhook} when an exception-based control flow is
|
|
90
|
+
* more convenient.
|
|
91
|
+
*/
|
|
92
|
+
export interface VerifyWebhookResult {
|
|
93
|
+
/** `true` only when the HMAC matched and the body parsed as a valid payload. */
|
|
94
|
+
readonly valid: boolean;
|
|
95
|
+
/** Parsed payload when {@link valid} is `true`; otherwise `null`. */
|
|
96
|
+
readonly payload: WebhookPayload | null;
|
|
97
|
+
/** Short reason describing why verification failed, or `null` on success. */
|
|
98
|
+
readonly reason: string | null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Verify the HMAC-SHA256 signature B2 attaches to event-notification webhooks
|
|
102
|
+
* and parse the body on success.
|
|
103
|
+
*
|
|
104
|
+
* Never throws: returns a discriminated {@link VerifyWebhookResult}. Use this
|
|
105
|
+
* when you want a single, explicit place to branch on `valid` and log the
|
|
106
|
+
* `reason` on rejection.
|
|
107
|
+
*
|
|
108
|
+
* @param opts - The body, signature header, and signing secret. See {@link VerifyWebhookOptions}.
|
|
109
|
+
*
|
|
110
|
+
* @returns Verification result with optional parsed payload and failure reason.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { verifyWebhookSignature, B2_WEBHOOK_SIGNATURE_HEADER } from '@backblaze-labs/b2-sdk/notifications'
|
|
115
|
+
*
|
|
116
|
+
* app.post('/webhook', async (req, res) => {
|
|
117
|
+
* const raw = await readRawBody(req) // raw bytes, NOT json
|
|
118
|
+
* const result = await verifyWebhookSignature({
|
|
119
|
+
* body: raw,
|
|
120
|
+
* signature: req.headers[B2_WEBHOOK_SIGNATURE_HEADER],
|
|
121
|
+
* secret: process.env.B2_WEBHOOK_SECRET,
|
|
122
|
+
* })
|
|
123
|
+
* if (!result.valid) return res.status(401).send(result.reason)
|
|
124
|
+
* for (const event of result.payload.events) handleEvent(event)
|
|
125
|
+
* res.status(204).end()
|
|
126
|
+
* })
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
*/
|
|
130
|
+
export declare function verifyWebhookSignature(opts: VerifyWebhookOptions): Promise<VerifyWebhookResult>;
|
|
131
|
+
/**
|
|
132
|
+
* Throwing wrapper around {@link verifyWebhookSignature}. Returns the parsed
|
|
133
|
+
* payload on success; throws an `Error` whose message is the verifier's
|
|
134
|
+
* `reason` string on any failure.
|
|
135
|
+
*
|
|
136
|
+
* Useful when you want the verification to integrate with your framework's
|
|
137
|
+
* existing error-handling middleware rather than handling the result inline.
|
|
138
|
+
*
|
|
139
|
+
* @param opts - The body, signature header, and signing secret. See {@link VerifyWebhookOptions}.
|
|
140
|
+
*
|
|
141
|
+
* @returns The parsed webhook payload.
|
|
142
|
+
*
|
|
143
|
+
* @throws When verification fails for any reason.
|
|
144
|
+
*/
|
|
145
|
+
export declare function requireValidWebhook(opts: VerifyWebhookOptions): Promise<WebhookPayload>;
|
|
146
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/notifications/webhook.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAG1D;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,sCAAsC,CAAA;AAK9E;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,iDAAiD;IACjD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IAC1D;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IACvC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AA+JD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAiC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAM7F"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { utf8Decoder, utf8Encoder } from "../util/text-codec.js";
|
|
2
|
+
const B2_WEBHOOK_SIGNATURE_HEADER = "x-bz-event-notification-signature";
|
|
3
|
+
const SIGNATURE_VERSION_PREFIX = "v1=";
|
|
4
|
+
function timingSafeEqual(a, b) {
|
|
5
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
6
|
+
let diff = 0;
|
|
7
|
+
for (let i = 0; i < a.byteLength; i++) {
|
|
8
|
+
diff |= a[i] ^ b[i];
|
|
9
|
+
}
|
|
10
|
+
return diff === 0;
|
|
11
|
+
}
|
|
12
|
+
function hexToBytes(hex) {
|
|
13
|
+
if (hex.length % 2 !== 0) return null;
|
|
14
|
+
const out = new Uint8Array(hex.length / 2);
|
|
15
|
+
for (let i = 0; i < out.byteLength; i++) {
|
|
16
|
+
const byte = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
17
|
+
if (Number.isNaN(byte)) return null;
|
|
18
|
+
out[i] = byte;
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
function pickSignature(raw) {
|
|
23
|
+
if (raw === void 0) return null;
|
|
24
|
+
if (Array.isArray(raw)) {
|
|
25
|
+
for (const v of raw) {
|
|
26
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return typeof raw === "string" && raw.length > 0 ? raw : null;
|
|
31
|
+
}
|
|
32
|
+
function bytes(s) {
|
|
33
|
+
return utf8Encoder.encode(s);
|
|
34
|
+
}
|
|
35
|
+
function bodyBytes(body) {
|
|
36
|
+
return typeof body === "string" ? bytes(body) : body;
|
|
37
|
+
}
|
|
38
|
+
async function hmacSha256(secret, body) {
|
|
39
|
+
const secretBytes = bytes(secret);
|
|
40
|
+
const key = await globalThis.crypto.subtle.importKey(
|
|
41
|
+
"raw",
|
|
42
|
+
secretBytes.buffer.slice(
|
|
43
|
+
secretBytes.byteOffset,
|
|
44
|
+
secretBytes.byteOffset + secretBytes.byteLength
|
|
45
|
+
),
|
|
46
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
47
|
+
false,
|
|
48
|
+
["sign"]
|
|
49
|
+
);
|
|
50
|
+
const sig = await globalThis.crypto.subtle.sign(
|
|
51
|
+
"HMAC",
|
|
52
|
+
key,
|
|
53
|
+
body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength)
|
|
54
|
+
);
|
|
55
|
+
return new Uint8Array(sig);
|
|
56
|
+
}
|
|
57
|
+
function tryParse(raw) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(raw);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function looksLikePayload(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && Array.isArray(value.events);
|
|
66
|
+
}
|
|
67
|
+
async function verifyWebhookSignature(opts) {
|
|
68
|
+
if (typeof opts.secret !== "string" || opts.secret.length === 0) {
|
|
69
|
+
return { valid: false, payload: null, reason: "missing signing secret" };
|
|
70
|
+
}
|
|
71
|
+
const signature = pickSignature(opts.signature);
|
|
72
|
+
if (signature === null) {
|
|
73
|
+
return { valid: false, payload: null, reason: "missing signature header" };
|
|
74
|
+
}
|
|
75
|
+
if (!signature.startsWith(SIGNATURE_VERSION_PREFIX)) {
|
|
76
|
+
return { valid: false, payload: null, reason: "unsupported signature version" };
|
|
77
|
+
}
|
|
78
|
+
const claimed = hexToBytes(signature.slice(SIGNATURE_VERSION_PREFIX.length).toLowerCase());
|
|
79
|
+
if (claimed === null) {
|
|
80
|
+
return { valid: false, payload: null, reason: "bad signature format" };
|
|
81
|
+
}
|
|
82
|
+
const raw = bodyBytes(opts.body);
|
|
83
|
+
const expected = await hmacSha256(opts.secret, raw);
|
|
84
|
+
if (!timingSafeEqual(claimed, expected)) {
|
|
85
|
+
return { valid: false, payload: null, reason: "signature mismatch" };
|
|
86
|
+
}
|
|
87
|
+
const decoded = typeof opts.body === "string" ? opts.body : utf8Decoder.decode(raw);
|
|
88
|
+
const parsed = tryParse(decoded);
|
|
89
|
+
if (!looksLikePayload(parsed)) {
|
|
90
|
+
return { valid: false, payload: null, reason: "invalid payload shape" };
|
|
91
|
+
}
|
|
92
|
+
return { valid: true, payload: parsed, reason: null };
|
|
93
|
+
}
|
|
94
|
+
async function requireValidWebhook(opts) {
|
|
95
|
+
const result = await verifyWebhookSignature(opts);
|
|
96
|
+
if (!result.valid || result.payload === null) {
|
|
97
|
+
throw new Error(`B2 webhook verification failed: ${result.reason ?? "unknown"}`);
|
|
98
|
+
}
|
|
99
|
+
return result.payload;
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
B2_WEBHOOK_SIGNATURE_HEADER,
|
|
103
|
+
requireValidWebhook,
|
|
104
|
+
verifyWebhookSignature
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sources":["../../src/notifications/webhook.ts"],"sourcesContent":["import type { EventType } from '../types/notifications.ts'\nimport { utf8Decoder, utf8Encoder } from '../util/text-codec.ts'\n\n/**\n * The HTTP header B2 attaches to every event-notification webhook delivery.\n * The value is a versioned HMAC-SHA256 signature of the raw request body:\n * `v1=<lowercase-hex>`.\n *\n * The lowercase form matches Node's `req.headers` normalisation and most\n * server-framework conventions. Producers must compare case-insensitively.\n */\nexport const B2_WEBHOOK_SIGNATURE_HEADER = 'x-bz-event-notification-signature'\n\n/** Current B2 event-notification signature scheme prefix. */\nconst SIGNATURE_VERSION_PREFIX = 'v1='\n\n/**\n * A single event entry inside a B2 webhook payload.\n *\n * The `events` array on the parsed body contains zero or more of these. Most\n * deliveries hold a single event, but B2 may coalesce multiple events from the\n * same bucket into one delivery for efficiency, so callers should iterate.\n *\n * @see https://www.backblaze.com/apidocs/event-notifications-overview\n */\nexport interface WebhookEvent {\n /** Account that owns the bucket the event fired on. */\n readonly accountId: string\n /** Bucket ID the event fired on. */\n readonly bucketId: string\n /** Bucket name at the moment the event fired. */\n readonly bucketName: string\n /** Globally unique event identifier (useful for idempotency on the receiver). */\n readonly eventId: string\n /** Event time in UNIX milliseconds (UTC). */\n readonly eventTimestamp: number\n /** Specific event type, e.g. `'b2:ObjectCreated:Upload'`. */\n readonly eventType: EventType\n /** Schema version of the event payload. Currently `1`. */\n readonly eventVersion: number\n /** Name of the `EventNotificationRule` on the bucket that matched. */\n readonly matchedRuleName: string\n /** B2 file name of the affected object. */\n readonly objectName: string\n /** Affected object's size in bytes, when present (absent for some delete events). */\n readonly objectSize?: number\n /** Specific file version ID, when applicable. */\n readonly objectVersionId?: string\n}\n\n/**\n * The complete JSON body B2 POSTs to a webhook endpoint after signature\n * verification succeeds. See {@link verifyWebhookSignature}.\n */\nexport interface WebhookPayload {\n /** One or more event entries. Always non-empty on real deliveries. */\n readonly events: readonly WebhookEvent[]\n}\n\n/**\n * Options for {@link verifyWebhookSignature} and {@link requireValidWebhook}.\n */\nexport interface VerifyWebhookOptions {\n /**\n * The raw request body B2 sent. MUST be the exact bytes received: any\n * JSON re-serialisation or whitespace normalisation will break the HMAC.\n *\n * Pass a `Uint8Array` whenever the surrounding framework gives you raw\n * bytes (e.g. `req.rawBody` in fastify, `req.arrayBuffer()` in Hono /\n * Workers). The string overload is provided for convenience when a\n * framework already decoded the body as UTF-8.\n */\n readonly body: string | Uint8Array\n /**\n * Value of the {@link B2_WEBHOOK_SIGNATURE_HEADER} header.\n *\n * Accepts a single string or an array (Node's `req.headers` returns\n * `string | string[] | undefined`). When an array is supplied, the first\n * non-empty element is used: B2 only ever sends one value, and rejecting\n * the multi-value case prevents callers from accidentally trusting a\n * spoofed second header injected by a buggy reverse proxy.\n */\n readonly signature: string | readonly string[] | undefined\n /**\n * The signing secret from `EventNotificationRule.targetConfiguration.hmacSha256SigningSecret`.\n *\n * This is the exact string B2 returned in the `b2_set_bucket_notification_rules`\n * response. Do NOT base64-decode or otherwise transform it.\n */\n readonly secret: string\n}\n\n/**\n * Outcome of {@link verifyWebhookSignature}.\n *\n * The verifier never throws; instead it returns a discriminated result so\n * callers can branch on `valid` and log `reason` without try/catch noise.\n * Use {@link requireValidWebhook} when an exception-based control flow is\n * more convenient.\n */\nexport interface VerifyWebhookResult {\n /** `true` only when the HMAC matched and the body parsed as a valid payload. */\n readonly valid: boolean\n /** Parsed payload when {@link valid} is `true`; otherwise `null`. */\n readonly payload: WebhookPayload | null\n /** Short reason describing why verification failed, or `null` on success. */\n readonly reason: string | null\n}\n\n/**\n * Constant-time comparison of two equal-length byte sequences.\n *\n * Web Crypto exposes no native timing-safe compare, so we do the standard\n * XOR-and-OR pattern ourselves. The early-out on length mismatch is fine\n * here because the signature length is publicly fixed (32 bytes for\n * HMAC-SHA256), so a length-mismatch branch leaks nothing about the secret.\n *\n * @param a - First byte sequence.\n * @param b - Second byte sequence.\n *\n * @returns `true` if the byte sequences are byte-for-byte equal.\n */\nfunction timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false\n let diff = 0\n for (let i = 0; i < a.byteLength; i++) {\n // Non-null asserted: `a` and `b` have the same length and `i` is in range.\n diff |= (a[i] as number) ^ (b[i] as number)\n }\n return diff === 0\n}\n\n/**\n * Decode a lowercase hex string into bytes. Returns `null` on any malformed\n * input (odd length, non-hex characters). We don't surface a thrown error\n * because all malformed signatures should land in the same\n * `reason: 'bad signature format'` bucket on the verifier's caller,\n * regardless of which specific malformation triggered it.\n *\n * @param hex - The lowercase hex string to decode.\n *\n * @returns The decoded bytes, or `null` if the input was not valid hex.\n */\nfunction hexToBytes(hex: string): Uint8Array | null {\n if (hex.length % 2 !== 0) return null\n const out = new Uint8Array(hex.length / 2)\n for (let i = 0; i < out.byteLength; i++) {\n const byte = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16)\n if (Number.isNaN(byte)) return null\n out[i] = byte\n }\n return out\n}\n\n/**\n * Pick the single signature string from {@link VerifyWebhookOptions.signature}.\n * Returns `null` if absent, empty, or supplied as an empty array.\n *\n * @param raw - The signature value as supplied by the caller.\n *\n * @returns The chosen signature string, or `null` if no candidate was usable.\n */\nfunction pickSignature(raw: VerifyWebhookOptions['signature']): string | null {\n if (raw === undefined) return null\n if (Array.isArray(raw)) {\n for (const v of raw) {\n if (typeof v === 'string' && v.length > 0) return v\n }\n return null\n }\n return typeof raw === 'string' && raw.length > 0 ? raw : null\n}\n\n/**\n * Encode a UTF-8 string into bytes using a shared encoder.\n *\n * @param s - The string to encode.\n *\n * @returns The UTF-8 encoded bytes.\n */\nfunction bytes(s: string): Uint8Array {\n return utf8Encoder.encode(s)\n}\n\n/**\n * Normalise the body parameter to a `Uint8Array` view of its raw bytes.\n *\n * Strings are UTF-8 encoded. `Uint8Array` inputs pass through untouched.\n *\n * @param body - The raw request body as supplied by the caller.\n *\n * @returns The body as a byte sequence ready for HMAC computation.\n */\nfunction bodyBytes(body: string | Uint8Array): Uint8Array {\n return typeof body === 'string' ? bytes(body) : body\n}\n\n/**\n * Compute the HMAC-SHA256 of `body` under `secret` using the isomorphic Web\n * Crypto API. Works in Node 22+, browsers, Bun, Deno, and Cloudflare Workers\n * without any platform-specific code.\n *\n * @param secret - The HMAC signing secret.\n * @param body - The bytes to sign.\n *\n * @returns The 32-byte HMAC-SHA256 digest.\n */\nasync function hmacSha256(secret: string, body: Uint8Array): Promise<Uint8Array> {\n // The explicit `slice(byteOffset, byteOffset + byteLength)` defends against\n // a Uint8Array view that points at a subset of a larger buffer. Casting to\n // `ArrayBuffer` is needed because TS 5.7+ types Uint8Array's buffer as\n // `ArrayBufferLike`, which includes `SharedArrayBuffer`. Web Crypto's\n // signatures only accept the plain `ArrayBuffer` variant.\n const secretBytes = bytes(secret)\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n secretBytes.buffer.slice(\n secretBytes.byteOffset,\n secretBytes.byteOffset + secretBytes.byteLength,\n ) as ArrayBuffer,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n const sig = await globalThis.crypto.subtle.sign(\n 'HMAC',\n key,\n body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength) as ArrayBuffer,\n )\n return new Uint8Array(sig)\n}\n\n/**\n * Best-effort JSON parse that returns `null` on failure. We accept partial\n * structural mismatches (no `events` array etc.) at the caller's discretion.\n *\n * @param raw - The decoded request body string.\n *\n * @returns The parsed payload, or `null` if `raw` is not valid JSON.\n */\nfunction tryParse(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown\n } catch {\n return null\n }\n}\n\n/**\n * Narrow `value` to {@link WebhookPayload}. Currently only checks that\n * `events` is an array; per-event validation is the caller's responsibility\n * since B2 may add new optional fields and we don't want to reject deliveries\n * that include them.\n *\n * @param value - The parsed JSON value to validate.\n *\n * @returns `true` if the value matches the {@link WebhookPayload} shape.\n */\nfunction looksLikePayload(value: unknown): value is WebhookPayload {\n return (\n typeof value === 'object' &&\n value !== null &&\n Array.isArray((value as { events?: unknown }).events)\n )\n}\n\n/**\n * Verify the HMAC-SHA256 signature B2 attaches to event-notification webhooks\n * and parse the body on success.\n *\n * Never throws: returns a discriminated {@link VerifyWebhookResult}. Use this\n * when you want a single, explicit place to branch on `valid` and log the\n * `reason` on rejection.\n *\n * @param opts - The body, signature header, and signing secret. See {@link VerifyWebhookOptions}.\n *\n * @returns Verification result with optional parsed payload and failure reason.\n *\n * @example\n * ```ts\n * import { verifyWebhookSignature, B2_WEBHOOK_SIGNATURE_HEADER } from '@backblaze-labs/b2-sdk/notifications'\n *\n * app.post('/webhook', async (req, res) => {\n * const raw = await readRawBody(req) // raw bytes, NOT json\n * const result = await verifyWebhookSignature({\n * body: raw,\n * signature: req.headers[B2_WEBHOOK_SIGNATURE_HEADER],\n * secret: process.env.B2_WEBHOOK_SECRET,\n * })\n * if (!result.valid) return res.status(401).send(result.reason)\n * for (const event of result.payload.events) handleEvent(event)\n * res.status(204).end()\n * })\n * ```\n *\n */\nexport async function verifyWebhookSignature(\n opts: VerifyWebhookOptions,\n): Promise<VerifyWebhookResult> {\n if (typeof opts.secret !== 'string' || opts.secret.length === 0) {\n return { valid: false, payload: null, reason: 'missing signing secret' }\n }\n\n const signature = pickSignature(opts.signature)\n if (signature === null) {\n return { valid: false, payload: null, reason: 'missing signature header' }\n }\n\n if (!signature.startsWith(SIGNATURE_VERSION_PREFIX)) {\n return { valid: false, payload: null, reason: 'unsupported signature version' }\n }\n\n const claimed = hexToBytes(signature.slice(SIGNATURE_VERSION_PREFIX.length).toLowerCase())\n if (claimed === null) {\n return { valid: false, payload: null, reason: 'bad signature format' }\n }\n\n const raw = bodyBytes(opts.body)\n const expected = await hmacSha256(opts.secret, raw)\n\n if (!timingSafeEqual(claimed, expected)) {\n return { valid: false, payload: null, reason: 'signature mismatch' }\n }\n\n const decoded = typeof opts.body === 'string' ? opts.body : utf8Decoder.decode(raw)\n const parsed = tryParse(decoded)\n if (!looksLikePayload(parsed)) {\n return { valid: false, payload: null, reason: 'invalid payload shape' }\n }\n\n return { valid: true, payload: parsed, reason: null }\n}\n\n/**\n * Throwing wrapper around {@link verifyWebhookSignature}. Returns the parsed\n * payload on success; throws an `Error` whose message is the verifier's\n * `reason` string on any failure.\n *\n * Useful when you want the verification to integrate with your framework's\n * existing error-handling middleware rather than handling the result inline.\n *\n * @param opts - The body, signature header, and signing secret. See {@link VerifyWebhookOptions}.\n *\n * @returns The parsed webhook payload.\n *\n * @throws When verification fails for any reason.\n */\nexport async function requireValidWebhook(opts: VerifyWebhookOptions): Promise<WebhookPayload> {\n const result = await verifyWebhookSignature(opts)\n if (!result.valid || result.payload === null) {\n throw new Error(`B2 webhook verification failed: ${result.reason ?? 'unknown'}`)\n }\n return result.payload\n}\n"],"names":[],"mappings":"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"}
|
package/dist/object.cjs
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const parallel = require("./download/parallel.cjs");
|
|
4
|
+
const single$1 = require("./download/single.cjs");
|
|
5
|
+
const large = require("./upload/large.cjs");
|
|
6
|
+
const single = require("./upload/single.cjs");
|
|
7
|
+
const stream = require("./upload/stream.cjs");
|
|
8
|
+
class B2Object {
|
|
9
|
+
/** The file name (path) within the bucket. */
|
|
10
|
+
fileName;
|
|
11
|
+
client;
|
|
12
|
+
bucket;
|
|
13
|
+
/**
|
|
14
|
+
* @param client - The parent B2Client instance.
|
|
15
|
+
* @param bucket - The parent Bucket this object belongs to.
|
|
16
|
+
* @param fileName - The file path within the bucket.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
constructor(client, bucket, fileName) {
|
|
21
|
+
this.client = client;
|
|
22
|
+
this.bucket = bucket;
|
|
23
|
+
this.fileName = fileName;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Uploads data to this file name. Automatically uses multipart upload for large files.
|
|
27
|
+
* @param options - Upload configuration including data source and optional settings.
|
|
28
|
+
*
|
|
29
|
+
* @returns Metadata for the uploaded file version.
|
|
30
|
+
*/
|
|
31
|
+
async upload(options) {
|
|
32
|
+
const recommendedPartSize = this.client.accountInfo.getRecommendedPartSize();
|
|
33
|
+
const isLarge = options.source.size > recommendedPartSize;
|
|
34
|
+
if (isLarge) {
|
|
35
|
+
return large.uploadLargeFile(this.client.raw, this.client.accountInfo, {
|
|
36
|
+
bucketId: this.bucket.id,
|
|
37
|
+
fileName: this.fileName,
|
|
38
|
+
...options
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const { resume: _resume, resumeFileId: _resumeFileId, ...smallOptions } = options;
|
|
42
|
+
return single.uploadSmallFile(this.client.raw, this.client.accountInfo, {
|
|
43
|
+
bucketId: this.bucket.id,
|
|
44
|
+
fileName: this.fileName,
|
|
45
|
+
...smallOptions
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Downloads this file by name. Pass `method: 'HEAD'` to fetch only the
|
|
50
|
+
* response headers (file metadata) without streaming the body.
|
|
51
|
+
* @param options - Optional method, range, SSE-C decryption, response-header overrides, and abort signal.
|
|
52
|
+
*
|
|
53
|
+
* @returns The download result with response headers and body stream.
|
|
54
|
+
*/
|
|
55
|
+
async download(options) {
|
|
56
|
+
return single$1.downloadByName(this.client.raw, this.client.accountInfo, {
|
|
57
|
+
bucketName: this.bucket.name,
|
|
58
|
+
fileName: this.fileName,
|
|
59
|
+
...options
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fetches response headers for this file via HTTP HEAD. Returns a
|
|
64
|
+
* body-less result so callers never have to drain the (logically
|
|
65
|
+
* empty) HEAD body themselves.
|
|
66
|
+
*
|
|
67
|
+
* @param options - Optional range, SSE-C decryption, response-header
|
|
68
|
+
* overrides, and abort signal. Same shape as {@link B2Object.download}'s
|
|
69
|
+
* options minus `method` (always HEAD) and `onProgress` (no body).
|
|
70
|
+
*
|
|
71
|
+
* @returns Parsed download headers (content type, SHA-1, file info, etc.).
|
|
72
|
+
*/
|
|
73
|
+
async head(options) {
|
|
74
|
+
return single$1.headByName(this.client.raw, this.client.accountInfo, {
|
|
75
|
+
bucketName: this.bucket.name,
|
|
76
|
+
fileName: this.fileName,
|
|
77
|
+
...options
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Downloads a specific version of this file by ID. Pass `method: 'HEAD'`
|
|
82
|
+
* to fetch only the response headers (file metadata) without streaming the body.
|
|
83
|
+
* @param fileId - The file version ID to download.
|
|
84
|
+
* @param options - Optional method, range, SSE-C decryption, response-header overrides, and abort signal.
|
|
85
|
+
*
|
|
86
|
+
* @returns The download result with response headers and body stream.
|
|
87
|
+
*/
|
|
88
|
+
async downloadById(fileId, options) {
|
|
89
|
+
return single$1.downloadById(this.client.raw, this.client.accountInfo, {
|
|
90
|
+
fileId,
|
|
91
|
+
...options
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Fetches response headers for a specific version of this file by ID
|
|
96
|
+
* via HTTP HEAD. Returns a body-less result so callers never have to
|
|
97
|
+
* drain the (logically empty) HEAD body themselves.
|
|
98
|
+
*
|
|
99
|
+
* @param fileId - The file version ID to inspect.
|
|
100
|
+
* @param options - Optional range, SSE-C decryption, response-header
|
|
101
|
+
* overrides, and abort signal.
|
|
102
|
+
*
|
|
103
|
+
* @returns Parsed download headers.
|
|
104
|
+
*/
|
|
105
|
+
async headById(fileId, options) {
|
|
106
|
+
return single$1.headById(this.client.raw, this.client.accountInfo, {
|
|
107
|
+
fileId,
|
|
108
|
+
...options
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Creates a parallel-download ReadableStream that fetches the file in concurrent ranged chunks.
|
|
113
|
+
* @param fileId - The file version ID to download.
|
|
114
|
+
* @param totalSize - Total file size in bytes (needed to compute range boundaries).
|
|
115
|
+
* @param options - Concurrency, range size, and abort signal.
|
|
116
|
+
*
|
|
117
|
+
* @returns A Web ReadableStream of file data in sequential order.
|
|
118
|
+
*/
|
|
119
|
+
createReadStream(fileId, totalSize, options) {
|
|
120
|
+
return parallel.createParallelDownloadStream(this.client.raw, this.client.accountInfo, {
|
|
121
|
+
fileId,
|
|
122
|
+
totalSize,
|
|
123
|
+
...options
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Creates a Web `WritableStream` that uploads streamed data into this file
|
|
128
|
+
* using the multipart protocol. Pipe a `ReadableStream<Uint8Array>` into the
|
|
129
|
+
* returned `writable` and await `done` to get the final {@link FileVersion}.
|
|
130
|
+
*
|
|
131
|
+
* Note: streaming uploads do not support resume because the size and per-part
|
|
132
|
+
* hashes are not known in advance. Use {@link upload} with a buffered source
|
|
133
|
+
* when resume is required.
|
|
134
|
+
*
|
|
135
|
+
* @param options - Streaming upload parameters (part size, concurrency, encryption).
|
|
136
|
+
*
|
|
137
|
+
* @returns A handle with the writable sink and a completion promise.
|
|
138
|
+
*/
|
|
139
|
+
createWriteStream(options) {
|
|
140
|
+
return stream.createWriteStream(this.client.raw, this.client.accountInfo, {
|
|
141
|
+
bucketId: this.bucket.id,
|
|
142
|
+
fileName: this.fileName,
|
|
143
|
+
...options ?? {}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Retrieves metadata for a specific file version.
|
|
148
|
+
* @param fileId - The file version ID to look up.
|
|
149
|
+
*
|
|
150
|
+
* @returns The file version metadata.
|
|
151
|
+
*/
|
|
152
|
+
async getFileInfo(fileId) {
|
|
153
|
+
return this.client.raw.getFileInfo(
|
|
154
|
+
this.client.accountInfo.getApiUrl(),
|
|
155
|
+
this.client.accountInfo.getAuthToken(),
|
|
156
|
+
{ fileId }
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Hides this file by creating a hide marker at this file name.
|
|
161
|
+
*
|
|
162
|
+
* @returns Metadata for the newly created hide marker.
|
|
163
|
+
*/
|
|
164
|
+
async hide() {
|
|
165
|
+
return this.bucket.hideFile(this.fileName);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Permanently deletes a specific version of this file.
|
|
169
|
+
* @param fileId - The unique identifier of the file version to delete.
|
|
170
|
+
*/
|
|
171
|
+
async deleteVersion(fileId) {
|
|
172
|
+
await this.bucket.deleteFileVersion(this.fileName, fileId);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Sets or updates the Object Lock retention policy on a specific file
|
|
176
|
+
* version of this file.
|
|
177
|
+
*
|
|
178
|
+
* The bucket must have Object Lock enabled (`fileLockEnabled: true` at
|
|
179
|
+
* creation time). Governance-mode retention can be shortened or removed
|
|
180
|
+
* by passing `bypassGovernance: true` together with an application key
|
|
181
|
+
* that carries the `bypassGovernance` capability; compliance-mode
|
|
182
|
+
* retention cannot be shortened by anyone until the
|
|
183
|
+
* `retainUntilTimestamp` elapses.
|
|
184
|
+
*
|
|
185
|
+
* @param fileId - The file version to apply the policy to.
|
|
186
|
+
* @param retention - The retention policy to apply.
|
|
187
|
+
* @param options - Optional flag for shortening governance-mode retention.
|
|
188
|
+
*
|
|
189
|
+
* @returns Metadata for the updated file version.
|
|
190
|
+
*/
|
|
191
|
+
async setRetention(fileId, retention, options) {
|
|
192
|
+
return this.bucket.updateFileRetention(this.fileName, fileId, retention, options);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Toggles the legal hold flag on a specific file version of this file.
|
|
196
|
+
*
|
|
197
|
+
* Legal hold is independent of retention: a file can be on legal hold
|
|
198
|
+
* without any retention policy, and vice versa. The bucket must have
|
|
199
|
+
* Object Lock enabled, and any caller must hold the `writeFileLegalHolds`
|
|
200
|
+
* capability.
|
|
201
|
+
*
|
|
202
|
+
* @param fileId - The file version to apply the flag to.
|
|
203
|
+
* @param legalHold - `'on'` to apply the hold, `'off'` to remove it.
|
|
204
|
+
*
|
|
205
|
+
* @returns Metadata for the updated file version.
|
|
206
|
+
*/
|
|
207
|
+
async setLegalHold(fileId, legalHold) {
|
|
208
|
+
return this.bucket.updateFileLegalHold(this.fileName, fileId, legalHold);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.B2Object = B2Object;
|
|
212
|
+
//# sourceMappingURL=object.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.cjs","sources":["../src/object.ts"],"sourcesContent":["import type { Bucket } from './bucket.ts'\nimport type { B2Client } from './client.ts'\nimport { createParallelDownloadStream } from './download/parallel.ts'\nimport { type DownloadResult, downloadByName } from './download/single.ts'\nimport { type HeadResult, downloadById, headById, headByName } from './download/single.ts'\nimport type { SseCDownloadKey } from './raw/index.ts'\nimport type { ProgressListener } from './streams/progress.ts'\nimport type { ContentSource } from './streams/source.ts'\nimport type { EncryptionSetting } from './types/encryption.ts'\nimport type { FileVersion } from './types/file.ts'\nimport type { FileId, LargeFileId } from './types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from './types/lock.ts'\nimport { uploadLargeFile } from './upload/large.ts'\nimport { uploadSmallFile } from './upload/single.ts'\nimport { type UploadWriteHandle, createWriteStream } from './upload/stream.ts'\n\n/** Options accepted by {@link B2Object.download} and {@link B2Object.downloadById}. */\nexport interface DownloadCallOptions {\n /**\n * HTTP method. Defaults to `'GET'`. Use `'HEAD'` to fetch only\n * response headers. Prefer the dedicated {@link B2Object.head} /\n * {@link Bucket.head} method over this option — those return a\n * body-less result so callers never have to remember to drain the\n * empty body of a HEAD response.\n */\n readonly method?: 'GET' | 'HEAD'\n /** HTTP Range header value (e.g., `\"bytes=0-999\"`). */\n readonly range?: string\n /** SSE-C decryption parameters, required if the file was uploaded with SSE-C. */\n readonly serverSideEncryption?: SseCDownloadKey\n /** Override the response `Content-Disposition` header. */\n readonly b2ContentDisposition?: string\n /** Override the response `Content-Language` header. */\n readonly b2ContentLanguage?: string\n /** Override the response `Content-Encoding` header. */\n readonly b2ContentEncoding?: string\n /** Override the response `Content-Type` header. */\n readonly b2ContentType?: string\n /** Override the response `Cache-Control` header. */\n readonly b2CacheControl?: string\n /** Override the response `Expires` header. */\n readonly b2Expires?: string\n /** Abort signal for cancelling the download. */\n readonly signal?: AbortSignal\n /**\n * Callback invoked as the response body is consumed.\n *\n * Progress is byte-driven, not request-driven: the callback fires per\n * chunk as the caller reads the returned `body` stream, and the final\n * `partsCompleted: 1` event only fires once the stream is read to\n * completion. Downloads that are dropped or aborted partway through\n * will NOT emit a `completePart()` event.\n */\n readonly onProgress?: ProgressListener\n}\n\n/**\n * Options accepted by {@link B2Object.head} / {@link Bucket.head}.\n * Same shape as {@link DownloadCallOptions} minus `method` (always\n * HEAD) and `onProgress` (no body to track).\n */\nexport type HeadCallOptions = Omit<DownloadCallOptions, 'method' | 'onProgress'>\n\n/**\n * Handle to a specific file (by name) within a B2 bucket.\n *\n * Provides file-scoped upload, download, and management operations.\n * Obtained via {@link Bucket.file}.\n *\n * @example\n * ```ts\n * const obj = bucket.file('photos/2026/sunset.jpg')\n * await obj.upload({ source: new BufferSource(data) })\n * const result = await obj.download()\n * ```\n */\nexport class B2Object {\n /** The file name (path) within the bucket. */\n readonly fileName: string\n private readonly client: B2Client\n private readonly bucket: Bucket\n\n /**\n * @param client - The parent B2Client instance.\n * @param bucket - The parent Bucket this object belongs to.\n * @param fileName - The file path within the bucket.\n *\n * @internal\n */\n constructor(client: B2Client, bucket: Bucket, fileName: string) {\n this.client = client\n this.bucket = bucket\n this.fileName = fileName\n }\n\n /**\n * Uploads data to this file name. Automatically uses multipart upload for large files.\n * @param options - Upload configuration including data source and optional settings.\n *\n * @returns Metadata for the uploaded file version.\n */\n async upload(options: {\n /** Data source to upload. */\n source: ContentSource\n /** MIME type. Defaults to auto-detection by B2. */\n contentType?: string\n /** Custom key-value metadata stored with the file. */\n fileInfo?: Record<string, string>\n /** Server-side encryption settings. */\n serverSideEncryption?: EncryptionSetting\n /** File retention policy (requires file lock). */\n fileRetention?: FileRetentionValue\n /** Legal hold status. */\n legalHold?: LegalHoldValue\n /** Last-modified timestamp in milliseconds since epoch. */\n lastModifiedMillis?: number\n /** Part size override for multipart uploads, in bytes. */\n partSize?: number\n /** Number of concurrent part uploads for large files. */\n concurrency?: number\n /** Callback invoked with upload progress events. */\n onProgress?: ProgressListener\n /** Abort signal for cancelling the upload. */\n signal?: AbortSignal\n /**\n * Resume an unfinished multipart upload for this file name when one\n * exists. Only meaningful on the large-file path. Ignored on the\n * small-file path.\n */\n resume?: boolean\n /**\n * Resume into a specific large-file ID, bypassing discovery.\n * Overrides the `resume` discovery path.\n */\n resumeFileId?: LargeFileId\n }): Promise<FileVersion> {\n const recommendedPartSize = this.client.accountInfo.getRecommendedPartSize()\n const isLarge = options.source.size > recommendedPartSize\n\n if (isLarge) {\n return uploadLargeFile(this.client.raw, this.client.accountInfo, {\n bucketId: this.bucket.id,\n fileName: this.fileName,\n ...options,\n })\n }\n\n // Small-file path doesn't accept resume options.\n const { resume: _resume, resumeFileId: _resumeFileId, ...smallOptions } = options\n return uploadSmallFile(this.client.raw, this.client.accountInfo, {\n bucketId: this.bucket.id,\n fileName: this.fileName,\n ...smallOptions,\n })\n }\n\n /**\n * Downloads this file by name. Pass `method: 'HEAD'` to fetch only the\n * response headers (file metadata) without streaming the body.\n * @param options - Optional method, range, SSE-C decryption, response-header overrides, and abort signal.\n *\n * @returns The download result with response headers and body stream.\n */\n async download(options?: DownloadCallOptions): Promise<DownloadResult> {\n return downloadByName(this.client.raw, this.client.accountInfo, {\n bucketName: this.bucket.name,\n fileName: this.fileName,\n ...options,\n })\n }\n\n /**\n * Fetches response headers for this file via HTTP HEAD. Returns a\n * body-less result so callers never have to drain the (logically\n * empty) HEAD body themselves.\n *\n * @param options - Optional range, SSE-C decryption, response-header\n * overrides, and abort signal. Same shape as {@link B2Object.download}'s\n * options minus `method` (always HEAD) and `onProgress` (no body).\n *\n * @returns Parsed download headers (content type, SHA-1, file info, etc.).\n */\n async head(options?: HeadCallOptions): Promise<HeadResult> {\n return headByName(this.client.raw, this.client.accountInfo, {\n bucketName: this.bucket.name,\n fileName: this.fileName,\n ...options,\n })\n }\n\n /**\n * Downloads a specific version of this file by ID. Pass `method: 'HEAD'`\n * to fetch only the response headers (file metadata) without streaming the body.\n * @param fileId - The file version ID to download.\n * @param options - Optional method, range, SSE-C decryption, response-header overrides, and abort signal.\n *\n * @returns The download result with response headers and body stream.\n */\n async downloadById(fileId: FileId, options?: DownloadCallOptions): Promise<DownloadResult> {\n return downloadById(this.client.raw, this.client.accountInfo, {\n fileId,\n ...options,\n })\n }\n\n /**\n * Fetches response headers for a specific version of this file by ID\n * via HTTP HEAD. Returns a body-less result so callers never have to\n * drain the (logically empty) HEAD body themselves.\n *\n * @param fileId - The file version ID to inspect.\n * @param options - Optional range, SSE-C decryption, response-header\n * overrides, and abort signal.\n *\n * @returns Parsed download headers.\n */\n async headById(fileId: FileId, options?: HeadCallOptions): Promise<HeadResult> {\n return headById(this.client.raw, this.client.accountInfo, {\n fileId,\n ...options,\n })\n }\n\n /**\n * Creates a parallel-download ReadableStream that fetches the file in concurrent ranged chunks.\n * @param fileId - The file version ID to download.\n * @param totalSize - Total file size in bytes (needed to compute range boundaries).\n * @param options - Concurrency, range size, and abort signal.\n *\n * @returns A Web ReadableStream of file data in sequential order.\n */\n createReadStream(\n fileId: FileId,\n totalSize: number,\n options?: {\n /** Size of each ranged GET request in bytes. Defaults to 8 MB. */\n rangeSize?: number\n /** Number of concurrent range requests. Defaults to 4. */\n concurrency?: number\n /** Abort signal for cancelling the download. */\n signal?: AbortSignal\n },\n ): ReadableStream<Uint8Array> {\n return createParallelDownloadStream(this.client.raw, this.client.accountInfo, {\n fileId,\n totalSize,\n ...options,\n })\n }\n\n /**\n * Creates a Web `WritableStream` that uploads streamed data into this file\n * using the multipart protocol. Pipe a `ReadableStream<Uint8Array>` into the\n * returned `writable` and await `done` to get the final {@link FileVersion}.\n *\n * Note: streaming uploads do not support resume because the size and per-part\n * hashes are not known in advance. Use {@link upload} with a buffered source\n * when resume is required.\n *\n * @param options - Streaming upload parameters (part size, concurrency, encryption).\n *\n * @returns A handle with the writable sink and a completion promise.\n */\n createWriteStream(options?: {\n /** MIME type. Defaults to `b2/x-auto`. */\n contentType?: string\n /** Custom key-value metadata stored with the file. */\n fileInfo?: Record<string, string>\n /** Server-side encryption applied to each part. */\n serverSideEncryption?: EncryptionSetting\n /** Target part size in bytes. Defaults to the account's recommended part size. */\n partSize?: number\n /** Maximum number of parts uploaded in parallel. Defaults to 4. */\n concurrency?: number\n /** Callback invoked with upload progress events. */\n onProgress?: ProgressListener\n /** Abort signal that cancels the upload and the unfinished large file. */\n signal?: AbortSignal\n }): UploadWriteHandle {\n return createWriteStream(this.client.raw, this.client.accountInfo, {\n bucketId: this.bucket.id,\n fileName: this.fileName,\n ...(options ?? {}),\n })\n }\n\n /**\n * Retrieves metadata for a specific file version.\n * @param fileId - The file version ID to look up.\n *\n * @returns The file version metadata.\n */\n async getFileInfo(fileId: FileId): Promise<FileVersion> {\n return this.client.raw.getFileInfo(\n this.client.accountInfo.getApiUrl(),\n this.client.accountInfo.getAuthToken(),\n { fileId },\n )\n }\n\n /**\n * Hides this file by creating a hide marker at this file name.\n *\n * @returns Metadata for the newly created hide marker.\n */\n async hide(): Promise<FileVersion> {\n return this.bucket.hideFile(this.fileName)\n }\n\n /**\n * Permanently deletes a specific version of this file.\n * @param fileId - The unique identifier of the file version to delete.\n */\n async deleteVersion(fileId: FileId): Promise<void> {\n await this.bucket.deleteFileVersion(this.fileName, fileId)\n }\n\n /**\n * Sets or updates the Object Lock retention policy on a specific file\n * version of this file.\n *\n * The bucket must have Object Lock enabled (`fileLockEnabled: true` at\n * creation time). Governance-mode retention can be shortened or removed\n * by passing `bypassGovernance: true` together with an application key\n * that carries the `bypassGovernance` capability; compliance-mode\n * retention cannot be shortened by anyone until the\n * `retainUntilTimestamp` elapses.\n *\n * @param fileId - The file version to apply the policy to.\n * @param retention - The retention policy to apply.\n * @param options - Optional flag for shortening governance-mode retention.\n *\n * @returns Metadata for the updated file version.\n */\n async setRetention(\n fileId: FileId,\n retention: FileRetentionValue,\n options?: { bypassGovernance?: boolean },\n ) {\n return this.bucket.updateFileRetention(this.fileName, fileId, retention, options)\n }\n\n /**\n * Toggles the legal hold flag on a specific file version of this file.\n *\n * Legal hold is independent of retention: a file can be on legal hold\n * without any retention policy, and vice versa. The bucket must have\n * Object Lock enabled, and any caller must hold the `writeFileLegalHolds`\n * capability.\n *\n * @param fileId - The file version to apply the flag to.\n * @param legalHold - `'on'` to apply the hold, `'off'` to remove it.\n *\n * @returns Metadata for the updated file version.\n */\n async setLegalHold(fileId: FileId, legalHold: LegalHoldValue) {\n return this.bucket.updateFileLegalHold(this.fileName, fileId, legalHold)\n }\n}\n"],"names":["uploadLargeFile","uploadSmallFile","downloadByName","headByName","downloadById","headById","createParallelDownloadStream","createWriteStream"],"mappings":"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"}
|