@backblaze-labs/b2-sdk 0.3.0 → 0.4.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 +45 -1
- package/README.md +18 -5
- package/dist/_virtual/_b2-sdk-version-json.cjs +1 -1
- package/dist/_virtual/_b2-sdk-version-json.js +1 -1
- package/dist/auth/reauth-coalescer.cjs +65 -0
- package/dist/auth/reauth-coalescer.cjs.map +1 -0
- package/dist/auth/reauth-coalescer.d.cts +34 -0
- package/dist/auth/reauth-coalescer.d.cts.map +1 -0
- package/dist/auth/reauth-coalescer.d.ts +34 -0
- package/dist/auth/reauth-coalescer.d.ts.map +1 -0
- package/dist/auth/reauth-coalescer.js +65 -0
- package/dist/auth/reauth-coalescer.js.map +1 -0
- package/dist/backup/raw.cjs +37 -15
- package/dist/backup/raw.cjs.map +1 -1
- package/dist/backup/raw.d.cts +2 -2
- package/dist/backup/raw.d.cts.map +1 -1
- package/dist/backup/raw.d.ts +2 -2
- package/dist/backup/raw.d.ts.map +1 -1
- package/dist/backup/raw.js +37 -15
- package/dist/backup/raw.js.map +1 -1
- package/dist/bucket-validation.cjs +111 -0
- package/dist/bucket-validation.cjs.map +1 -0
- package/dist/bucket-validation.d.cts +27 -0
- package/dist/bucket-validation.d.cts.map +1 -0
- package/dist/bucket-validation.d.ts +27 -0
- package/dist/bucket-validation.d.ts.map +1 -0
- package/dist/bucket-validation.js +109 -0
- package/dist/bucket-validation.js.map +1 -0
- package/dist/bucket.cjs +123 -73
- package/dist/bucket.cjs.map +1 -1
- package/dist/bucket.d.cts +156 -61
- package/dist/bucket.d.cts.map +1 -1
- package/dist/bucket.d.ts +156 -61
- package/dist/bucket.d.ts.map +1 -1
- package/dist/bucket.js +123 -73
- package/dist/bucket.js.map +1 -1
- package/dist/client.cjs +29 -8
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +30 -9
- package/dist/client.d.cts.map +1 -1
- package/dist/client.d.ts +30 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +29 -8
- package/dist/client.js.map +1 -1
- package/dist/download/single.cjs +38 -13
- package/dist/download/single.cjs.map +1 -1
- package/dist/download/single.d.cts +10 -4
- package/dist/download/single.d.cts.map +1 -1
- package/dist/download/single.d.ts +10 -4
- package/dist/download/single.d.ts.map +1 -1
- package/dist/download/single.js +38 -13
- package/dist/download/single.js.map +1 -1
- package/dist/errors/index.cjs +27 -4
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +15 -0
- package/dist/errors/index.d.cts.map +1 -1
- package/dist/errors/index.d.ts +15 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +27 -5
- package/dist/errors/index.js.map +1 -1
- package/dist/http/non-idempotent-mutations.cjs +38 -0
- package/dist/http/non-idempotent-mutations.cjs.map +1 -0
- package/dist/http/non-idempotent-mutations.d.cts +25 -0
- package/dist/http/non-idempotent-mutations.d.cts.map +1 -0
- package/dist/http/non-idempotent-mutations.d.ts +25 -0
- package/dist/http/non-idempotent-mutations.d.ts.map +1 -0
- package/dist/http/non-idempotent-mutations.js +35 -0
- package/dist/http/non-idempotent-mutations.js.map +1 -0
- package/dist/http/transport.cjs +9 -8
- package/dist/http/transport.cjs.map +1 -1
- package/dist/http/transport.d.cts +5 -0
- package/dist/http/transport.d.cts.map +1 -1
- package/dist/http/transport.d.ts +5 -0
- package/dist/http/transport.d.ts.map +1 -1
- package/dist/http/transport.js +9 -8
- package/dist/http/transport.js.map +1 -1
- package/dist/http/user-agent.cjs +12 -1
- package/dist/http/user-agent.cjs.map +1 -1
- package/dist/http/user-agent.d.cts +8 -0
- package/dist/http/user-agent.d.cts.map +1 -1
- package/dist/http/user-agent.d.ts +8 -0
- package/dist/http/user-agent.d.ts.map +1 -1
- package/dist/http/user-agent.js +13 -3
- package/dist/http/user-agent.js.map +1 -1
- package/dist/index.cjs +25 -0
- package/dist/index.d.cts +10 -9
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +10 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/notifications/index.cjs +3 -0
- package/dist/notifications/index.d.cts +2 -0
- package/dist/notifications/index.d.cts.map +1 -1
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +2 -1
- package/dist/object.cjs +12 -1
- package/dist/object.cjs.map +1 -1
- package/dist/object.d.cts +7 -1
- package/dist/object.d.cts.map +1 -1
- package/dist/object.d.ts +7 -1
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +12 -1
- package/dist/object.js.map +1 -1
- package/dist/partner/auth-core.cjs +4 -23
- package/dist/partner/auth-core.cjs.map +1 -1
- package/dist/partner/auth-core.d.cts +1 -1
- package/dist/partner/auth-core.d.cts.map +1 -1
- package/dist/partner/auth-core.d.ts +1 -1
- package/dist/partner/auth-core.d.ts.map +1 -1
- package/dist/partner/auth-core.js +5 -24
- package/dist/partner/auth-core.js.map +1 -1
- package/dist/partner/client.cjs +25 -10
- package/dist/partner/client.cjs.map +1 -1
- package/dist/partner/client.d.cts +32 -10
- package/dist/partner/client.d.cts.map +1 -1
- package/dist/partner/client.d.ts +32 -10
- package/dist/partner/client.d.ts.map +1 -1
- package/dist/partner/client.js +25 -10
- package/dist/partner/client.js.map +1 -1
- package/dist/partner/endpoint-url.cjs +1 -0
- package/dist/partner/endpoint-url.cjs.map +1 -1
- package/dist/partner/endpoint-url.d.cts +2 -0
- package/dist/partner/endpoint-url.d.cts.map +1 -1
- package/dist/partner/endpoint-url.d.ts +2 -0
- package/dist/partner/endpoint-url.d.ts.map +1 -1
- package/dist/partner/endpoint-url.js +1 -0
- package/dist/partner/endpoint-url.js.map +1 -1
- package/dist/partner/in-memory.cjs.map +1 -1
- package/dist/partner/in-memory.js.map +1 -1
- package/dist/partner/index.cjs +9 -0
- package/dist/partner/index.d.cts +11 -2
- package/dist/partner/index.d.cts.map +1 -1
- package/dist/partner/index.d.ts +11 -2
- package/dist/partner/index.d.ts.map +1 -1
- package/dist/partner/index.js +3 -1
- package/dist/partner/raw.cjs +52 -44
- package/dist/partner/raw.cjs.map +1 -1
- package/dist/partner/raw.d.cts +16 -19
- package/dist/partner/raw.d.cts.map +1 -1
- package/dist/partner/raw.d.ts +16 -19
- package/dist/partner/raw.d.ts.map +1 -1
- package/dist/partner/raw.js +52 -44
- package/dist/partner/raw.js.map +1 -1
- package/dist/partner/redaction.cjs +133 -108
- package/dist/partner/redaction.cjs.map +1 -1
- package/dist/partner/redaction.d.cts +47 -13
- package/dist/partner/redaction.d.cts.map +1 -1
- package/dist/partner/redaction.d.ts +47 -13
- package/dist/partner/redaction.d.ts.map +1 -1
- package/dist/partner/redaction.js +133 -109
- package/dist/partner/redaction.js.map +1 -1
- package/dist/raw/encoding.cjs +29 -10
- package/dist/raw/encoding.cjs.map +1 -1
- package/dist/raw/encoding.d.cts +3 -2
- package/dist/raw/encoding.d.cts.map +1 -1
- package/dist/raw/encoding.d.ts +3 -2
- package/dist/raw/encoding.d.ts.map +1 -1
- package/dist/raw/encoding.js +29 -10
- package/dist/raw/encoding.js.map +1 -1
- package/dist/raw/index.cjs +64 -39
- package/dist/raw/index.cjs.map +1 -1
- package/dist/raw/index.d.cts +21 -19
- package/dist/raw/index.d.cts.map +1 -1
- package/dist/raw/index.d.ts +21 -19
- package/dist/raw/index.d.ts.map +1 -1
- package/dist/raw/index.js +47 -40
- package/dist/raw/index.js.map +1 -1
- package/dist/raw/url.cjs.map +1 -1
- package/dist/raw/url.d.cts +3 -3
- package/dist/raw/url.d.ts +3 -3
- package/dist/raw/url.js.map +1 -1
- package/dist/simulator/index.cjs +456 -125
- package/dist/simulator/index.cjs.map +1 -1
- package/dist/simulator/index.d.cts +16 -1
- package/dist/simulator/index.d.cts.map +1 -1
- package/dist/simulator/index.d.ts +16 -1
- package/dist/simulator/index.d.ts.map +1 -1
- package/dist/simulator/index.js +449 -130
- package/dist/simulator/index.js.map +1 -1
- package/dist/simulator/partner-capabilities.cjs +77 -0
- package/dist/simulator/partner-capabilities.cjs.map +1 -0
- package/dist/simulator/partner-capabilities.d.cts +53 -0
- package/dist/simulator/partner-capabilities.d.cts.map +1 -0
- package/dist/simulator/partner-capabilities.d.ts +53 -0
- package/dist/simulator/partner-capabilities.d.ts.map +1 -0
- package/dist/simulator/partner-capabilities.js +73 -0
- package/dist/simulator/partner-capabilities.js.map +1 -0
- package/dist/simulator/partner.cjs +55 -61
- package/dist/simulator/partner.cjs.map +1 -1
- package/dist/simulator/partner.d.cts +5 -2
- package/dist/simulator/partner.d.cts.map +1 -1
- package/dist/simulator/partner.d.ts +5 -2
- package/dist/simulator/partner.d.ts.map +1 -1
- package/dist/simulator/partner.js +56 -61
- package/dist/simulator/partner.js.map +1 -1
- package/dist/simulator/validation.cjs +160 -30
- package/dist/simulator/validation.cjs.map +1 -1
- package/dist/simulator/validation.d.cts +28 -6
- package/dist/simulator/validation.d.cts.map +1 -1
- package/dist/simulator/validation.d.ts +28 -6
- package/dist/simulator/validation.d.ts.map +1 -1
- package/dist/simulator/validation.js +148 -31
- 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/hash.cjs +246 -13
- package/dist/streams/hash.cjs.map +1 -1
- package/dist/streams/hash.d.cts +37 -12
- package/dist/streams/hash.d.cts.map +1 -1
- package/dist/streams/hash.d.ts +37 -12
- package/dist/streams/hash.d.ts.map +1 -1
- package/dist/streams/hash.js +246 -15
- package/dist/streams/hash.js.map +1 -1
- package/dist/streams/index.cjs +2 -0
- package/dist/streams/index.d.cts +1 -1
- package/dist/streams/index.d.cts.map +1 -1
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.d.ts.map +1 -1
- package/dist/streams/index.js +2 -2
- package/dist/streams/progress.cjs +63 -4
- package/dist/streams/progress.cjs.map +1 -1
- package/dist/streams/progress.d.cts +28 -2
- package/dist/streams/progress.d.cts.map +1 -1
- package/dist/streams/progress.d.ts +28 -2
- package/dist/streams/progress.d.ts.map +1 -1
- package/dist/streams/progress.js +63 -4
- package/dist/streams/progress.js.map +1 -1
- package/dist/sync/download-staging.cjs +147 -35
- package/dist/sync/download-staging.cjs.map +1 -1
- package/dist/sync/download-staging.d.cts +25 -2
- package/dist/sync/download-staging.d.cts.map +1 -1
- package/dist/sync/download-staging.d.ts +25 -2
- package/dist/sync/download-staging.d.ts.map +1 -1
- package/dist/sync/download-staging.js +146 -36
- package/dist/sync/download-staging.js.map +1 -1
- package/dist/sync/index.d.cts +1 -1
- package/dist/sync/index.d.cts.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/local-file-io.cjs +5 -1
- package/dist/sync/local-file-io.cjs.map +1 -1
- package/dist/sync/local-file-io.d.cts +2 -0
- package/dist/sync/local-file-io.d.cts.map +1 -1
- package/dist/sync/local-file-io.d.ts +2 -0
- package/dist/sync/local-file-io.d.ts.map +1 -1
- package/dist/sync/local-file-io.js +5 -1
- package/dist/sync/local-file-io.js.map +1 -1
- package/dist/sync/pairing.cjs +1 -0
- package/dist/sync/pairing.cjs.map +1 -1
- package/dist/sync/pairing.js +1 -0
- package/dist/sync/pairing.js.map +1 -1
- package/dist/sync/scanners/b2.cjs +2 -0
- package/dist/sync/scanners/b2.cjs.map +1 -1
- package/dist/sync/scanners/b2.d.cts.map +1 -1
- package/dist/sync/scanners/b2.d.ts.map +1 -1
- package/dist/sync/scanners/b2.js +2 -0
- package/dist/sync/scanners/b2.js.map +1 -1
- package/dist/sync/scanners/local.cjs +150 -33
- package/dist/sync/scanners/local.cjs.map +1 -1
- package/dist/sync/scanners/local.d.cts +6 -0
- package/dist/sync/scanners/local.d.cts.map +1 -1
- package/dist/sync/scanners/local.d.ts +6 -0
- package/dist/sync/scanners/local.d.ts.map +1 -1
- package/dist/sync/scanners/local.js +150 -33
- package/dist/sync/scanners/local.js.map +1 -1
- package/dist/sync/synchronizer.cjs +76 -29
- package/dist/sync/synchronizer.cjs.map +1 -1
- package/dist/sync/synchronizer.d.cts +1 -0
- package/dist/sync/synchronizer.d.cts.map +1 -1
- package/dist/sync/synchronizer.d.ts +1 -0
- package/dist/sync/synchronizer.d.ts.map +1 -1
- package/dist/sync/synchronizer.js +76 -29
- package/dist/sync/synchronizer.js.map +1 -1
- package/dist/sync/types.d.cts +19 -3
- package/dist/sync/types.d.cts.map +1 -1
- package/dist/sync/types.d.ts +19 -3
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/types/backup.d.cts +6 -1
- package/dist/types/backup.d.cts.map +1 -1
- package/dist/types/backup.d.ts +6 -1
- package/dist/types/backup.d.ts.map +1 -1
- package/dist/types/bucket.cjs +81 -11
- package/dist/types/bucket.cjs.map +1 -1
- package/dist/types/bucket.d.cts +190 -39
- package/dist/types/bucket.d.cts.map +1 -1
- package/dist/types/bucket.d.ts +190 -39
- package/dist/types/bucket.d.ts.map +1 -1
- package/dist/types/bucket.js +67 -12
- package/dist/types/bucket.js.map +1 -1
- package/dist/types/download.cjs.map +1 -1
- package/dist/types/download.d.cts +3 -17
- package/dist/types/download.d.cts.map +1 -1
- package/dist/types/download.d.ts +3 -17
- package/dist/types/download.d.ts.map +1 -1
- package/dist/types/download.js.map +1 -1
- package/dist/types/encryption.cjs +18 -0
- package/dist/types/encryption.cjs.map +1 -1
- package/dist/types/encryption.d.cts +21 -11
- package/dist/types/encryption.d.cts.map +1 -1
- package/dist/types/encryption.d.ts +21 -11
- package/dist/types/encryption.d.ts.map +1 -1
- package/dist/types/encryption.js +18 -0
- package/dist/types/encryption.js.map +1 -1
- package/dist/types/file.cjs +3 -0
- package/dist/types/file.cjs.map +1 -1
- package/dist/types/file.d.cts +125 -16
- package/dist/types/file.d.cts.map +1 -1
- package/dist/types/file.d.ts +125 -16
- package/dist/types/file.d.ts.map +1 -1
- package/dist/types/file.js +3 -1
- package/dist/types/file.js.map +1 -1
- package/dist/types/index.d.cts +7 -7
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/key.d.cts +4 -3
- package/dist/types/key.d.cts.map +1 -1
- package/dist/types/key.d.ts +4 -3
- package/dist/types/key.d.ts.map +1 -1
- package/dist/types/notifications.cjs +30 -0
- package/dist/types/notifications.cjs.map +1 -1
- package/dist/types/notifications.d.cts +26 -1
- package/dist/types/notifications.d.cts.map +1 -1
- package/dist/types/notifications.d.ts +26 -1
- package/dist/types/notifications.d.ts.map +1 -1
- package/dist/types/notifications.js +29 -1
- package/dist/types/notifications.js.map +1 -1
- package/dist/types/partner.cjs.map +1 -1
- package/dist/types/partner.d.cts +28 -36
- package/dist/types/partner.d.cts.map +1 -1
- package/dist/types/partner.d.ts +28 -36
- package/dist/types/partner.d.ts.map +1 -1
- package/dist/types/partner.js.map +1 -1
- package/dist/types/upload.d.cts +4 -0
- package/dist/types/upload.d.cts.map +1 -1
- package/dist/types/upload.d.ts +4 -0
- package/dist/types/upload.d.ts.map +1 -1
- package/dist/upload/large.cjs +10 -7
- package/dist/upload/large.cjs.map +1 -1
- package/dist/upload/large.d.cts +15 -6
- package/dist/upload/large.d.cts.map +1 -1
- package/dist/upload/large.d.ts +15 -6
- package/dist/upload/large.d.ts.map +1 -1
- package/dist/upload/large.js +10 -7
- 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 +4 -3
- package/dist/upload/resume.cjs.map +1 -1
- package/dist/upload/resume.d.cts +6 -4
- package/dist/upload/resume.d.cts.map +1 -1
- package/dist/upload/resume.d.ts +6 -4
- package/dist/upload/resume.d.ts.map +1 -1
- package/dist/upload/resume.js +4 -3
- package/dist/upload/resume.js.map +1 -1
- package/dist/upload/retry.cjs +17 -10
- package/dist/upload/retry.cjs.map +1 -1
- package/dist/upload/retry.d.cts.map +1 -1
- package/dist/upload/retry.d.ts.map +1 -1
- package/dist/upload/retry.js +17 -10
- package/dist/upload/retry.js.map +1 -1
- package/dist/upload/single.cjs +35 -31
- 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 +35 -31
- package/dist/upload/single.js.map +1 -1
- package/dist/upload/stream.cjs +12 -1
- 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 +12 -1
- package/dist/upload/stream.js.map +1 -1
- package/dist/version.cjs +56 -4
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +53 -4
- package/dist/version.d.cts.map +1 -1
- package/dist/version.d.ts +53 -4
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +52 -5
- package/dist/version.js.map +1 -1
- package/package.json +11 -4
package/dist/upload/large.cjs
CHANGED
|
@@ -22,7 +22,7 @@ function createResumeCandidateCriteria(options, request, totalSize, partSize, pa
|
|
|
22
22
|
parts,
|
|
23
23
|
...options.customUploadTimestamp !== void 0 ? { customUploadTimestamp: options.customUploadTimestamp } : {},
|
|
24
24
|
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
25
|
-
...request.serverSideEncryption !== void 0 ? { serverSideEncryption: request.serverSideEncryption } : options.bucketDefaultServerSideEncryption !== void 0 ? { serverSideEncryption: options.bucketDefaultServerSideEncryption } : {},
|
|
25
|
+
...request.serverSideEncryption !== void 0 ? { serverSideEncryption: request.serverSideEncryption } : options.bucketDefaultServerSideEncryption !== void 0 ? { serverSideEncryption: options.bucketDefaultServerSideEncryption } : options.bucketDefaultServerSideEncryptionUnreadable === true ? { defaultServerSideEncryptionUnreadable: true } : {},
|
|
26
26
|
...request.fileRetention !== void 0 ? { fileRetention: request.fileRetention } : options.bucketDefaultRetention !== void 0 ? { defaultFileRetention: options.bucketDefaultRetention } : options.bucketDefaultRetentionUnreadable === true ? { defaultFileRetentionUnreadable: true } : {},
|
|
27
27
|
...request.legalHold !== void 0 ? { legalHold: request.legalHold } : {},
|
|
28
28
|
...options.resumeDiscoveryTimeoutMs !== void 0 ? { discoveryTimeoutMs: options.resumeDiscoveryTimeoutMs } : {},
|
|
@@ -73,6 +73,7 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
73
73
|
let largeFileId;
|
|
74
74
|
let preUploaded = /* @__PURE__ */ new Map();
|
|
75
75
|
let createdLargeFile = false;
|
|
76
|
+
let tracker;
|
|
76
77
|
const abortScope = require_abort_scope.createAbortScope(options.signal);
|
|
77
78
|
const startFreshLargeFile = async () => {
|
|
78
79
|
if (abortScope.signal.aborted && !options.source.canSlice) await cancelForwardOnlySource(options.source, abortScope.signal.reason);
|
|
@@ -114,10 +115,11 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
114
115
|
const activeLargeFileId = largeFileId;
|
|
115
116
|
if (activeLargeFileId === void 0) throw new Error("uploadLargeFile: start did not return a large file ID.");
|
|
116
117
|
const partSha1s = new Array(parts.length);
|
|
117
|
-
const
|
|
118
|
+
const uploadTracker = new require_progress.ProgressTracker(options.onProgress, totalSize, parts.length, { ...options.progressIntervalMillis !== void 0 ? { minIntervalMs: options.progressIntervalMillis } : {} });
|
|
119
|
+
tracker = uploadTracker;
|
|
118
120
|
const sem = new require_concurrency.Semaphore(concurrency);
|
|
119
121
|
if (!options.source.canSlice) {
|
|
120
|
-
await uploadPartsSequentially(raw, accountInfo, options, activeLargeFileId, parts, partSha1s,
|
|
122
|
+
await uploadPartsSequentially(raw, accountInfo, options, activeLargeFileId, parts, partSha1s, uploadTracker, abortScope.signal);
|
|
121
123
|
return await require_finish.finishLargeFileWithAbortReconciliation(raw, accountInfo, {
|
|
122
124
|
fileId: activeLargeFileId,
|
|
123
125
|
bucketId: options.bucketId,
|
|
@@ -148,8 +150,8 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
148
150
|
contentSha1: serverSha1
|
|
149
151
|
});
|
|
150
152
|
partSha1s[part.partNumber - 1] = serverSha1;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
uploadTracker.addBytes(data.byteLength);
|
|
154
|
+
uploadTracker.completePart();
|
|
153
155
|
return;
|
|
154
156
|
}
|
|
155
157
|
const result = await require_retry.uploadPartWithFreshUrl(raw, accountInfo, activeLargeFileId, {
|
|
@@ -165,8 +167,8 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
165
167
|
...options.serverSideEncryption !== void 0 ? { serverSideEncryption: options.serverSideEncryption } : {}
|
|
166
168
|
});
|
|
167
169
|
partSha1s[part.partNumber - 1] = result.contentSha1;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
uploadTracker.addBytes(data.byteLength);
|
|
171
|
+
uploadTracker.completePart();
|
|
170
172
|
} catch (err) {
|
|
171
173
|
abortScope.abort(err);
|
|
172
174
|
throw err;
|
|
@@ -188,6 +190,7 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
188
190
|
if (largeFileId === void 0) throw err;
|
|
189
191
|
return await cleanupAfterUploadLargeFileError(err, raw, accountInfo, options, largeFileId, createdLargeFile);
|
|
190
192
|
} finally {
|
|
193
|
+
tracker?.dispose();
|
|
191
194
|
abortScope.dispose();
|
|
192
195
|
}
|
|
193
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"large.cjs","names":[],"sources":["../../src/upload/large.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport type { ProgressListener } from '../streams/progress.ts'\nimport { ProgressTracker } from '../streams/progress.ts'\nimport { type ContentSource, readNextNonEmptyStreamChunk } from '../streams/source.ts'\nimport type { BucketRetentionPolicy } from '../types/bucket.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { FileVersion } from '../types/file.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport { raceWithAbort } from '../util/abort.ts'\nimport { DEFAULT_CONTENT_TYPE, DEFAULT_TRANSFER_CONCURRENCY } from '../util/defaults.ts'\nimport { planRanges, type RangePlan } from '../util/plan-ranges.ts'\nimport { createAbortScope, throwRejectedOrAbortReason } from './abort-scope.ts'\nimport {\n type CleanupFailureOptions,\n cancelLargeFileBestEffort,\n cleanupAfterLargeFileError,\n} from './cancel.ts'\nimport { Semaphore } from './concurrency.ts'\nimport { finishLargeFileWithAbortReconciliation } from './finish.ts'\nimport {\n findResumeCandidate,\n type ResumeCandidateCriteria,\n type ResumeCandidateRejectedListener,\n ResumeFileIdMismatchError,\n} from './resume.ts'\nimport {\n resolveRetryResponseBodyFailures,\n type UploadRetryOptions,\n uploadPartWithFreshUrl,\n} from './retry.ts'\n\n/** Event emitted when explicit resume skips a local part because B2 already has matching SHA-1 bytes. */\nexport interface ResumePartReusedEvent {\n /** File name being resumed. */\n readonly fileName: string\n /** Unfinished large-file ID that supplied the existing part. */\n readonly fileId: LargeFileId\n /** One-based part number reused from the unfinished large file. */\n readonly partNumber: number\n /** Number of bytes in the reused part. */\n readonly contentLength: number\n /** SHA-1 hex digest that matched the local part bytes. */\n readonly contentSha1: string\n}\n\n/** Callback invoked when explicit resume accepts a pre-existing server part. */\nexport type ResumePartReusedListener = (event: ResumePartReusedEvent) => void\n\nconst MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS = 1024\n\n/** Options for uploading a large file via the multipart protocol. */\nexport interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailureOptions {\n /** Target bucket for the upload. */\n readonly bucketId: BucketId\n /** Full B2 file name including any path prefix. */\n readonly fileName: string\n /**\n * Content to upload. Sliceable sources ({@link BufferSource},\n * {@link BlobSource}, {@link FileSource}) use the parallel-parts path.\n * Non-sliceable streams and async iterables fall back to a sequential read\n * path — one part at a time, concurrency forced to 1 — so callers can stream\n * a multi-GB file without buffering the whole payload in memory. The\n * `resumeFileId` requires a sliceable source; deprecated `resume: true`\n * without an explicit file ID is ignored on forward-only sources.\n */\n readonly source: ContentSource\n /** MIME type. Defaults to `b2/x-auto` for server-side detection. */\n readonly contentType?: string\n /** Custom file info key/value pairs stored with the file. */\n readonly fileInfo?: Record<string, string>\n /** Server-side encryption settings applied to each part. */\n readonly serverSideEncryption?: EncryptionSetting\n /** Effective bucket default encryption used when serverSideEncryption is omitted. */\n readonly bucketDefaultServerSideEncryption?: EncryptionSetting\n /** File retention policy applied at upload time. */\n readonly fileRetention?: FileRetentionValue\n /** Effective readable bucket default retention used when fileRetention is omitted. */\n readonly bucketDefaultRetention?: BucketRetentionPolicy\n /** Bucket default retention exists but cannot be read, so resume must fail closed. */\n readonly bucketDefaultRetentionUnreadable?: boolean\n /** Legal hold status applied at upload time. */\n readonly legalHold?: LegalHoldValue\n /** Override the last-modified timestamp (epoch millis) stored in file info. */\n readonly lastModifiedMillis?: number\n /**\n * B2 upload timestamp override in milliseconds since epoch.\n * Sets the file version `uploadTimestamp`; distinct from `lastModifiedMillis` metadata.\n * Requires B2 account enablement for Custom Upload Timestamp.\n */\n readonly customUploadTimestamp?: number\n /** Size of each part in bytes. Defaults to the account's recommended part size. */\n readonly partSize?: number\n /** Maximum number of parts uploaded in parallel. Defaults to 4. */\n readonly concurrency?: number\n /** Callback invoked with upload progress updates. */\n readonly onProgress?: ProgressListener\n /** Signal to abort the upload. Triggers cancellation of the large file. */\n readonly signal?: AbortSignal\n /**\n * If true, look for an unfinished large file with the same bucket and file name\n * and continue uploading into it. Automatic discovery only reuses unfinished\n * files whose upload options and already-uploaded part lengths match;\n * otherwise a new large file is started. Existing server parts are overwritten\n * with locally read bytes instead of being trusted by SHA-1 alone.\n *\n * Discovery runs before the first upload byte and can make up to the\n * list-page budget plus the candidate budget times the part-page budget in\n * sequential B2 list calls. Pass `resumeDiscoveryTimeoutMs` or an\n * `AbortSignal` to enforce a hard discovery deadline. SSE-C uploads are\n * never auto-resumed because B2 does not expose the customer key identity\n * needed to verify a compatible unfinished file. Candidates with unreadable\n * Object Lock fields are rejected unless the caller provides explicit settings\n * that can be verified. When `customUploadTimestamp` is set, discovery only\n * reuses candidates with the same `uploadTimestamp`; when it is omitted, a\n * reused unfinished file keeps its existing `uploadTimestamp` because B2 does\n * not expose whether that timestamp was custom or server-assigned.\n * `lastModifiedMillis` is part of the file-info identity; unfinished files\n * started by older SDK versions that omitted it can be rejected with\n * `file-info-mismatch`.\n */\n readonly resume?: boolean\n /** Optional aggregate SDK-enforced timeout for resume discovery. */\n readonly resumeDiscoveryTimeoutMs?: number\n /**\n * Maximum `b2_list_unfinished_large_files` pages inspected before upload starts. Defaults to 10.\n * If the scan truncates, resume falls back to a fresh upload and\n * `onResumeCandidateRejected` is the only SDK signal.\n */\n readonly resumeMaxListPages?: number\n /**\n * Maximum metadata-compatible candidates whose parts may be listed before upload starts. Defaults to 25.\n * Hitting the limit can leave older unfinished uploads orphaned while a fresh\n * large file is started; tune for high-churn buckets.\n */\n readonly resumeMaxPartCandidates?: number\n /**\n * Maximum `b2_list_parts` pages inspected per metadata-compatible candidate before upload starts. Defaults to 10.\n * A candidate whose parts exceed this bound is skipped and reported through\n * `onResumeCandidateRejected`.\n */\n readonly resumeMaxPartPages?: number\n /**\n * Explicit large file ID to resume into. Overrides {@link resume} discovery\n * after verifying that the ID belongs to the requested bucket/file name and\n * matches the current upload options and already-uploaded part lengths. This\n * verification also rejects SSE-C uploads because B2 does not expose\n * customer key identity for unfinished files. A mismatch, or a file ID that\n * cannot be verified through B2's unfinished-large-file listing, throws\n * {@link ResumeFileIdMismatchError}. Unreadable Object Lock fields reject\n * the candidate.\n */\n readonly resumeFileId?: LargeFileId\n /** Diagnostic callback invoked when resume discovery rejects a candidate. */\n readonly onResumeCandidateRejected?: ResumeCandidateRejectedListener\n /** Diagnostic callback invoked when resume reuses an already-uploaded part. */\n readonly onResumePartReused?: ResumePartReusedListener\n}\n\ninterface StartLargeFileResumeRequest {\n readonly contentType: string\n readonly fileInfo: Record<string, string>\n readonly serverSideEncryption?: EncryptionSetting\n readonly fileRetention?: FileRetentionValue\n readonly legalHold?: LegalHoldValue\n}\n\nfunction createResumeCandidateCriteria(\n options: UploadLargeFileOptions,\n request: StartLargeFileResumeRequest,\n totalSize: number,\n partSize: number,\n parts: readonly RangePlan[],\n): ResumeCandidateCriteria {\n return {\n contentType: request.contentType,\n fileInfo: request.fileInfo,\n sourceSize: totalSize,\n partSize,\n parts,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: options.customUploadTimestamp }\n : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(request.serverSideEncryption !== undefined\n ? { serverSideEncryption: request.serverSideEncryption }\n : options.bucketDefaultServerSideEncryption !== undefined\n ? { serverSideEncryption: options.bucketDefaultServerSideEncryption }\n : {}),\n ...(request.fileRetention !== undefined\n ? { fileRetention: request.fileRetention }\n : options.bucketDefaultRetention !== undefined\n ? { defaultFileRetention: options.bucketDefaultRetention }\n : options.bucketDefaultRetentionUnreadable === true\n ? { defaultFileRetentionUnreadable: true }\n : {}),\n ...(request.legalHold !== undefined ? { legalHold: request.legalHold } : {}),\n ...(options.resumeDiscoveryTimeoutMs !== undefined\n ? { discoveryTimeoutMs: options.resumeDiscoveryTimeoutMs }\n : {}),\n ...(options.onResumeCandidateRejected !== undefined\n ? { onCandidateRejected: options.onResumeCandidateRejected }\n : {}),\n ...(options.resumeMaxListPages !== undefined\n ? { maxListPages: options.resumeMaxListPages }\n : {}),\n ...(options.resumeMaxPartCandidates !== undefined\n ? { maxPartCandidates: options.resumeMaxPartCandidates }\n : {}),\n ...(options.resumeMaxPartPages !== undefined\n ? { maxPartPages: options.resumeMaxPartPages }\n : {}),\n }\n}\n\n/**\n * Uploads a file using the B2 multipart (large file) protocol.\n *\n * The source is sliced into parts and uploaded concurrently via\n * `b2_upload_part`. This is appropriate for files larger than the recommended\n * part size. For smaller files, use {@link uploadSmallFile} which sends the\n * entire payload in a single request.\n *\n * On failure, the in-progress large file is cancelled on a best-effort basis.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state (tokens, URLs, upload URL pool).\n * @param options - Upload parameters including part size and concurrency.\n *\n * @returns The resulting {@link FileVersion} metadata.\n */\nexport async function uploadLargeFile(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n): Promise<FileVersion> {\n const recommendedPartSize = accountInfo.getRecommendedPartSize()\n const minPartSize = accountInfo.getAbsoluteMinimumPartSize()\n const partSize = Math.max(options.partSize ?? recommendedPartSize, minPartSize)\n const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY\n const totalSize = options.source.size\n\n const parts = planRanges(totalSize, partSize)\n // Keep caller fileInfo on a null-prototype record so resume identity\n // comparison only sees caller-owned enumerable keys.\n const fileInfo: Record<string, string> = Object.create(null)\n if (options.fileInfo !== undefined) {\n for (const [key, value] of Object.entries(options.fileInfo)) {\n fileInfo[key] = value\n }\n }\n if (options.lastModifiedMillis !== undefined) {\n fileInfo['src_last_modified_millis'] = String(options.lastModifiedMillis)\n }\n\n // Construct the `b2_start_large_file` request body once so the two\n // non-resume branches below (no `resume`, resume-but-no-candidate)\n // can dispatch without re-spelling the conditional spreads.\n const startLargeFileRequest = {\n bucketId: options.bucketId,\n fileName: options.fileName,\n contentType: options.contentType ?? DEFAULT_CONTENT_TYPE,\n fileInfo,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: String(options.customUploadTimestamp) }\n : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.fileRetention !== undefined ? { fileRetention: options.fileRetention } : {}),\n ...(options.legalHold !== undefined ? { legalHold: options.legalHold } : {}),\n }\n const resumeCandidateCriteria = createResumeCandidateCriteria(\n options,\n startLargeFileRequest,\n totalSize,\n partSize,\n parts,\n )\n\n if (!options.source.canSlice && options.resumeFileId !== undefined) {\n throw new Error('uploadLargeFile: resume is not supported on non-sliceable sources.')\n }\n\n // --- Explicit resume file reuse (M11.1) ---\n let largeFileId: LargeFileId | undefined\n let preUploaded: ReadonlyMap<number, string> = new Map()\n let createdLargeFile = false\n const abortScope = createAbortScope(options.signal)\n const startFreshLargeFile = async (): Promise<void> => {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n const startPromise = raw.startLargeFile(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n startLargeFileRequest,\n {\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n )\n try {\n const startResp = await raceWithAbort(startPromise, abortScope.signal)\n largeFileId = startResp.fileId\n } catch (err) {\n if (abortScope.signal.aborted) {\n if (!options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason).catch(() => {})\n }\n cancelLargeFileAfterStart(startPromise, raw, accountInfo, options.onCleanupFailure)\n }\n throw err\n }\n preUploaded = new Map<number, string>()\n createdLargeFile = true\n }\n\n try {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n if (options.resumeFileId !== undefined) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n {\n ...resumeCandidateCriteria,\n resumeFileId: options.resumeFileId,\n },\n )\n if (candidate === null) {\n throw new ResumeFileIdMismatchError(options.resumeFileId, options.fileName)\n }\n largeFileId = candidate.fileId\n preUploaded = candidate.uploadedPartSha1s\n } else if (options.resume === true && options.source.canSlice) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n resumeCandidateCriteria,\n )\n if (candidate) {\n largeFileId = candidate.fileId\n preUploaded = new Map<number, string>()\n } else {\n await startFreshLargeFile()\n }\n } else {\n await startFreshLargeFile()\n }\n const activeLargeFileId = largeFileId\n if (activeLargeFileId === undefined) {\n throw new Error('uploadLargeFile: start did not return a large file ID.')\n }\n\n const partSha1s: string[] = new Array(parts.length)\n const tracker = new ProgressTracker(options.onProgress, totalSize, parts.length)\n const sem = new Semaphore(concurrency)\n\n // Non-sliceable sources can't be read in parallel — there's only one\n // forward-only cursor. Resume is also impossible (no seek). Bail to a\n // sequential read loop instead. Each part is buffered, hashed, shipped,\n // then dropped before the next read starts, so the peak memory footprint is\n // ~partSize bytes regardless of total file size.\n if (!options.source.canSlice) {\n await uploadPartsSequentially(\n raw,\n accountInfo,\n options,\n activeLargeFileId,\n parts,\n partSha1s,\n tracker,\n abortScope.signal,\n )\n return await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n }\n\n const tasks = parts.map(async (part) => {\n await sem.acquire()\n try {\n abortScope.signal.throwIfAborted()\n\n const partSource = options.source.slice(part.offset, part.offset + part.length)\n const data = new Uint8Array(await partSource.toArrayBuffer({ signal: abortScope.signal }))\n abortScope.signal.throwIfAborted()\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n abortScope.signal.throwIfAborted()\n\n // Explicit resume is the only mode that trusts an already-uploaded\n // server part enough to skip sending the local bytes again.\n const serverSha1 = preUploaded.get(part.partNumber)\n if (serverSha1 !== undefined && serverSha1 === sha1Hex) {\n notifyResumePartReused(options.onResumePartReused, {\n fileName: options.fileName,\n fileId: activeLargeFileId,\n partNumber: part.partNumber,\n contentLength: data.byteLength,\n contentSha1: serverSha1,\n })\n partSha1s[part.partNumber - 1] = serverSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n return\n }\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, activeLargeFileId, {\n fileName: options.fileName,\n partNumber: part.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal: abortScope.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[part.partNumber - 1] = result.contentSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n } catch (err) {\n abortScope.abort(err)\n throw err\n } finally {\n sem.release()\n }\n })\n\n throwRejectedOrAbortReason(await Promise.allSettled(tasks), abortScope)\n\n const result = await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n\n return result\n } catch (err) {\n abortScope.abort(err)\n if (largeFileId === undefined) throw err\n return await cleanupAfterUploadLargeFileError(\n err,\n raw,\n accountInfo,\n options,\n largeFileId,\n createdLargeFile,\n )\n } finally {\n abortScope.dispose()\n }\n}\n\nfunction cancelLargeFileAfterStart(\n started: Promise<{ readonly fileId: LargeFileId }>,\n raw: RawClient,\n accountInfo: AccountInfo,\n onCleanupFailure: CleanupFailureOptions['onCleanupFailure'],\n): void {\n void started\n .then((resp) =>\n cancelLargeFileBestEffort(\n raw,\n accountInfo,\n resp.fileId,\n onCleanupFailure === undefined ? undefined : { onCleanupFailure },\n ),\n )\n .catch(() => {\n // If start failed, no file ID is available to cancel.\n })\n}\n\nasync function cleanupAfterUploadLargeFileError(\n err: unknown,\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n createdLargeFile: boolean,\n): Promise<never> {\n return await cleanupAfterLargeFileError(\n err,\n raw,\n accountInfo,\n {\n fileId: largeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n signal: options.signal,\n onCleanupFailure: options.onCleanupFailure,\n },\n { cancelOnError: createdLargeFile },\n )\n}\n\n/**\n * Sequential upload path for non-sliceable sources.\n *\n * Reads the source's `stream()` once and accumulates exactly `partSize`\n * bytes into an in-memory buffer per iteration. Each filled buffer is\n * hashed, dispatched to `b2_upload_part`, then released before the next\n * part starts — so peak memory is ~partSize regardless of file size.\n *\n * Concurrency is forced to 1 here because the stream is a single\n * forward-only cursor; the engine can't read part N+1 until part N is\n * fully consumed.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - The original `uploadLargeFile` options.\n * @param largeFileId - ID of the in-progress large file (already started).\n * @param parts - Pre-planned part layout (used for part numbers + count).\n * @param partSha1s - Output array, written in-place at index `partNumber - 1`.\n * @param tracker - Progress tracker; bytes added per chunk, part completed\n * each time a part finishes.\n * @param signal - Linked abort signal for source reads and part uploads.\n */\nasync function uploadPartsSequentially(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n parts: readonly RangePlan[],\n partSha1s: string[],\n tracker: ProgressTracker,\n signal: AbortSignal,\n): Promise<void> {\n const reader = options.source.stream().getReader()\n let bytesRead = 0\n // Carry-over bytes from a previous read when the read returned more\n // than we needed to fill one part. Kept as an array to avoid an\n // allocation per loop iteration on a typical multi-part upload.\n let carry: Uint8Array | null = null\n\n try {\n for (const planned of parts) {\n signal.throwIfAborted()\n\n const buf = new Uint8Array(planned.length)\n let filled = 0\n\n if (carry !== null) {\n const take = Math.min(carry.byteLength, buf.byteLength - filled)\n buf.set(carry.subarray(0, take), filled)\n filled += take\n carry = take < carry.byteLength ? carry.subarray(take) : null\n }\n\n while (filled < buf.byteLength) {\n const { done, value } = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (done) {\n throw new Error(\n `uploadLargeFile: source stream ended after ${bytesRead} bytes, expected ${options.source.size}.`,\n )\n }\n bytesRead += value.byteLength\n const take = Math.min(value.byteLength, buf.byteLength - filled)\n buf.set(value.subarray(0, take), filled)\n filled += take\n if (take < value.byteLength) {\n carry = value.subarray(take)\n }\n }\n\n signal.throwIfAborted()\n const data = buf\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n signal.throwIfAborted()\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, largeFileId, {\n fileName: options.fileName,\n partNumber: planned.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[planned.partNumber - 1] = result.contentSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n }\n if (carry !== null && carry.byteLength > 0) {\n throw new Error(tooManyBytesError(options.source.size))\n }\n const extra = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (!extra.done) {\n bytesRead += extra.value.byteLength\n throw new Error(tooManyBytesError(options.source.size))\n }\n } catch (err) {\n await reader.cancel(err).catch(() => {})\n throw err\n } finally {\n // Releasing the lock lets the underlying stream propagate close / error\n // events to any upstream producer (e.g. a Node `Readable`).\n reader.releaseLock()\n }\n}\n\nfunction emptyChunkError(): string {\n return `uploadLargeFile: source stream emitted more than ${MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS} consecutive empty chunks. too many empty chunks.`\n}\n\nfunction tooManyBytesError(advertisedSize: number): string {\n return `uploadLargeFile: source stream emitted more than advertised ${advertisedSize} bytes. source stream emitted more bytes than advertised size.`\n}\n\nasync function cancelForwardOnlySource(source: ContentSource, reason: unknown): Promise<void> {\n const reader = source.stream().getReader()\n try {\n await reader.cancel(reason)\n } finally {\n reader.releaseLock()\n }\n}\n\nfunction notifyResumePartReused(\n listener: ResumePartReusedListener | undefined,\n event: ResumePartReusedEvent,\n): void {\n try {\n listener?.(event)\n } catch {\n // Diagnostic observers must not change upload success or failure.\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"large.cjs","names":[],"sources":["../../src/upload/large.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport type { ProgressListener } from '../streams/progress.ts'\nimport { ProgressTracker } from '../streams/progress.ts'\nimport { type ContentSource, readNextNonEmptyStreamChunk } from '../streams/source.ts'\nimport type { BucketDefaultRetention, BucketDefaultServerSideEncryption } from '../types/bucket.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { FileVersion } from '../types/file.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport { raceWithAbort } from '../util/abort.ts'\nimport { DEFAULT_CONTENT_TYPE, DEFAULT_TRANSFER_CONCURRENCY } from '../util/defaults.ts'\nimport { planRanges, type RangePlan } from '../util/plan-ranges.ts'\nimport { createAbortScope, throwRejectedOrAbortReason } from './abort-scope.ts'\nimport {\n type CleanupFailureOptions,\n cancelLargeFileBestEffort,\n cleanupAfterLargeFileError,\n} from './cancel.ts'\nimport { Semaphore } from './concurrency.ts'\nimport { finishLargeFileWithAbortReconciliation } from './finish.ts'\nimport {\n findResumeCandidate,\n type ResumeCandidateCriteria,\n type ResumeCandidateRejectedListener,\n ResumeFileIdMismatchError,\n} from './resume.ts'\nimport {\n resolveRetryResponseBodyFailures,\n type UploadRetryOptions,\n uploadPartWithFreshUrl,\n} from './retry.ts'\n\n/** Event emitted when explicit resume skips a local part because B2 already has matching SHA-1 bytes. */\nexport interface ResumePartReusedEvent {\n /** File name being resumed. */\n readonly fileName: string\n /** Unfinished large-file ID that supplied the existing part. */\n readonly fileId: LargeFileId\n /** One-based part number reused from the unfinished large file. */\n readonly partNumber: number\n /** Number of bytes in the reused part. */\n readonly contentLength: number\n /** SHA-1 hex digest that matched the local part bytes. */\n readonly contentSha1: string\n}\n\n/** Callback invoked when explicit resume accepts a pre-existing server part. */\nexport type ResumePartReusedListener = (event: ResumePartReusedEvent) => void\n\nconst MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS = 1024\n\n/** Options for uploading a large file via the multipart protocol. */\nexport interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailureOptions {\n /** Target bucket for the upload. */\n readonly bucketId: BucketId\n /** Full B2 file name including any path prefix. */\n readonly fileName: string\n /**\n * Content to upload. Sliceable sources ({@link BufferSource},\n * {@link BlobSource}, {@link FileSource}) use the parallel-parts path.\n * Non-sliceable streams and async iterables fall back to a sequential read\n * path — one part at a time, concurrency forced to 1 — so callers can stream\n * a multi-GB file without buffering the whole payload in memory. The\n * `resumeFileId` requires a sliceable source; deprecated `resume: true`\n * without an explicit file ID is ignored on forward-only sources.\n */\n readonly source: ContentSource\n /** MIME type. Defaults to `b2/x-auto` for server-side detection. */\n readonly contentType?: string\n /** Custom file info key/value pairs stored with the file. */\n readonly fileInfo?: Record<string, string>\n /** Server-side encryption settings applied to each part. */\n readonly serverSideEncryption?: EncryptionSetting\n /** Effective readable bucket default encryption used when serverSideEncryption is omitted. */\n readonly bucketDefaultServerSideEncryption?: BucketDefaultServerSideEncryption\n /** Bucket default encryption exists but cannot be read, so resume must fail closed. */\n readonly bucketDefaultServerSideEncryptionUnreadable?: boolean\n /** File retention policy applied at upload time. */\n readonly fileRetention?: FileRetentionValue\n /** Effective readable bucket default retention used when fileRetention is omitted. */\n readonly bucketDefaultRetention?: BucketDefaultRetention\n /** Bucket default retention exists but cannot be read, so resume must fail closed. */\n readonly bucketDefaultRetentionUnreadable?: boolean\n /** Legal hold status applied at upload time. */\n readonly legalHold?: LegalHoldValue\n /** Override the last-modified timestamp (epoch millis) stored in file info. */\n readonly lastModifiedMillis?: number\n /**\n * B2 upload timestamp override in milliseconds since epoch.\n * Sets the file version `uploadTimestamp`; distinct from `lastModifiedMillis` metadata.\n * Requires B2 account enablement for Custom Upload Timestamp.\n */\n readonly customUploadTimestamp?: number\n /** Size of each part in bytes. Defaults to the account's recommended part size. */\n readonly partSize?: number\n /** Maximum number of parts uploaded in parallel. Defaults to 4. */\n readonly concurrency?: number\n /** Callback invoked with upload progress updates. */\n readonly onProgress?: ProgressListener\n /**\n * Minimum milliseconds between byte-only progress callbacks. Defaults to\n * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.\n * Part-completion progress callbacks are always emitted immediately.\n */\n readonly progressIntervalMillis?: number\n /** Signal to abort the upload. Triggers cancellation of the large file. */\n readonly signal?: AbortSignal\n /**\n * If true, look for an unfinished large file with the same bucket and file name\n * and continue uploading into it. Automatic discovery only reuses unfinished\n * files whose upload options and already-uploaded part lengths match;\n * otherwise a new large file is started. Existing server parts are overwritten\n * with locally read bytes instead of being trusted by SHA-1 alone.\n *\n * Discovery runs before the first upload byte and can make up to the\n * list-page budget plus the candidate budget times the part-page budget in\n * sequential B2 list calls. Pass `resumeDiscoveryTimeoutMs` or an\n * `AbortSignal` to enforce a hard discovery deadline. SSE-C uploads are\n * never auto-resumed because B2 does not expose the customer key identity\n * needed to verify a compatible unfinished file. Candidates with unreadable\n * Object Lock fields are rejected unless the caller provides explicit settings\n * that can be verified. When `customUploadTimestamp` is set, discovery only\n * reuses candidates with the same `uploadTimestamp`; when it is omitted, a\n * reused unfinished file keeps its existing `uploadTimestamp` because B2 does\n * not expose whether that timestamp was custom or server-assigned.\n * `lastModifiedMillis` is part of the file-info identity; unfinished files\n * started by older SDK versions that omitted it can be rejected with\n * `file-info-mismatch`.\n */\n readonly resume?: boolean\n /** Optional aggregate SDK-enforced timeout for resume discovery. */\n readonly resumeDiscoveryTimeoutMs?: number\n /**\n * Maximum `b2_list_unfinished_large_files` pages inspected before upload starts. Defaults to 10.\n * If the scan truncates, resume falls back to a fresh upload and\n * `onResumeCandidateRejected` is the only SDK signal.\n */\n readonly resumeMaxListPages?: number\n /**\n * Maximum metadata-compatible candidates whose parts may be listed before upload starts. Defaults to 25.\n * Hitting the limit can leave older unfinished uploads orphaned while a fresh\n * large file is started; tune for high-churn buckets.\n */\n readonly resumeMaxPartCandidates?: number\n /**\n * Maximum `b2_list_parts` pages inspected per metadata-compatible candidate before upload starts. Defaults to 10.\n * A candidate whose parts exceed this bound is skipped and reported through\n * `onResumeCandidateRejected`.\n */\n readonly resumeMaxPartPages?: number\n /**\n * Explicit large file ID to resume into. Overrides {@link resume} discovery\n * after verifying that the ID belongs to the requested bucket/file name and\n * matches the current upload options and already-uploaded part lengths. This\n * verification also rejects SSE-C uploads because B2 does not expose\n * customer key identity for unfinished files. A mismatch, or a file ID that\n * cannot be verified through B2's unfinished-large-file listing, throws\n * {@link ResumeFileIdMismatchError}. Caller-supplied Object Lock settings are\n * verified when present; when they are omitted, readable current bucket\n * defaults or unreadable Object Lock state still participate in verification.\n */\n readonly resumeFileId?: LargeFileId\n /** Diagnostic callback invoked when resume discovery rejects a candidate. */\n readonly onResumeCandidateRejected?: ResumeCandidateRejectedListener\n /** Diagnostic callback invoked when resume reuses an already-uploaded part. */\n readonly onResumePartReused?: ResumePartReusedListener\n}\n\ninterface StartLargeFileResumeRequest {\n readonly contentType: string\n readonly fileInfo: Record<string, string>\n readonly serverSideEncryption?: EncryptionSetting\n readonly fileRetention?: FileRetentionValue\n readonly legalHold?: LegalHoldValue\n}\n\nfunction createResumeCandidateCriteria(\n options: UploadLargeFileOptions,\n request: StartLargeFileResumeRequest,\n totalSize: number,\n partSize: number,\n parts: readonly RangePlan[],\n): ResumeCandidateCriteria {\n return {\n contentType: request.contentType,\n fileInfo: request.fileInfo,\n sourceSize: totalSize,\n partSize,\n parts,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: options.customUploadTimestamp }\n : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(request.serverSideEncryption !== undefined\n ? { serverSideEncryption: request.serverSideEncryption }\n : options.bucketDefaultServerSideEncryption !== undefined\n ? { serverSideEncryption: options.bucketDefaultServerSideEncryption }\n : options.bucketDefaultServerSideEncryptionUnreadable === true\n ? { defaultServerSideEncryptionUnreadable: true }\n : {}),\n ...(request.fileRetention !== undefined\n ? { fileRetention: request.fileRetention }\n : options.bucketDefaultRetention !== undefined\n ? { defaultFileRetention: options.bucketDefaultRetention }\n : options.bucketDefaultRetentionUnreadable === true\n ? { defaultFileRetentionUnreadable: true }\n : {}),\n ...(request.legalHold !== undefined ? { legalHold: request.legalHold } : {}),\n ...(options.resumeDiscoveryTimeoutMs !== undefined\n ? { discoveryTimeoutMs: options.resumeDiscoveryTimeoutMs }\n : {}),\n ...(options.onResumeCandidateRejected !== undefined\n ? { onCandidateRejected: options.onResumeCandidateRejected }\n : {}),\n ...(options.resumeMaxListPages !== undefined\n ? { maxListPages: options.resumeMaxListPages }\n : {}),\n ...(options.resumeMaxPartCandidates !== undefined\n ? { maxPartCandidates: options.resumeMaxPartCandidates }\n : {}),\n ...(options.resumeMaxPartPages !== undefined\n ? { maxPartPages: options.resumeMaxPartPages }\n : {}),\n }\n}\n\n/**\n * Uploads a file using the B2 multipart (large file) protocol.\n *\n * The source is sliced into parts and uploaded concurrently via\n * `b2_upload_part`. This is appropriate for files larger than the recommended\n * part size. For smaller files, use {@link uploadSmallFile} which sends the\n * entire payload in a single request.\n *\n * On failure, the in-progress large file is cancelled on a best-effort basis.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state (tokens, URLs, upload URL pool).\n * @param options - Upload parameters including part size and concurrency.\n *\n * @returns The resulting {@link FileVersion} metadata.\n */\nexport async function uploadLargeFile(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n): Promise<FileVersion> {\n const recommendedPartSize = accountInfo.getRecommendedPartSize()\n const minPartSize = accountInfo.getAbsoluteMinimumPartSize()\n const partSize = Math.max(options.partSize ?? recommendedPartSize, minPartSize)\n const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY\n const totalSize = options.source.size\n\n const parts = planRanges(totalSize, partSize)\n // Keep caller fileInfo on a null-prototype record so resume identity\n // comparison only sees caller-owned enumerable keys.\n const fileInfo: Record<string, string> = Object.create(null)\n if (options.fileInfo !== undefined) {\n for (const [key, value] of Object.entries(options.fileInfo)) {\n fileInfo[key] = value\n }\n }\n if (options.lastModifiedMillis !== undefined) {\n fileInfo['src_last_modified_millis'] = String(options.lastModifiedMillis)\n }\n\n // Construct the `b2_start_large_file` request body once so the two\n // non-resume branches below (no `resume`, resume-but-no-candidate)\n // can dispatch without re-spelling the conditional spreads.\n const startLargeFileRequest = {\n bucketId: options.bucketId,\n fileName: options.fileName,\n contentType: options.contentType ?? DEFAULT_CONTENT_TYPE,\n fileInfo,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: String(options.customUploadTimestamp) }\n : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.fileRetention !== undefined ? { fileRetention: options.fileRetention } : {}),\n ...(options.legalHold !== undefined ? { legalHold: options.legalHold } : {}),\n }\n const resumeCandidateCriteria = createResumeCandidateCriteria(\n options,\n startLargeFileRequest,\n totalSize,\n partSize,\n parts,\n )\n\n if (!options.source.canSlice && options.resumeFileId !== undefined) {\n throw new Error('uploadLargeFile: resume is not supported on non-sliceable sources.')\n }\n\n // --- Explicit resume file reuse (M11.1) ---\n let largeFileId: LargeFileId | undefined\n let preUploaded: ReadonlyMap<number, string> = new Map()\n let createdLargeFile = false\n let tracker: ProgressTracker | undefined\n const abortScope = createAbortScope(options.signal)\n const startFreshLargeFile = async (): Promise<void> => {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n const startPromise = raw.startLargeFile(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n startLargeFileRequest,\n {\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n )\n try {\n const startResp = await raceWithAbort(startPromise, abortScope.signal)\n largeFileId = startResp.fileId\n } catch (err) {\n if (abortScope.signal.aborted) {\n if (!options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason).catch(() => {})\n }\n cancelLargeFileAfterStart(startPromise, raw, accountInfo, options.onCleanupFailure)\n }\n throw err\n }\n preUploaded = new Map<number, string>()\n createdLargeFile = true\n }\n\n try {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n if (options.resumeFileId !== undefined) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n {\n ...resumeCandidateCriteria,\n resumeFileId: options.resumeFileId,\n },\n )\n if (candidate === null) {\n throw new ResumeFileIdMismatchError(options.resumeFileId, options.fileName)\n }\n largeFileId = candidate.fileId\n preUploaded = candidate.uploadedPartSha1s\n } else if (options.resume === true && options.source.canSlice) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n resumeCandidateCriteria,\n )\n if (candidate) {\n largeFileId = candidate.fileId\n preUploaded = new Map<number, string>()\n } else {\n await startFreshLargeFile()\n }\n } else {\n await startFreshLargeFile()\n }\n const activeLargeFileId = largeFileId\n if (activeLargeFileId === undefined) {\n throw new Error('uploadLargeFile: start did not return a large file ID.')\n }\n\n const partSha1s: string[] = new Array(parts.length)\n const uploadTracker = new ProgressTracker(options.onProgress, totalSize, parts.length, {\n ...(options.progressIntervalMillis !== undefined\n ? { minIntervalMs: options.progressIntervalMillis }\n : {}),\n })\n tracker = uploadTracker\n const sem = new Semaphore(concurrency)\n\n // Non-sliceable sources can't be read in parallel — there's only one\n // forward-only cursor. Resume is also impossible (no seek). Bail to a\n // sequential read loop instead. Each part is buffered, hashed, shipped,\n // then dropped before the next read starts, so the peak memory footprint is\n // ~partSize bytes regardless of total file size.\n if (!options.source.canSlice) {\n await uploadPartsSequentially(\n raw,\n accountInfo,\n options,\n activeLargeFileId,\n parts,\n partSha1s,\n uploadTracker,\n abortScope.signal,\n )\n return await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n }\n\n const tasks = parts.map(async (part) => {\n await sem.acquire()\n try {\n abortScope.signal.throwIfAborted()\n\n const partSource = options.source.slice(part.offset, part.offset + part.length)\n const data = new Uint8Array(await partSource.toArrayBuffer({ signal: abortScope.signal }))\n abortScope.signal.throwIfAborted()\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n abortScope.signal.throwIfAborted()\n\n // Explicit resume is the only mode that trusts an already-uploaded\n // server part enough to skip sending the local bytes again.\n const serverSha1 = preUploaded.get(part.partNumber)\n if (serverSha1 !== undefined && serverSha1 === sha1Hex) {\n notifyResumePartReused(options.onResumePartReused, {\n fileName: options.fileName,\n fileId: activeLargeFileId,\n partNumber: part.partNumber,\n contentLength: data.byteLength,\n contentSha1: serverSha1,\n })\n partSha1s[part.partNumber - 1] = serverSha1\n uploadTracker.addBytes(data.byteLength)\n uploadTracker.completePart()\n return\n }\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, activeLargeFileId, {\n fileName: options.fileName,\n partNumber: part.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal: abortScope.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[part.partNumber - 1] = result.contentSha1\n uploadTracker.addBytes(data.byteLength)\n uploadTracker.completePart()\n } catch (err) {\n abortScope.abort(err)\n throw err\n } finally {\n sem.release()\n }\n })\n\n throwRejectedOrAbortReason(await Promise.allSettled(tasks), abortScope)\n\n const result = await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n\n return result\n } catch (err) {\n abortScope.abort(err)\n if (largeFileId === undefined) throw err\n return await cleanupAfterUploadLargeFileError(\n err,\n raw,\n accountInfo,\n options,\n largeFileId,\n createdLargeFile,\n )\n } finally {\n tracker?.dispose()\n abortScope.dispose()\n }\n}\n\nfunction cancelLargeFileAfterStart(\n started: Promise<{ readonly fileId: LargeFileId }>,\n raw: RawClient,\n accountInfo: AccountInfo,\n onCleanupFailure: CleanupFailureOptions['onCleanupFailure'],\n): void {\n void started\n .then((resp) =>\n cancelLargeFileBestEffort(\n raw,\n accountInfo,\n resp.fileId,\n onCleanupFailure === undefined ? undefined : { onCleanupFailure },\n ),\n )\n .catch(() => {\n // If start failed, no file ID is available to cancel.\n })\n}\n\nasync function cleanupAfterUploadLargeFileError(\n err: unknown,\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n createdLargeFile: boolean,\n): Promise<never> {\n return await cleanupAfterLargeFileError(\n err,\n raw,\n accountInfo,\n {\n fileId: largeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n signal: options.signal,\n onCleanupFailure: options.onCleanupFailure,\n },\n { cancelOnError: createdLargeFile },\n )\n}\n\n/**\n * Sequential upload path for non-sliceable sources.\n *\n * Reads the source's `stream()` once and accumulates exactly `partSize`\n * bytes into an in-memory buffer per iteration. Each filled buffer is\n * hashed, dispatched to `b2_upload_part`, then released before the next\n * part starts — so peak memory is ~partSize regardless of file size.\n *\n * Concurrency is forced to 1 here because the stream is a single\n * forward-only cursor; the engine can't read part N+1 until part N is\n * fully consumed.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - The original `uploadLargeFile` options.\n * @param largeFileId - ID of the in-progress large file (already started).\n * @param parts - Pre-planned part layout (used for part numbers + count).\n * @param partSha1s - Output array, written in-place at index `partNumber - 1`.\n * @param tracker - Progress tracker; bytes added per chunk, part completed\n * each time a part finishes.\n * @param signal - Linked abort signal for source reads and part uploads.\n */\nasync function uploadPartsSequentially(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n parts: readonly RangePlan[],\n partSha1s: string[],\n tracker: ProgressTracker,\n signal: AbortSignal,\n): Promise<void> {\n const reader = options.source.stream().getReader()\n let bytesRead = 0\n // Carry-over bytes from a previous read when the read returned more\n // than we needed to fill one part. Kept as an array to avoid an\n // allocation per loop iteration on a typical multi-part upload.\n let carry: Uint8Array | null = null\n\n try {\n for (const planned of parts) {\n signal.throwIfAborted()\n\n const buf = new Uint8Array(planned.length)\n let filled = 0\n\n if (carry !== null) {\n const take = Math.min(carry.byteLength, buf.byteLength - filled)\n buf.set(carry.subarray(0, take), filled)\n filled += take\n carry = take < carry.byteLength ? carry.subarray(take) : null\n }\n\n while (filled < buf.byteLength) {\n const { done, value } = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (done) {\n throw new Error(\n `uploadLargeFile: source stream ended after ${bytesRead} bytes, expected ${options.source.size}.`,\n )\n }\n bytesRead += value.byteLength\n const take = Math.min(value.byteLength, buf.byteLength - filled)\n buf.set(value.subarray(0, take), filled)\n filled += take\n if (take < value.byteLength) {\n carry = value.subarray(take)\n }\n }\n\n signal.throwIfAborted()\n const data = buf\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n signal.throwIfAborted()\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, largeFileId, {\n fileName: options.fileName,\n partNumber: planned.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[planned.partNumber - 1] = result.contentSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n }\n if (carry !== null && carry.byteLength > 0) {\n throw new Error(tooManyBytesError(options.source.size))\n }\n const extra = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (!extra.done) {\n bytesRead += extra.value.byteLength\n throw new Error(tooManyBytesError(options.source.size))\n }\n } catch (err) {\n await reader.cancel(err).catch(() => {})\n throw err\n } finally {\n // Releasing the lock lets the underlying stream propagate close / error\n // events to any upstream producer (e.g. a Node `Readable`).\n reader.releaseLock()\n }\n}\n\nfunction emptyChunkError(): string {\n return `uploadLargeFile: source stream emitted more than ${MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS} consecutive empty chunks. too many empty chunks.`\n}\n\nfunction tooManyBytesError(advertisedSize: number): string {\n return `uploadLargeFile: source stream emitted more than advertised ${advertisedSize} bytes. source stream emitted more bytes than advertised size.`\n}\n\nasync function cancelForwardOnlySource(source: ContentSource, reason: unknown): Promise<void> {\n const reader = source.stream().getReader()\n try {\n await reader.cancel(reason)\n } finally {\n reader.releaseLock()\n }\n}\n\nfunction notifyResumePartReused(\n listener: ResumePartReusedListener | undefined,\n event: ResumePartReusedEvent,\n): void {\n try {\n listener?.(event)\n } catch {\n // Diagnostic observers must not change upload success or failure.\n }\n}\n"],"mappings":"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"}
|
package/dist/upload/large.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { AccountInfo } from '../auth/account-info.js';
|
|
|
2
2
|
import { RawClient } from '../raw/index.js';
|
|
3
3
|
import { ProgressListener } from '../streams/progress.js';
|
|
4
4
|
import { ContentSource } from '../streams/source.js';
|
|
5
|
-
import {
|
|
5
|
+
import { BucketDefaultRetention, BucketDefaultServerSideEncryption } from '../types/bucket.js';
|
|
6
6
|
import { EncryptionSetting } from '../types/encryption.js';
|
|
7
7
|
import { FileVersion } from '../types/file.js';
|
|
8
8
|
import { BucketId, LargeFileId } from '../types/ids.js';
|
|
@@ -47,12 +47,14 @@ export interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailu
|
|
|
47
47
|
readonly fileInfo?: Record<string, string>;
|
|
48
48
|
/** Server-side encryption settings applied to each part. */
|
|
49
49
|
readonly serverSideEncryption?: EncryptionSetting;
|
|
50
|
-
/** Effective bucket default encryption used when serverSideEncryption is omitted. */
|
|
51
|
-
readonly bucketDefaultServerSideEncryption?:
|
|
50
|
+
/** Effective readable bucket default encryption used when serverSideEncryption is omitted. */
|
|
51
|
+
readonly bucketDefaultServerSideEncryption?: BucketDefaultServerSideEncryption;
|
|
52
|
+
/** Bucket default encryption exists but cannot be read, so resume must fail closed. */
|
|
53
|
+
readonly bucketDefaultServerSideEncryptionUnreadable?: boolean;
|
|
52
54
|
/** File retention policy applied at upload time. */
|
|
53
55
|
readonly fileRetention?: FileRetentionValue;
|
|
54
56
|
/** Effective readable bucket default retention used when fileRetention is omitted. */
|
|
55
|
-
readonly bucketDefaultRetention?:
|
|
57
|
+
readonly bucketDefaultRetention?: BucketDefaultRetention;
|
|
56
58
|
/** Bucket default retention exists but cannot be read, so resume must fail closed. */
|
|
57
59
|
readonly bucketDefaultRetentionUnreadable?: boolean;
|
|
58
60
|
/** Legal hold status applied at upload time. */
|
|
@@ -71,6 +73,12 @@ export interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailu
|
|
|
71
73
|
readonly concurrency?: number;
|
|
72
74
|
/** Callback invoked with upload progress updates. */
|
|
73
75
|
readonly onProgress?: ProgressListener;
|
|
76
|
+
/**
|
|
77
|
+
* Minimum milliseconds between byte-only progress callbacks. Defaults to
|
|
78
|
+
* the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.
|
|
79
|
+
* Part-completion progress callbacks are always emitted immediately.
|
|
80
|
+
*/
|
|
81
|
+
readonly progressIntervalMillis?: number;
|
|
74
82
|
/** Signal to abort the upload. Triggers cancellation of the large file. */
|
|
75
83
|
readonly signal?: AbortSignal;
|
|
76
84
|
/**
|
|
@@ -123,8 +131,9 @@ export interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailu
|
|
|
123
131
|
* verification also rejects SSE-C uploads because B2 does not expose
|
|
124
132
|
* customer key identity for unfinished files. A mismatch, or a file ID that
|
|
125
133
|
* cannot be verified through B2's unfinished-large-file listing, throws
|
|
126
|
-
* {@link ResumeFileIdMismatchError}.
|
|
127
|
-
*
|
|
134
|
+
* {@link ResumeFileIdMismatchError}. Caller-supplied Object Lock settings are
|
|
135
|
+
* verified when present; when they are omitted, readable current bucket
|
|
136
|
+
* defaults or unreadable Object Lock state still participate in verification.
|
|
128
137
|
*/
|
|
129
138
|
readonly resumeFileId?: LargeFileId;
|
|
130
139
|
/** Diagnostic callback invoked when resume discovery rejects a candidate. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"large.d.ts","sourceRoot":"","sources":["../../src/upload/large.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,sBAAsB,CAAA;AACtF,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"large.d.ts","sourceRoot":"","sources":["../../src/upload/large.js"],"names":[],"mappings":"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"}
|
package/dist/upload/large.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { AccountInfo } from '../auth/account-info.js';
|
|
|
2
2
|
import { RawClient } from '../raw/index.js';
|
|
3
3
|
import { ProgressListener } from '../streams/progress.js';
|
|
4
4
|
import { ContentSource } from '../streams/source.js';
|
|
5
|
-
import {
|
|
5
|
+
import { BucketDefaultRetention, BucketDefaultServerSideEncryption } from '../types/bucket.js';
|
|
6
6
|
import { EncryptionSetting } from '../types/encryption.js';
|
|
7
7
|
import { FileVersion } from '../types/file.js';
|
|
8
8
|
import { BucketId, LargeFileId } from '../types/ids.js';
|
|
@@ -47,12 +47,14 @@ export interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailu
|
|
|
47
47
|
readonly fileInfo?: Record<string, string>;
|
|
48
48
|
/** Server-side encryption settings applied to each part. */
|
|
49
49
|
readonly serverSideEncryption?: EncryptionSetting;
|
|
50
|
-
/** Effective bucket default encryption used when serverSideEncryption is omitted. */
|
|
51
|
-
readonly bucketDefaultServerSideEncryption?:
|
|
50
|
+
/** Effective readable bucket default encryption used when serverSideEncryption is omitted. */
|
|
51
|
+
readonly bucketDefaultServerSideEncryption?: BucketDefaultServerSideEncryption;
|
|
52
|
+
/** Bucket default encryption exists but cannot be read, so resume must fail closed. */
|
|
53
|
+
readonly bucketDefaultServerSideEncryptionUnreadable?: boolean;
|
|
52
54
|
/** File retention policy applied at upload time. */
|
|
53
55
|
readonly fileRetention?: FileRetentionValue;
|
|
54
56
|
/** Effective readable bucket default retention used when fileRetention is omitted. */
|
|
55
|
-
readonly bucketDefaultRetention?:
|
|
57
|
+
readonly bucketDefaultRetention?: BucketDefaultRetention;
|
|
56
58
|
/** Bucket default retention exists but cannot be read, so resume must fail closed. */
|
|
57
59
|
readonly bucketDefaultRetentionUnreadable?: boolean;
|
|
58
60
|
/** Legal hold status applied at upload time. */
|
|
@@ -71,6 +73,12 @@ export interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailu
|
|
|
71
73
|
readonly concurrency?: number;
|
|
72
74
|
/** Callback invoked with upload progress updates. */
|
|
73
75
|
readonly onProgress?: ProgressListener;
|
|
76
|
+
/**
|
|
77
|
+
* Minimum milliseconds between byte-only progress callbacks. Defaults to
|
|
78
|
+
* the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.
|
|
79
|
+
* Part-completion progress callbacks are always emitted immediately.
|
|
80
|
+
*/
|
|
81
|
+
readonly progressIntervalMillis?: number;
|
|
74
82
|
/** Signal to abort the upload. Triggers cancellation of the large file. */
|
|
75
83
|
readonly signal?: AbortSignal;
|
|
76
84
|
/**
|
|
@@ -123,8 +131,9 @@ export interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailu
|
|
|
123
131
|
* verification also rejects SSE-C uploads because B2 does not expose
|
|
124
132
|
* customer key identity for unfinished files. A mismatch, or a file ID that
|
|
125
133
|
* cannot be verified through B2's unfinished-large-file listing, throws
|
|
126
|
-
* {@link ResumeFileIdMismatchError}.
|
|
127
|
-
*
|
|
134
|
+
* {@link ResumeFileIdMismatchError}. Caller-supplied Object Lock settings are
|
|
135
|
+
* verified when present; when they are omitted, readable current bucket
|
|
136
|
+
* defaults or unreadable Object Lock state still participate in verification.
|
|
128
137
|
*/
|
|
129
138
|
readonly resumeFileId?: LargeFileId;
|
|
130
139
|
/** Diagnostic callback invoked when resume discovery rejects a candidate. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"large.d.ts","sourceRoot":"","sources":["../../src/upload/large.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,sBAAsB,CAAA;AACtF,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"large.d.ts","sourceRoot":"","sources":["../../src/upload/large.js"],"names":[],"mappings":"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"}
|
package/dist/upload/large.js
CHANGED
|
@@ -22,7 +22,7 @@ function createResumeCandidateCriteria(options, request, totalSize, partSize, pa
|
|
|
22
22
|
parts,
|
|
23
23
|
...options.customUploadTimestamp !== void 0 ? { customUploadTimestamp: options.customUploadTimestamp } : {},
|
|
24
24
|
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
25
|
-
...request.serverSideEncryption !== void 0 ? { serverSideEncryption: request.serverSideEncryption } : options.bucketDefaultServerSideEncryption !== void 0 ? { serverSideEncryption: options.bucketDefaultServerSideEncryption } : {},
|
|
25
|
+
...request.serverSideEncryption !== void 0 ? { serverSideEncryption: request.serverSideEncryption } : options.bucketDefaultServerSideEncryption !== void 0 ? { serverSideEncryption: options.bucketDefaultServerSideEncryption } : options.bucketDefaultServerSideEncryptionUnreadable === true ? { defaultServerSideEncryptionUnreadable: true } : {},
|
|
26
26
|
...request.fileRetention !== void 0 ? { fileRetention: request.fileRetention } : options.bucketDefaultRetention !== void 0 ? { defaultFileRetention: options.bucketDefaultRetention } : options.bucketDefaultRetentionUnreadable === true ? { defaultFileRetentionUnreadable: true } : {},
|
|
27
27
|
...request.legalHold !== void 0 ? { legalHold: request.legalHold } : {},
|
|
28
28
|
...options.resumeDiscoveryTimeoutMs !== void 0 ? { discoveryTimeoutMs: options.resumeDiscoveryTimeoutMs } : {},
|
|
@@ -73,6 +73,7 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
73
73
|
let largeFileId;
|
|
74
74
|
let preUploaded = /* @__PURE__ */ new Map();
|
|
75
75
|
let createdLargeFile = false;
|
|
76
|
+
let tracker;
|
|
76
77
|
const abortScope = createAbortScope(options.signal);
|
|
77
78
|
const startFreshLargeFile = async () => {
|
|
78
79
|
if (abortScope.signal.aborted && !options.source.canSlice) await cancelForwardOnlySource(options.source, abortScope.signal.reason);
|
|
@@ -114,10 +115,11 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
114
115
|
const activeLargeFileId = largeFileId;
|
|
115
116
|
if (activeLargeFileId === void 0) throw new Error("uploadLargeFile: start did not return a large file ID.");
|
|
116
117
|
const partSha1s = new Array(parts.length);
|
|
117
|
-
const
|
|
118
|
+
const uploadTracker = new ProgressTracker(options.onProgress, totalSize, parts.length, { ...options.progressIntervalMillis !== void 0 ? { minIntervalMs: options.progressIntervalMillis } : {} });
|
|
119
|
+
tracker = uploadTracker;
|
|
118
120
|
const sem = new Semaphore(concurrency);
|
|
119
121
|
if (!options.source.canSlice) {
|
|
120
|
-
await uploadPartsSequentially(raw, accountInfo, options, activeLargeFileId, parts, partSha1s,
|
|
122
|
+
await uploadPartsSequentially(raw, accountInfo, options, activeLargeFileId, parts, partSha1s, uploadTracker, abortScope.signal);
|
|
121
123
|
return await finishLargeFileWithAbortReconciliation(raw, accountInfo, {
|
|
122
124
|
fileId: activeLargeFileId,
|
|
123
125
|
bucketId: options.bucketId,
|
|
@@ -148,8 +150,8 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
148
150
|
contentSha1: serverSha1
|
|
149
151
|
});
|
|
150
152
|
partSha1s[part.partNumber - 1] = serverSha1;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
uploadTracker.addBytes(data.byteLength);
|
|
154
|
+
uploadTracker.completePart();
|
|
153
155
|
return;
|
|
154
156
|
}
|
|
155
157
|
const result = await uploadPartWithFreshUrl(raw, accountInfo, activeLargeFileId, {
|
|
@@ -165,8 +167,8 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
165
167
|
...options.serverSideEncryption !== void 0 ? { serverSideEncryption: options.serverSideEncryption } : {}
|
|
166
168
|
});
|
|
167
169
|
partSha1s[part.partNumber - 1] = result.contentSha1;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
uploadTracker.addBytes(data.byteLength);
|
|
171
|
+
uploadTracker.completePart();
|
|
170
172
|
} catch (err) {
|
|
171
173
|
abortScope.abort(err);
|
|
172
174
|
throw err;
|
|
@@ -188,6 +190,7 @@ async function uploadLargeFile(raw, accountInfo, options) {
|
|
|
188
190
|
if (largeFileId === void 0) throw err;
|
|
189
191
|
return await cleanupAfterUploadLargeFileError(err, raw, accountInfo, options, largeFileId, createdLargeFile);
|
|
190
192
|
} finally {
|
|
193
|
+
tracker?.dispose();
|
|
191
194
|
abortScope.dispose();
|
|
192
195
|
}
|
|
193
196
|
}
|
package/dist/upload/large.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"large.js","names":[],"sources":["../../src/upload/large.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport type { ProgressListener } from '../streams/progress.ts'\nimport { ProgressTracker } from '../streams/progress.ts'\nimport { type ContentSource, readNextNonEmptyStreamChunk } from '../streams/source.ts'\nimport type { BucketRetentionPolicy } from '../types/bucket.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { FileVersion } from '../types/file.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport { raceWithAbort } from '../util/abort.ts'\nimport { DEFAULT_CONTENT_TYPE, DEFAULT_TRANSFER_CONCURRENCY } from '../util/defaults.ts'\nimport { planRanges, type RangePlan } from '../util/plan-ranges.ts'\nimport { createAbortScope, throwRejectedOrAbortReason } from './abort-scope.ts'\nimport {\n type CleanupFailureOptions,\n cancelLargeFileBestEffort,\n cleanupAfterLargeFileError,\n} from './cancel.ts'\nimport { Semaphore } from './concurrency.ts'\nimport { finishLargeFileWithAbortReconciliation } from './finish.ts'\nimport {\n findResumeCandidate,\n type ResumeCandidateCriteria,\n type ResumeCandidateRejectedListener,\n ResumeFileIdMismatchError,\n} from './resume.ts'\nimport {\n resolveRetryResponseBodyFailures,\n type UploadRetryOptions,\n uploadPartWithFreshUrl,\n} from './retry.ts'\n\n/** Event emitted when explicit resume skips a local part because B2 already has matching SHA-1 bytes. */\nexport interface ResumePartReusedEvent {\n /** File name being resumed. */\n readonly fileName: string\n /** Unfinished large-file ID that supplied the existing part. */\n readonly fileId: LargeFileId\n /** One-based part number reused from the unfinished large file. */\n readonly partNumber: number\n /** Number of bytes in the reused part. */\n readonly contentLength: number\n /** SHA-1 hex digest that matched the local part bytes. */\n readonly contentSha1: string\n}\n\n/** Callback invoked when explicit resume accepts a pre-existing server part. */\nexport type ResumePartReusedListener = (event: ResumePartReusedEvent) => void\n\nconst MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS = 1024\n\n/** Options for uploading a large file via the multipart protocol. */\nexport interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailureOptions {\n /** Target bucket for the upload. */\n readonly bucketId: BucketId\n /** Full B2 file name including any path prefix. */\n readonly fileName: string\n /**\n * Content to upload. Sliceable sources ({@link BufferSource},\n * {@link BlobSource}, {@link FileSource}) use the parallel-parts path.\n * Non-sliceable streams and async iterables fall back to a sequential read\n * path — one part at a time, concurrency forced to 1 — so callers can stream\n * a multi-GB file without buffering the whole payload in memory. The\n * `resumeFileId` requires a sliceable source; deprecated `resume: true`\n * without an explicit file ID is ignored on forward-only sources.\n */\n readonly source: ContentSource\n /** MIME type. Defaults to `b2/x-auto` for server-side detection. */\n readonly contentType?: string\n /** Custom file info key/value pairs stored with the file. */\n readonly fileInfo?: Record<string, string>\n /** Server-side encryption settings applied to each part. */\n readonly serverSideEncryption?: EncryptionSetting\n /** Effective bucket default encryption used when serverSideEncryption is omitted. */\n readonly bucketDefaultServerSideEncryption?: EncryptionSetting\n /** File retention policy applied at upload time. */\n readonly fileRetention?: FileRetentionValue\n /** Effective readable bucket default retention used when fileRetention is omitted. */\n readonly bucketDefaultRetention?: BucketRetentionPolicy\n /** Bucket default retention exists but cannot be read, so resume must fail closed. */\n readonly bucketDefaultRetentionUnreadable?: boolean\n /** Legal hold status applied at upload time. */\n readonly legalHold?: LegalHoldValue\n /** Override the last-modified timestamp (epoch millis) stored in file info. */\n readonly lastModifiedMillis?: number\n /**\n * B2 upload timestamp override in milliseconds since epoch.\n * Sets the file version `uploadTimestamp`; distinct from `lastModifiedMillis` metadata.\n * Requires B2 account enablement for Custom Upload Timestamp.\n */\n readonly customUploadTimestamp?: number\n /** Size of each part in bytes. Defaults to the account's recommended part size. */\n readonly partSize?: number\n /** Maximum number of parts uploaded in parallel. Defaults to 4. */\n readonly concurrency?: number\n /** Callback invoked with upload progress updates. */\n readonly onProgress?: ProgressListener\n /** Signal to abort the upload. Triggers cancellation of the large file. */\n readonly signal?: AbortSignal\n /**\n * If true, look for an unfinished large file with the same bucket and file name\n * and continue uploading into it. Automatic discovery only reuses unfinished\n * files whose upload options and already-uploaded part lengths match;\n * otherwise a new large file is started. Existing server parts are overwritten\n * with locally read bytes instead of being trusted by SHA-1 alone.\n *\n * Discovery runs before the first upload byte and can make up to the\n * list-page budget plus the candidate budget times the part-page budget in\n * sequential B2 list calls. Pass `resumeDiscoveryTimeoutMs` or an\n * `AbortSignal` to enforce a hard discovery deadline. SSE-C uploads are\n * never auto-resumed because B2 does not expose the customer key identity\n * needed to verify a compatible unfinished file. Candidates with unreadable\n * Object Lock fields are rejected unless the caller provides explicit settings\n * that can be verified. When `customUploadTimestamp` is set, discovery only\n * reuses candidates with the same `uploadTimestamp`; when it is omitted, a\n * reused unfinished file keeps its existing `uploadTimestamp` because B2 does\n * not expose whether that timestamp was custom or server-assigned.\n * `lastModifiedMillis` is part of the file-info identity; unfinished files\n * started by older SDK versions that omitted it can be rejected with\n * `file-info-mismatch`.\n */\n readonly resume?: boolean\n /** Optional aggregate SDK-enforced timeout for resume discovery. */\n readonly resumeDiscoveryTimeoutMs?: number\n /**\n * Maximum `b2_list_unfinished_large_files` pages inspected before upload starts. Defaults to 10.\n * If the scan truncates, resume falls back to a fresh upload and\n * `onResumeCandidateRejected` is the only SDK signal.\n */\n readonly resumeMaxListPages?: number\n /**\n * Maximum metadata-compatible candidates whose parts may be listed before upload starts. Defaults to 25.\n * Hitting the limit can leave older unfinished uploads orphaned while a fresh\n * large file is started; tune for high-churn buckets.\n */\n readonly resumeMaxPartCandidates?: number\n /**\n * Maximum `b2_list_parts` pages inspected per metadata-compatible candidate before upload starts. Defaults to 10.\n * A candidate whose parts exceed this bound is skipped and reported through\n * `onResumeCandidateRejected`.\n */\n readonly resumeMaxPartPages?: number\n /**\n * Explicit large file ID to resume into. Overrides {@link resume} discovery\n * after verifying that the ID belongs to the requested bucket/file name and\n * matches the current upload options and already-uploaded part lengths. This\n * verification also rejects SSE-C uploads because B2 does not expose\n * customer key identity for unfinished files. A mismatch, or a file ID that\n * cannot be verified through B2's unfinished-large-file listing, throws\n * {@link ResumeFileIdMismatchError}. Unreadable Object Lock fields reject\n * the candidate.\n */\n readonly resumeFileId?: LargeFileId\n /** Diagnostic callback invoked when resume discovery rejects a candidate. */\n readonly onResumeCandidateRejected?: ResumeCandidateRejectedListener\n /** Diagnostic callback invoked when resume reuses an already-uploaded part. */\n readonly onResumePartReused?: ResumePartReusedListener\n}\n\ninterface StartLargeFileResumeRequest {\n readonly contentType: string\n readonly fileInfo: Record<string, string>\n readonly serverSideEncryption?: EncryptionSetting\n readonly fileRetention?: FileRetentionValue\n readonly legalHold?: LegalHoldValue\n}\n\nfunction createResumeCandidateCriteria(\n options: UploadLargeFileOptions,\n request: StartLargeFileResumeRequest,\n totalSize: number,\n partSize: number,\n parts: readonly RangePlan[],\n): ResumeCandidateCriteria {\n return {\n contentType: request.contentType,\n fileInfo: request.fileInfo,\n sourceSize: totalSize,\n partSize,\n parts,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: options.customUploadTimestamp }\n : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(request.serverSideEncryption !== undefined\n ? { serverSideEncryption: request.serverSideEncryption }\n : options.bucketDefaultServerSideEncryption !== undefined\n ? { serverSideEncryption: options.bucketDefaultServerSideEncryption }\n : {}),\n ...(request.fileRetention !== undefined\n ? { fileRetention: request.fileRetention }\n : options.bucketDefaultRetention !== undefined\n ? { defaultFileRetention: options.bucketDefaultRetention }\n : options.bucketDefaultRetentionUnreadable === true\n ? { defaultFileRetentionUnreadable: true }\n : {}),\n ...(request.legalHold !== undefined ? { legalHold: request.legalHold } : {}),\n ...(options.resumeDiscoveryTimeoutMs !== undefined\n ? { discoveryTimeoutMs: options.resumeDiscoveryTimeoutMs }\n : {}),\n ...(options.onResumeCandidateRejected !== undefined\n ? { onCandidateRejected: options.onResumeCandidateRejected }\n : {}),\n ...(options.resumeMaxListPages !== undefined\n ? { maxListPages: options.resumeMaxListPages }\n : {}),\n ...(options.resumeMaxPartCandidates !== undefined\n ? { maxPartCandidates: options.resumeMaxPartCandidates }\n : {}),\n ...(options.resumeMaxPartPages !== undefined\n ? { maxPartPages: options.resumeMaxPartPages }\n : {}),\n }\n}\n\n/**\n * Uploads a file using the B2 multipart (large file) protocol.\n *\n * The source is sliced into parts and uploaded concurrently via\n * `b2_upload_part`. This is appropriate for files larger than the recommended\n * part size. For smaller files, use {@link uploadSmallFile} which sends the\n * entire payload in a single request.\n *\n * On failure, the in-progress large file is cancelled on a best-effort basis.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state (tokens, URLs, upload URL pool).\n * @param options - Upload parameters including part size and concurrency.\n *\n * @returns The resulting {@link FileVersion} metadata.\n */\nexport async function uploadLargeFile(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n): Promise<FileVersion> {\n const recommendedPartSize = accountInfo.getRecommendedPartSize()\n const minPartSize = accountInfo.getAbsoluteMinimumPartSize()\n const partSize = Math.max(options.partSize ?? recommendedPartSize, minPartSize)\n const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY\n const totalSize = options.source.size\n\n const parts = planRanges(totalSize, partSize)\n // Keep caller fileInfo on a null-prototype record so resume identity\n // comparison only sees caller-owned enumerable keys.\n const fileInfo: Record<string, string> = Object.create(null)\n if (options.fileInfo !== undefined) {\n for (const [key, value] of Object.entries(options.fileInfo)) {\n fileInfo[key] = value\n }\n }\n if (options.lastModifiedMillis !== undefined) {\n fileInfo['src_last_modified_millis'] = String(options.lastModifiedMillis)\n }\n\n // Construct the `b2_start_large_file` request body once so the two\n // non-resume branches below (no `resume`, resume-but-no-candidate)\n // can dispatch without re-spelling the conditional spreads.\n const startLargeFileRequest = {\n bucketId: options.bucketId,\n fileName: options.fileName,\n contentType: options.contentType ?? DEFAULT_CONTENT_TYPE,\n fileInfo,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: String(options.customUploadTimestamp) }\n : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.fileRetention !== undefined ? { fileRetention: options.fileRetention } : {}),\n ...(options.legalHold !== undefined ? { legalHold: options.legalHold } : {}),\n }\n const resumeCandidateCriteria = createResumeCandidateCriteria(\n options,\n startLargeFileRequest,\n totalSize,\n partSize,\n parts,\n )\n\n if (!options.source.canSlice && options.resumeFileId !== undefined) {\n throw new Error('uploadLargeFile: resume is not supported on non-sliceable sources.')\n }\n\n // --- Explicit resume file reuse (M11.1) ---\n let largeFileId: LargeFileId | undefined\n let preUploaded: ReadonlyMap<number, string> = new Map()\n let createdLargeFile = false\n const abortScope = createAbortScope(options.signal)\n const startFreshLargeFile = async (): Promise<void> => {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n const startPromise = raw.startLargeFile(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n startLargeFileRequest,\n {\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n )\n try {\n const startResp = await raceWithAbort(startPromise, abortScope.signal)\n largeFileId = startResp.fileId\n } catch (err) {\n if (abortScope.signal.aborted) {\n if (!options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason).catch(() => {})\n }\n cancelLargeFileAfterStart(startPromise, raw, accountInfo, options.onCleanupFailure)\n }\n throw err\n }\n preUploaded = new Map<number, string>()\n createdLargeFile = true\n }\n\n try {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n if (options.resumeFileId !== undefined) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n {\n ...resumeCandidateCriteria,\n resumeFileId: options.resumeFileId,\n },\n )\n if (candidate === null) {\n throw new ResumeFileIdMismatchError(options.resumeFileId, options.fileName)\n }\n largeFileId = candidate.fileId\n preUploaded = candidate.uploadedPartSha1s\n } else if (options.resume === true && options.source.canSlice) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n resumeCandidateCriteria,\n )\n if (candidate) {\n largeFileId = candidate.fileId\n preUploaded = new Map<number, string>()\n } else {\n await startFreshLargeFile()\n }\n } else {\n await startFreshLargeFile()\n }\n const activeLargeFileId = largeFileId\n if (activeLargeFileId === undefined) {\n throw new Error('uploadLargeFile: start did not return a large file ID.')\n }\n\n const partSha1s: string[] = new Array(parts.length)\n const tracker = new ProgressTracker(options.onProgress, totalSize, parts.length)\n const sem = new Semaphore(concurrency)\n\n // Non-sliceable sources can't be read in parallel — there's only one\n // forward-only cursor. Resume is also impossible (no seek). Bail to a\n // sequential read loop instead. Each part is buffered, hashed, shipped,\n // then dropped before the next read starts, so the peak memory footprint is\n // ~partSize bytes regardless of total file size.\n if (!options.source.canSlice) {\n await uploadPartsSequentially(\n raw,\n accountInfo,\n options,\n activeLargeFileId,\n parts,\n partSha1s,\n tracker,\n abortScope.signal,\n )\n return await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n }\n\n const tasks = parts.map(async (part) => {\n await sem.acquire()\n try {\n abortScope.signal.throwIfAborted()\n\n const partSource = options.source.slice(part.offset, part.offset + part.length)\n const data = new Uint8Array(await partSource.toArrayBuffer({ signal: abortScope.signal }))\n abortScope.signal.throwIfAborted()\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n abortScope.signal.throwIfAborted()\n\n // Explicit resume is the only mode that trusts an already-uploaded\n // server part enough to skip sending the local bytes again.\n const serverSha1 = preUploaded.get(part.partNumber)\n if (serverSha1 !== undefined && serverSha1 === sha1Hex) {\n notifyResumePartReused(options.onResumePartReused, {\n fileName: options.fileName,\n fileId: activeLargeFileId,\n partNumber: part.partNumber,\n contentLength: data.byteLength,\n contentSha1: serverSha1,\n })\n partSha1s[part.partNumber - 1] = serverSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n return\n }\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, activeLargeFileId, {\n fileName: options.fileName,\n partNumber: part.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal: abortScope.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[part.partNumber - 1] = result.contentSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n } catch (err) {\n abortScope.abort(err)\n throw err\n } finally {\n sem.release()\n }\n })\n\n throwRejectedOrAbortReason(await Promise.allSettled(tasks), abortScope)\n\n const result = await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n\n return result\n } catch (err) {\n abortScope.abort(err)\n if (largeFileId === undefined) throw err\n return await cleanupAfterUploadLargeFileError(\n err,\n raw,\n accountInfo,\n options,\n largeFileId,\n createdLargeFile,\n )\n } finally {\n abortScope.dispose()\n }\n}\n\nfunction cancelLargeFileAfterStart(\n started: Promise<{ readonly fileId: LargeFileId }>,\n raw: RawClient,\n accountInfo: AccountInfo,\n onCleanupFailure: CleanupFailureOptions['onCleanupFailure'],\n): void {\n void started\n .then((resp) =>\n cancelLargeFileBestEffort(\n raw,\n accountInfo,\n resp.fileId,\n onCleanupFailure === undefined ? undefined : { onCleanupFailure },\n ),\n )\n .catch(() => {\n // If start failed, no file ID is available to cancel.\n })\n}\n\nasync function cleanupAfterUploadLargeFileError(\n err: unknown,\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n createdLargeFile: boolean,\n): Promise<never> {\n return await cleanupAfterLargeFileError(\n err,\n raw,\n accountInfo,\n {\n fileId: largeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n signal: options.signal,\n onCleanupFailure: options.onCleanupFailure,\n },\n { cancelOnError: createdLargeFile },\n )\n}\n\n/**\n * Sequential upload path for non-sliceable sources.\n *\n * Reads the source's `stream()` once and accumulates exactly `partSize`\n * bytes into an in-memory buffer per iteration. Each filled buffer is\n * hashed, dispatched to `b2_upload_part`, then released before the next\n * part starts — so peak memory is ~partSize regardless of file size.\n *\n * Concurrency is forced to 1 here because the stream is a single\n * forward-only cursor; the engine can't read part N+1 until part N is\n * fully consumed.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - The original `uploadLargeFile` options.\n * @param largeFileId - ID of the in-progress large file (already started).\n * @param parts - Pre-planned part layout (used for part numbers + count).\n * @param partSha1s - Output array, written in-place at index `partNumber - 1`.\n * @param tracker - Progress tracker; bytes added per chunk, part completed\n * each time a part finishes.\n * @param signal - Linked abort signal for source reads and part uploads.\n */\nasync function uploadPartsSequentially(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n parts: readonly RangePlan[],\n partSha1s: string[],\n tracker: ProgressTracker,\n signal: AbortSignal,\n): Promise<void> {\n const reader = options.source.stream().getReader()\n let bytesRead = 0\n // Carry-over bytes from a previous read when the read returned more\n // than we needed to fill one part. Kept as an array to avoid an\n // allocation per loop iteration on a typical multi-part upload.\n let carry: Uint8Array | null = null\n\n try {\n for (const planned of parts) {\n signal.throwIfAborted()\n\n const buf = new Uint8Array(planned.length)\n let filled = 0\n\n if (carry !== null) {\n const take = Math.min(carry.byteLength, buf.byteLength - filled)\n buf.set(carry.subarray(0, take), filled)\n filled += take\n carry = take < carry.byteLength ? carry.subarray(take) : null\n }\n\n while (filled < buf.byteLength) {\n const { done, value } = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (done) {\n throw new Error(\n `uploadLargeFile: source stream ended after ${bytesRead} bytes, expected ${options.source.size}.`,\n )\n }\n bytesRead += value.byteLength\n const take = Math.min(value.byteLength, buf.byteLength - filled)\n buf.set(value.subarray(0, take), filled)\n filled += take\n if (take < value.byteLength) {\n carry = value.subarray(take)\n }\n }\n\n signal.throwIfAborted()\n const data = buf\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n signal.throwIfAborted()\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, largeFileId, {\n fileName: options.fileName,\n partNumber: planned.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[planned.partNumber - 1] = result.contentSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n }\n if (carry !== null && carry.byteLength > 0) {\n throw new Error(tooManyBytesError(options.source.size))\n }\n const extra = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (!extra.done) {\n bytesRead += extra.value.byteLength\n throw new Error(tooManyBytesError(options.source.size))\n }\n } catch (err) {\n await reader.cancel(err).catch(() => {})\n throw err\n } finally {\n // Releasing the lock lets the underlying stream propagate close / error\n // events to any upstream producer (e.g. a Node `Readable`).\n reader.releaseLock()\n }\n}\n\nfunction emptyChunkError(): string {\n return `uploadLargeFile: source stream emitted more than ${MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS} consecutive empty chunks. too many empty chunks.`\n}\n\nfunction tooManyBytesError(advertisedSize: number): string {\n return `uploadLargeFile: source stream emitted more than advertised ${advertisedSize} bytes. source stream emitted more bytes than advertised size.`\n}\n\nasync function cancelForwardOnlySource(source: ContentSource, reason: unknown): Promise<void> {\n const reader = source.stream().getReader()\n try {\n await reader.cancel(reason)\n } finally {\n reader.releaseLock()\n }\n}\n\nfunction notifyResumePartReused(\n listener: ResumePartReusedListener | undefined,\n event: ResumePartReusedEvent,\n): void {\n try {\n listener?.(event)\n } catch {\n // Diagnostic observers must not change upload success or failure.\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAmDA,IAAM,sCAAsC;AAsH5C,SAAS,8BACP,SACA,SACA,WACA,UACA,OACyB;CACzB,OAAO;EACL,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,YAAY;EACZ;EACA;EACA,GAAI,QAAQ,0BAA0B,KAAA,IAClC,EAAE,uBAAuB,QAAQ,sBAAsB,IACvD,CAAC;EACL,GAAI,QAAQ,WAAW,KAAA,IAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACjE,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,QAAQ,sCAAsC,KAAA,IAC5C,EAAE,sBAAsB,QAAQ,kCAAkC,IAClE,CAAC;EACP,GAAI,QAAQ,kBAAkB,KAAA,IAC1B,EAAE,eAAe,QAAQ,cAAc,IACvC,QAAQ,2BAA2B,KAAA,IACjC,EAAE,sBAAsB,QAAQ,uBAAuB,IACvD,QAAQ,qCAAqC,OAC3C,EAAE,gCAAgC,KAAK,IACvC,CAAC;EACT,GAAI,QAAQ,cAAc,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;EAC1E,GAAI,QAAQ,6BAA6B,KAAA,IACrC,EAAE,oBAAoB,QAAQ,yBAAyB,IACvD,CAAC;EACL,GAAI,QAAQ,8BAA8B,KAAA,IACtC,EAAE,qBAAqB,QAAQ,0BAA0B,IACzD,CAAC;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,cAAc,QAAQ,mBAAmB,IAC3C,CAAC;EACL,GAAI,QAAQ,4BAA4B,KAAA,IACpC,EAAE,mBAAmB,QAAQ,wBAAwB,IACrD,CAAC;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,cAAc,QAAQ,mBAAmB,IAC3C,CAAC;CACP;AACF;;;;;;;;;;;;;;;;;AAkBA,eAAsB,gBACpB,KACA,aACA,SACsB;CACtB,MAAM,sBAAsB,YAAY,uBAAuB;CAC/D,MAAM,cAAc,YAAY,2BAA2B;CAC3D,MAAM,WAAW,KAAK,IAAI,QAAQ,YAAY,qBAAqB,WAAW;CAC9E,MAAM,cAAc,QAAQ,eAAA;CAC5B,MAAM,YAAY,QAAQ,OAAO;CAEjC,MAAM,QAAQ,WAAW,WAAW,QAAQ;CAG5C,MAAM,WAAmC,OAAO,OAAO,IAAI;CAC3D,IAAI,QAAQ,aAAa,KAAA,GACvB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,QAAQ,GACxD,SAAS,OAAO;CAGpB,IAAI,QAAQ,uBAAuB,KAAA,GACjC,SAAS,8BAA8B,OAAO,QAAQ,kBAAkB;CAM1E,MAAM,wBAAwB;EAC5B,UAAU,QAAQ;EAClB,UAAU,QAAQ;EAClB,aAAa,QAAQ,eAAA;EACrB;EACA,GAAI,QAAQ,0BAA0B,KAAA,IAClC,EAAE,uBAAuB,OAAO,QAAQ,qBAAqB,EAAE,IAC/D,CAAC;EACL,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;EACL,GAAI,QAAQ,kBAAkB,KAAA,IAAY,EAAE,eAAe,QAAQ,cAAc,IAAI,CAAC;EACtF,GAAI,QAAQ,cAAc,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;CAC5E;CACA,MAAM,0BAA0B,8BAC9B,SACA,uBACA,WACA,UACA,KACF;CAEA,IAAI,CAAC,QAAQ,OAAO,YAAY,QAAQ,iBAAiB,KAAA,GACvD,MAAM,IAAI,MAAM,oEAAoE;CAItF,IAAI;CACJ,IAAI,8BAA2C,IAAI,IAAI;CACvD,IAAI,mBAAmB;CACvB,MAAM,aAAa,iBAAiB,QAAQ,MAAM;CAClD,MAAM,sBAAsB,YAA2B;EACrD,IAAI,WAAW,OAAO,WAAW,CAAC,QAAQ,OAAO,UAC/C,MAAM,wBAAwB,QAAQ,QAAQ,WAAW,OAAO,MAAM;EAExE,WAAW,OAAO,eAAe;EACjC,MAAM,eAAe,IAAI,eACvB,YAAY,UAAU,GACtB,YAAY,aAAa,GACzB,uBACA;GACE,QAAQ,WAAW;GACnB,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAChE,CACF;EACA,IAAI;GAEF,eAAc,MADU,cAAc,cAAc,WAAW,MAAM,EAAA,CAC7C;EAC1B,SAAS,KAAK;GACZ,IAAI,WAAW,OAAO,SAAS;IAC7B,IAAI,CAAC,QAAQ,OAAO,UAClB,MAAM,wBAAwB,QAAQ,QAAQ,WAAW,OAAO,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAExF,0BAA0B,cAAc,KAAK,aAAa,QAAQ,gBAAgB;GACpF;GACA,MAAM;EACR;EACA,8BAAc,IAAI,IAAoB;EACtC,mBAAmB;CACrB;CAEA,IAAI;EACF,IAAI,WAAW,OAAO,WAAW,CAAC,QAAQ,OAAO,UAC/C,MAAM,wBAAwB,QAAQ,QAAQ,WAAW,OAAO,MAAM;EAExE,WAAW,OAAO,eAAe;EACjC,IAAI,QAAQ,iBAAiB,KAAA,GAAW;GACtC,MAAM,YAAY,MAAM,oBACtB,KACA,aACA,QAAQ,UACR,QAAQ,UACR;IACE,GAAG;IACH,cAAc,QAAQ;GACxB,CACF;GACA,IAAI,cAAc,MAChB,MAAM,IAAI,0BAA0B,QAAQ,cAAc,QAAQ,QAAQ;GAE5E,cAAc,UAAU;GACxB,cAAc,UAAU;EAC1B,OAAO,IAAI,QAAQ,WAAW,QAAQ,QAAQ,OAAO,UAAU;GAC7D,MAAM,YAAY,MAAM,oBACtB,KACA,aACA,QAAQ,UACR,QAAQ,UACR,uBACF;GACA,IAAI,WAAW;IACb,cAAc,UAAU;IACxB,8BAAc,IAAI,IAAoB;GACxC,OACE,MAAM,oBAAoB;EAE9B,OACE,MAAM,oBAAoB;EAE5B,MAAM,oBAAoB;EAC1B,IAAI,sBAAsB,KAAA,GACxB,MAAM,IAAI,MAAM,wDAAwD;EAG1E,MAAM,YAAsB,IAAI,MAAM,MAAM,MAAM;EAClD,MAAM,UAAU,IAAI,gBAAgB,QAAQ,YAAY,WAAW,MAAM,MAAM;EAC/E,MAAM,MAAM,IAAI,UAAU,WAAW;EAOrC,IAAI,CAAC,QAAQ,OAAO,UAAU;GAC5B,MAAM,wBACJ,KACA,aACA,SACA,mBACA,OACA,WACA,SACA,WAAW,MACb;GACA,OAAO,MAAM,uCAAuC,KAAK,aAAa;IACpE,QAAQ;IACR,UAAU,QAAQ;IAClB,UAAU,QAAQ;IAClB;IACA,QAAQ,WAAW;IACnB,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;GAChE,CAAC;EACH;EAEA,MAAM,QAAQ,MAAM,IAAI,OAAO,SAAS;GACtC,MAAM,IAAI,QAAQ;GAClB,IAAI;IACF,WAAW,OAAO,eAAe;IAEjC,MAAM,aAAa,QAAQ,OAAO,MAAM,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;IAC9E,MAAM,OAAO,IAAI,WAAW,MAAM,WAAW,cAAc,EAAE,QAAQ,WAAW,OAAO,CAAC,CAAC;IACzF,WAAW,OAAO,eAAe;IAEjC,MAAM,WAAW,IAAI,gBAAgB;IACrC,MAAM,SAAS,OAAO,IAAI;IAC1B,MAAM,UAAU,MAAM,SAAS,OAAO;IACtC,WAAW,OAAO,eAAe;IAIjC,MAAM,aAAa,YAAY,IAAI,KAAK,UAAU;IAClD,IAAI,eAAe,KAAA,KAAa,eAAe,SAAS;KACtD,uBAAuB,QAAQ,oBAAoB;MACjD,UAAU,QAAQ;MAClB,QAAQ;MACR,YAAY,KAAK;MACjB,eAAe,KAAK;MACpB,aAAa;KACf,CAAC;KACD,UAAU,KAAK,aAAa,KAAK;KACjC,QAAQ,SAAS,KAAK,UAAU;KAChC,QAAQ,aAAa;KACrB;IACF;IAEA,MAAM,SAAS,MAAM,uBAAuB,KAAK,aAAa,mBAAmB;KAC/E,UAAU,QAAQ;KAClB,YAAY,KAAK;KACjB;KACA,eAAe,KAAK;KACpB,aAAa;KACb,OAAO,QAAQ;KACf,QAAQ,WAAW;KACnB,eAAe,QAAQ;KACvB,2BAA2B,iCACzB,QAAQ,yBACV;KACA,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;IACP,CAAC;IAED,UAAU,KAAK,aAAa,KAAK,OAAO;IACxC,QAAQ,SAAS,KAAK,UAAU;IAChC,QAAQ,aAAa;GACvB,SAAS,KAAK;IACZ,WAAW,MAAM,GAAG;IACpB,MAAM;GACR,UAAU;IACR,IAAI,QAAQ;GACd;EACF,CAAC;EAED,2BAA2B,MAAM,QAAQ,WAAW,KAAK,GAAG,UAAU;EAWtE,OAAO,MATc,uCAAuC,KAAK,aAAa;GAC5E,QAAQ;GACR,UAAU,QAAQ;GAClB,UAAU,QAAQ;GAClB;GACA,QAAQ,WAAW;GACnB,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAChE,CAAC;CAGH,SAAS,KAAK;EACZ,WAAW,MAAM,GAAG;EACpB,IAAI,gBAAgB,KAAA,GAAW,MAAM;EACrC,OAAO,MAAM,iCACX,KACA,KACA,aACA,SACA,aACA,gBACF;CACF,UAAU;EACR,WAAW,QAAQ;CACrB;AACF;AAEA,SAAS,0BACP,SACA,KACA,aACA,kBACM;CACN,QACG,MAAM,SACL,0BACE,KACA,aACA,KAAK,QACL,qBAAqB,KAAA,IAAY,KAAA,IAAY,EAAE,iBAAiB,CAClE,CACF,CAAC,CACA,YAAY,CAEb,CAAC;AACL;AAEA,eAAe,iCACb,KACA,KACA,aACA,SACA,aACA,kBACgB;CAChB,OAAO,MAAM,2BACX,KACA,KACA,aACA;EACE,QAAQ;EACR,UAAU,QAAQ;EAClB,UAAU,QAAQ;EAClB,QAAQ,QAAQ;EAChB,kBAAkB,QAAQ;CAC5B,GACA,EAAE,eAAe,iBAAiB,CACpC;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,eAAe,wBACb,KACA,aACA,SACA,aACA,OACA,WACA,SACA,QACe;CACf,MAAM,SAAS,QAAQ,OAAO,OAAO,CAAC,CAAC,UAAU;CACjD,IAAI,YAAY;CAIhB,IAAI,QAA2B;CAE/B,IAAI;EACF,KAAK,MAAM,WAAW,OAAO;GAC3B,OAAO,eAAe;GAEtB,MAAM,MAAM,IAAI,WAAW,QAAQ,MAAM;GACzC,IAAI,SAAS;GAEb,IAAI,UAAU,MAAM;IAClB,MAAM,OAAO,KAAK,IAAI,MAAM,YAAY,IAAI,aAAa,MAAM;IAC/D,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM;IACvC,UAAU;IACV,QAAQ,OAAO,MAAM,aAAa,MAAM,SAAS,IAAI,IAAI;GAC3D;GAEA,OAAO,SAAS,IAAI,YAAY;IAC9B,MAAM,EAAE,MAAM,UAAU,MAAM,4BAA4B,QAAQ,gBAAgB,GAAG,MAAM;IAC3F,IAAI,MACF,MAAM,IAAI,MACR,8CAA8C,UAAU,mBAAmB,QAAQ,OAAO,KAAK,EACjG;IAEF,aAAa,MAAM;IACnB,MAAM,OAAO,KAAK,IAAI,MAAM,YAAY,IAAI,aAAa,MAAM;IAC/D,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM;IACvC,UAAU;IACV,IAAI,OAAO,MAAM,YACf,QAAQ,MAAM,SAAS,IAAI;GAE/B;GAEA,OAAO,eAAe;GACtB,MAAM,OAAO;GAEb,MAAM,WAAW,IAAI,gBAAgB;GACrC,MAAM,SAAS,OAAO,IAAI;GAC1B,MAAM,UAAU,MAAM,SAAS,OAAO;GACtC,OAAO,eAAe;GAEtB,MAAM,SAAS,MAAM,uBAAuB,KAAK,aAAa,aAAa;IACzE,UAAU,QAAQ;IAClB,YAAY,QAAQ;IACpB;IACA,eAAe,KAAK;IACpB,aAAa;IACb,OAAO,QAAQ;IACf;IACA,eAAe,QAAQ;IACvB,2BAA2B,iCACzB,QAAQ,yBACV;IACA,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;GACP,CAAC;GAED,UAAU,QAAQ,aAAa,KAAK,OAAO;GAC3C,QAAQ,SAAS,KAAK,UAAU;GAChC,QAAQ,aAAa;EACvB;EACA,IAAI,UAAU,QAAQ,MAAM,aAAa,GACvC,MAAM,IAAI,MAAM,kBAAkB,QAAQ,OAAO,IAAI,CAAC;EAExD,MAAM,QAAQ,MAAM,4BAA4B,QAAQ,gBAAgB,GAAG,MAAM;EACjF,IAAI,CAAC,MAAM,MAAM;GACf,aAAa,MAAM,MAAM;GACzB,MAAM,IAAI,MAAM,kBAAkB,QAAQ,OAAO,IAAI,CAAC;EACxD;CACF,SAAS,KAAK;EACZ,MAAM,OAAO,OAAO,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;EACvC,MAAM;CACR,UAAU;EAGR,OAAO,YAAY;CACrB;AACF;AAEA,SAAS,kBAA0B;CACjC,OAAO,oDAAoD,oCAAoC;AACjG;AAEA,SAAS,kBAAkB,gBAAgC;CACzD,OAAO,+DAA+D,eAAe;AACvF;AAEA,eAAe,wBAAwB,QAAuB,QAAgC;CAC5F,MAAM,SAAS,OAAO,OAAO,CAAC,CAAC,UAAU;CACzC,IAAI;EACF,MAAM,OAAO,OAAO,MAAM;CAC5B,UAAU;EACR,OAAO,YAAY;CACrB;AACF;AAEA,SAAS,uBACP,UACA,OACM;CACN,IAAI;EACF,WAAW,KAAK;CAClB,QAAQ,CAER;AACF"}
|
|
1
|
+
{"version":3,"file":"large.js","names":[],"sources":["../../src/upload/large.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport type { ProgressListener } from '../streams/progress.ts'\nimport { ProgressTracker } from '../streams/progress.ts'\nimport { type ContentSource, readNextNonEmptyStreamChunk } from '../streams/source.ts'\nimport type { BucketDefaultRetention, BucketDefaultServerSideEncryption } from '../types/bucket.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { FileVersion } from '../types/file.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport { raceWithAbort } from '../util/abort.ts'\nimport { DEFAULT_CONTENT_TYPE, DEFAULT_TRANSFER_CONCURRENCY } from '../util/defaults.ts'\nimport { planRanges, type RangePlan } from '../util/plan-ranges.ts'\nimport { createAbortScope, throwRejectedOrAbortReason } from './abort-scope.ts'\nimport {\n type CleanupFailureOptions,\n cancelLargeFileBestEffort,\n cleanupAfterLargeFileError,\n} from './cancel.ts'\nimport { Semaphore } from './concurrency.ts'\nimport { finishLargeFileWithAbortReconciliation } from './finish.ts'\nimport {\n findResumeCandidate,\n type ResumeCandidateCriteria,\n type ResumeCandidateRejectedListener,\n ResumeFileIdMismatchError,\n} from './resume.ts'\nimport {\n resolveRetryResponseBodyFailures,\n type UploadRetryOptions,\n uploadPartWithFreshUrl,\n} from './retry.ts'\n\n/** Event emitted when explicit resume skips a local part because B2 already has matching SHA-1 bytes. */\nexport interface ResumePartReusedEvent {\n /** File name being resumed. */\n readonly fileName: string\n /** Unfinished large-file ID that supplied the existing part. */\n readonly fileId: LargeFileId\n /** One-based part number reused from the unfinished large file. */\n readonly partNumber: number\n /** Number of bytes in the reused part. */\n readonly contentLength: number\n /** SHA-1 hex digest that matched the local part bytes. */\n readonly contentSha1: string\n}\n\n/** Callback invoked when explicit resume accepts a pre-existing server part. */\nexport type ResumePartReusedListener = (event: ResumePartReusedEvent) => void\n\nconst MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS = 1024\n\n/** Options for uploading a large file via the multipart protocol. */\nexport interface UploadLargeFileOptions extends UploadRetryOptions, CleanupFailureOptions {\n /** Target bucket for the upload. */\n readonly bucketId: BucketId\n /** Full B2 file name including any path prefix. */\n readonly fileName: string\n /**\n * Content to upload. Sliceable sources ({@link BufferSource},\n * {@link BlobSource}, {@link FileSource}) use the parallel-parts path.\n * Non-sliceable streams and async iterables fall back to a sequential read\n * path — one part at a time, concurrency forced to 1 — so callers can stream\n * a multi-GB file without buffering the whole payload in memory. The\n * `resumeFileId` requires a sliceable source; deprecated `resume: true`\n * without an explicit file ID is ignored on forward-only sources.\n */\n readonly source: ContentSource\n /** MIME type. Defaults to `b2/x-auto` for server-side detection. */\n readonly contentType?: string\n /** Custom file info key/value pairs stored with the file. */\n readonly fileInfo?: Record<string, string>\n /** Server-side encryption settings applied to each part. */\n readonly serverSideEncryption?: EncryptionSetting\n /** Effective readable bucket default encryption used when serverSideEncryption is omitted. */\n readonly bucketDefaultServerSideEncryption?: BucketDefaultServerSideEncryption\n /** Bucket default encryption exists but cannot be read, so resume must fail closed. */\n readonly bucketDefaultServerSideEncryptionUnreadable?: boolean\n /** File retention policy applied at upload time. */\n readonly fileRetention?: FileRetentionValue\n /** Effective readable bucket default retention used when fileRetention is omitted. */\n readonly bucketDefaultRetention?: BucketDefaultRetention\n /** Bucket default retention exists but cannot be read, so resume must fail closed. */\n readonly bucketDefaultRetentionUnreadable?: boolean\n /** Legal hold status applied at upload time. */\n readonly legalHold?: LegalHoldValue\n /** Override the last-modified timestamp (epoch millis) stored in file info. */\n readonly lastModifiedMillis?: number\n /**\n * B2 upload timestamp override in milliseconds since epoch.\n * Sets the file version `uploadTimestamp`; distinct from `lastModifiedMillis` metadata.\n * Requires B2 account enablement for Custom Upload Timestamp.\n */\n readonly customUploadTimestamp?: number\n /** Size of each part in bytes. Defaults to the account's recommended part size. */\n readonly partSize?: number\n /** Maximum number of parts uploaded in parallel. Defaults to 4. */\n readonly concurrency?: number\n /** Callback invoked with upload progress updates. */\n readonly onProgress?: ProgressListener\n /**\n * Minimum milliseconds between byte-only progress callbacks. Defaults to\n * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.\n * Part-completion progress callbacks are always emitted immediately.\n */\n readonly progressIntervalMillis?: number\n /** Signal to abort the upload. Triggers cancellation of the large file. */\n readonly signal?: AbortSignal\n /**\n * If true, look for an unfinished large file with the same bucket and file name\n * and continue uploading into it. Automatic discovery only reuses unfinished\n * files whose upload options and already-uploaded part lengths match;\n * otherwise a new large file is started. Existing server parts are overwritten\n * with locally read bytes instead of being trusted by SHA-1 alone.\n *\n * Discovery runs before the first upload byte and can make up to the\n * list-page budget plus the candidate budget times the part-page budget in\n * sequential B2 list calls. Pass `resumeDiscoveryTimeoutMs` or an\n * `AbortSignal` to enforce a hard discovery deadline. SSE-C uploads are\n * never auto-resumed because B2 does not expose the customer key identity\n * needed to verify a compatible unfinished file. Candidates with unreadable\n * Object Lock fields are rejected unless the caller provides explicit settings\n * that can be verified. When `customUploadTimestamp` is set, discovery only\n * reuses candidates with the same `uploadTimestamp`; when it is omitted, a\n * reused unfinished file keeps its existing `uploadTimestamp` because B2 does\n * not expose whether that timestamp was custom or server-assigned.\n * `lastModifiedMillis` is part of the file-info identity; unfinished files\n * started by older SDK versions that omitted it can be rejected with\n * `file-info-mismatch`.\n */\n readonly resume?: boolean\n /** Optional aggregate SDK-enforced timeout for resume discovery. */\n readonly resumeDiscoveryTimeoutMs?: number\n /**\n * Maximum `b2_list_unfinished_large_files` pages inspected before upload starts. Defaults to 10.\n * If the scan truncates, resume falls back to a fresh upload and\n * `onResumeCandidateRejected` is the only SDK signal.\n */\n readonly resumeMaxListPages?: number\n /**\n * Maximum metadata-compatible candidates whose parts may be listed before upload starts. Defaults to 25.\n * Hitting the limit can leave older unfinished uploads orphaned while a fresh\n * large file is started; tune for high-churn buckets.\n */\n readonly resumeMaxPartCandidates?: number\n /**\n * Maximum `b2_list_parts` pages inspected per metadata-compatible candidate before upload starts. Defaults to 10.\n * A candidate whose parts exceed this bound is skipped and reported through\n * `onResumeCandidateRejected`.\n */\n readonly resumeMaxPartPages?: number\n /**\n * Explicit large file ID to resume into. Overrides {@link resume} discovery\n * after verifying that the ID belongs to the requested bucket/file name and\n * matches the current upload options and already-uploaded part lengths. This\n * verification also rejects SSE-C uploads because B2 does not expose\n * customer key identity for unfinished files. A mismatch, or a file ID that\n * cannot be verified through B2's unfinished-large-file listing, throws\n * {@link ResumeFileIdMismatchError}. Caller-supplied Object Lock settings are\n * verified when present; when they are omitted, readable current bucket\n * defaults or unreadable Object Lock state still participate in verification.\n */\n readonly resumeFileId?: LargeFileId\n /** Diagnostic callback invoked when resume discovery rejects a candidate. */\n readonly onResumeCandidateRejected?: ResumeCandidateRejectedListener\n /** Diagnostic callback invoked when resume reuses an already-uploaded part. */\n readonly onResumePartReused?: ResumePartReusedListener\n}\n\ninterface StartLargeFileResumeRequest {\n readonly contentType: string\n readonly fileInfo: Record<string, string>\n readonly serverSideEncryption?: EncryptionSetting\n readonly fileRetention?: FileRetentionValue\n readonly legalHold?: LegalHoldValue\n}\n\nfunction createResumeCandidateCriteria(\n options: UploadLargeFileOptions,\n request: StartLargeFileResumeRequest,\n totalSize: number,\n partSize: number,\n parts: readonly RangePlan[],\n): ResumeCandidateCriteria {\n return {\n contentType: request.contentType,\n fileInfo: request.fileInfo,\n sourceSize: totalSize,\n partSize,\n parts,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: options.customUploadTimestamp }\n : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(request.serverSideEncryption !== undefined\n ? { serverSideEncryption: request.serverSideEncryption }\n : options.bucketDefaultServerSideEncryption !== undefined\n ? { serverSideEncryption: options.bucketDefaultServerSideEncryption }\n : options.bucketDefaultServerSideEncryptionUnreadable === true\n ? { defaultServerSideEncryptionUnreadable: true }\n : {}),\n ...(request.fileRetention !== undefined\n ? { fileRetention: request.fileRetention }\n : options.bucketDefaultRetention !== undefined\n ? { defaultFileRetention: options.bucketDefaultRetention }\n : options.bucketDefaultRetentionUnreadable === true\n ? { defaultFileRetentionUnreadable: true }\n : {}),\n ...(request.legalHold !== undefined ? { legalHold: request.legalHold } : {}),\n ...(options.resumeDiscoveryTimeoutMs !== undefined\n ? { discoveryTimeoutMs: options.resumeDiscoveryTimeoutMs }\n : {}),\n ...(options.onResumeCandidateRejected !== undefined\n ? { onCandidateRejected: options.onResumeCandidateRejected }\n : {}),\n ...(options.resumeMaxListPages !== undefined\n ? { maxListPages: options.resumeMaxListPages }\n : {}),\n ...(options.resumeMaxPartCandidates !== undefined\n ? { maxPartCandidates: options.resumeMaxPartCandidates }\n : {}),\n ...(options.resumeMaxPartPages !== undefined\n ? { maxPartPages: options.resumeMaxPartPages }\n : {}),\n }\n}\n\n/**\n * Uploads a file using the B2 multipart (large file) protocol.\n *\n * The source is sliced into parts and uploaded concurrently via\n * `b2_upload_part`. This is appropriate for files larger than the recommended\n * part size. For smaller files, use {@link uploadSmallFile} which sends the\n * entire payload in a single request.\n *\n * On failure, the in-progress large file is cancelled on a best-effort basis.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state (tokens, URLs, upload URL pool).\n * @param options - Upload parameters including part size and concurrency.\n *\n * @returns The resulting {@link FileVersion} metadata.\n */\nexport async function uploadLargeFile(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n): Promise<FileVersion> {\n const recommendedPartSize = accountInfo.getRecommendedPartSize()\n const minPartSize = accountInfo.getAbsoluteMinimumPartSize()\n const partSize = Math.max(options.partSize ?? recommendedPartSize, minPartSize)\n const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY\n const totalSize = options.source.size\n\n const parts = planRanges(totalSize, partSize)\n // Keep caller fileInfo on a null-prototype record so resume identity\n // comparison only sees caller-owned enumerable keys.\n const fileInfo: Record<string, string> = Object.create(null)\n if (options.fileInfo !== undefined) {\n for (const [key, value] of Object.entries(options.fileInfo)) {\n fileInfo[key] = value\n }\n }\n if (options.lastModifiedMillis !== undefined) {\n fileInfo['src_last_modified_millis'] = String(options.lastModifiedMillis)\n }\n\n // Construct the `b2_start_large_file` request body once so the two\n // non-resume branches below (no `resume`, resume-but-no-candidate)\n // can dispatch without re-spelling the conditional spreads.\n const startLargeFileRequest = {\n bucketId: options.bucketId,\n fileName: options.fileName,\n contentType: options.contentType ?? DEFAULT_CONTENT_TYPE,\n fileInfo,\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: String(options.customUploadTimestamp) }\n : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.fileRetention !== undefined ? { fileRetention: options.fileRetention } : {}),\n ...(options.legalHold !== undefined ? { legalHold: options.legalHold } : {}),\n }\n const resumeCandidateCriteria = createResumeCandidateCriteria(\n options,\n startLargeFileRequest,\n totalSize,\n partSize,\n parts,\n )\n\n if (!options.source.canSlice && options.resumeFileId !== undefined) {\n throw new Error('uploadLargeFile: resume is not supported on non-sliceable sources.')\n }\n\n // --- Explicit resume file reuse (M11.1) ---\n let largeFileId: LargeFileId | undefined\n let preUploaded: ReadonlyMap<number, string> = new Map()\n let createdLargeFile = false\n let tracker: ProgressTracker | undefined\n const abortScope = createAbortScope(options.signal)\n const startFreshLargeFile = async (): Promise<void> => {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n const startPromise = raw.startLargeFile(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n startLargeFileRequest,\n {\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n )\n try {\n const startResp = await raceWithAbort(startPromise, abortScope.signal)\n largeFileId = startResp.fileId\n } catch (err) {\n if (abortScope.signal.aborted) {\n if (!options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason).catch(() => {})\n }\n cancelLargeFileAfterStart(startPromise, raw, accountInfo, options.onCleanupFailure)\n }\n throw err\n }\n preUploaded = new Map<number, string>()\n createdLargeFile = true\n }\n\n try {\n if (abortScope.signal.aborted && !options.source.canSlice) {\n await cancelForwardOnlySource(options.source, abortScope.signal.reason)\n }\n abortScope.signal.throwIfAborted()\n if (options.resumeFileId !== undefined) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n {\n ...resumeCandidateCriteria,\n resumeFileId: options.resumeFileId,\n },\n )\n if (candidate === null) {\n throw new ResumeFileIdMismatchError(options.resumeFileId, options.fileName)\n }\n largeFileId = candidate.fileId\n preUploaded = candidate.uploadedPartSha1s\n } else if (options.resume === true && options.source.canSlice) {\n const candidate = await findResumeCandidate(\n raw,\n accountInfo,\n options.bucketId,\n options.fileName,\n resumeCandidateCriteria,\n )\n if (candidate) {\n largeFileId = candidate.fileId\n preUploaded = new Map<number, string>()\n } else {\n await startFreshLargeFile()\n }\n } else {\n await startFreshLargeFile()\n }\n const activeLargeFileId = largeFileId\n if (activeLargeFileId === undefined) {\n throw new Error('uploadLargeFile: start did not return a large file ID.')\n }\n\n const partSha1s: string[] = new Array(parts.length)\n const uploadTracker = new ProgressTracker(options.onProgress, totalSize, parts.length, {\n ...(options.progressIntervalMillis !== undefined\n ? { minIntervalMs: options.progressIntervalMillis }\n : {}),\n })\n tracker = uploadTracker\n const sem = new Semaphore(concurrency)\n\n // Non-sliceable sources can't be read in parallel — there's only one\n // forward-only cursor. Resume is also impossible (no seek). Bail to a\n // sequential read loop instead. Each part is buffered, hashed, shipped,\n // then dropped before the next read starts, so the peak memory footprint is\n // ~partSize bytes regardless of total file size.\n if (!options.source.canSlice) {\n await uploadPartsSequentially(\n raw,\n accountInfo,\n options,\n activeLargeFileId,\n parts,\n partSha1s,\n uploadTracker,\n abortScope.signal,\n )\n return await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n }\n\n const tasks = parts.map(async (part) => {\n await sem.acquire()\n try {\n abortScope.signal.throwIfAborted()\n\n const partSource = options.source.slice(part.offset, part.offset + part.length)\n const data = new Uint8Array(await partSource.toArrayBuffer({ signal: abortScope.signal }))\n abortScope.signal.throwIfAborted()\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n abortScope.signal.throwIfAborted()\n\n // Explicit resume is the only mode that trusts an already-uploaded\n // server part enough to skip sending the local bytes again.\n const serverSha1 = preUploaded.get(part.partNumber)\n if (serverSha1 !== undefined && serverSha1 === sha1Hex) {\n notifyResumePartReused(options.onResumePartReused, {\n fileName: options.fileName,\n fileId: activeLargeFileId,\n partNumber: part.partNumber,\n contentLength: data.byteLength,\n contentSha1: serverSha1,\n })\n partSha1s[part.partNumber - 1] = serverSha1\n uploadTracker.addBytes(data.byteLength)\n uploadTracker.completePart()\n return\n }\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, activeLargeFileId, {\n fileName: options.fileName,\n partNumber: part.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal: abortScope.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[part.partNumber - 1] = result.contentSha1\n uploadTracker.addBytes(data.byteLength)\n uploadTracker.completePart()\n } catch (err) {\n abortScope.abort(err)\n throw err\n } finally {\n sem.release()\n }\n })\n\n throwRejectedOrAbortReason(await Promise.allSettled(tasks), abortScope)\n\n const result = await finishLargeFileWithAbortReconciliation(raw, accountInfo, {\n fileId: activeLargeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n partSha1s,\n signal: abortScope.signal,\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n })\n\n return result\n } catch (err) {\n abortScope.abort(err)\n if (largeFileId === undefined) throw err\n return await cleanupAfterUploadLargeFileError(\n err,\n raw,\n accountInfo,\n options,\n largeFileId,\n createdLargeFile,\n )\n } finally {\n tracker?.dispose()\n abortScope.dispose()\n }\n}\n\nfunction cancelLargeFileAfterStart(\n started: Promise<{ readonly fileId: LargeFileId }>,\n raw: RawClient,\n accountInfo: AccountInfo,\n onCleanupFailure: CleanupFailureOptions['onCleanupFailure'],\n): void {\n void started\n .then((resp) =>\n cancelLargeFileBestEffort(\n raw,\n accountInfo,\n resp.fileId,\n onCleanupFailure === undefined ? undefined : { onCleanupFailure },\n ),\n )\n .catch(() => {\n // If start failed, no file ID is available to cancel.\n })\n}\n\nasync function cleanupAfterUploadLargeFileError(\n err: unknown,\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n createdLargeFile: boolean,\n): Promise<never> {\n return await cleanupAfterLargeFileError(\n err,\n raw,\n accountInfo,\n {\n fileId: largeFileId,\n bucketId: options.bucketId,\n fileName: options.fileName,\n signal: options.signal,\n onCleanupFailure: options.onCleanupFailure,\n },\n { cancelOnError: createdLargeFile },\n )\n}\n\n/**\n * Sequential upload path for non-sliceable sources.\n *\n * Reads the source's `stream()` once and accumulates exactly `partSize`\n * bytes into an in-memory buffer per iteration. Each filled buffer is\n * hashed, dispatched to `b2_upload_part`, then released before the next\n * part starts — so peak memory is ~partSize regardless of file size.\n *\n * Concurrency is forced to 1 here because the stream is a single\n * forward-only cursor; the engine can't read part N+1 until part N is\n * fully consumed.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - The original `uploadLargeFile` options.\n * @param largeFileId - ID of the in-progress large file (already started).\n * @param parts - Pre-planned part layout (used for part numbers + count).\n * @param partSha1s - Output array, written in-place at index `partNumber - 1`.\n * @param tracker - Progress tracker; bytes added per chunk, part completed\n * each time a part finishes.\n * @param signal - Linked abort signal for source reads and part uploads.\n */\nasync function uploadPartsSequentially(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadLargeFileOptions,\n largeFileId: LargeFileId,\n parts: readonly RangePlan[],\n partSha1s: string[],\n tracker: ProgressTracker,\n signal: AbortSignal,\n): Promise<void> {\n const reader = options.source.stream().getReader()\n let bytesRead = 0\n // Carry-over bytes from a previous read when the read returned more\n // than we needed to fill one part. Kept as an array to avoid an\n // allocation per loop iteration on a typical multi-part upload.\n let carry: Uint8Array | null = null\n\n try {\n for (const planned of parts) {\n signal.throwIfAborted()\n\n const buf = new Uint8Array(planned.length)\n let filled = 0\n\n if (carry !== null) {\n const take = Math.min(carry.byteLength, buf.byteLength - filled)\n buf.set(carry.subarray(0, take), filled)\n filled += take\n carry = take < carry.byteLength ? carry.subarray(take) : null\n }\n\n while (filled < buf.byteLength) {\n const { done, value } = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (done) {\n throw new Error(\n `uploadLargeFile: source stream ended after ${bytesRead} bytes, expected ${options.source.size}.`,\n )\n }\n bytesRead += value.byteLength\n const take = Math.min(value.byteLength, buf.byteLength - filled)\n buf.set(value.subarray(0, take), filled)\n filled += take\n if (take < value.byteLength) {\n carry = value.subarray(take)\n }\n }\n\n signal.throwIfAborted()\n const data = buf\n\n const partSha1 = new IncrementalSha1()\n await partSha1.update(data)\n const sha1Hex = await partSha1.digest()\n signal.throwIfAborted()\n\n const result = await uploadPartWithFreshUrl(raw, accountInfo, largeFileId, {\n fileName: options.fileName,\n partNumber: planned.partNumber,\n data,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n retry: options.retry,\n signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n })\n\n partSha1s[planned.partNumber - 1] = result.contentSha1\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n }\n if (carry !== null && carry.byteLength > 0) {\n throw new Error(tooManyBytesError(options.source.size))\n }\n const extra = await readNextNonEmptyStreamChunk(reader, emptyChunkError(), signal)\n if (!extra.done) {\n bytesRead += extra.value.byteLength\n throw new Error(tooManyBytesError(options.source.size))\n }\n } catch (err) {\n await reader.cancel(err).catch(() => {})\n throw err\n } finally {\n // Releasing the lock lets the underlying stream propagate close / error\n // events to any upstream producer (e.g. a Node `Readable`).\n reader.releaseLock()\n }\n}\n\nfunction emptyChunkError(): string {\n return `uploadLargeFile: source stream emitted more than ${MAX_CONSECUTIVE_EMPTY_STREAM_CHUNKS} consecutive empty chunks. too many empty chunks.`\n}\n\nfunction tooManyBytesError(advertisedSize: number): string {\n return `uploadLargeFile: source stream emitted more than advertised ${advertisedSize} bytes. source stream emitted more bytes than advertised size.`\n}\n\nasync function cancelForwardOnlySource(source: ContentSource, reason: unknown): Promise<void> {\n const reader = source.stream().getReader()\n try {\n await reader.cancel(reason)\n } finally {\n reader.releaseLock()\n }\n}\n\nfunction notifyResumePartReused(\n listener: ResumePartReusedListener | undefined,\n event: ResumePartReusedEvent,\n): void {\n try {\n listener?.(event)\n } catch {\n // Diagnostic observers must not change upload success or failure.\n }\n}\n"],"mappings":"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"}
|