Releases: backblaze-labs/b2-sdk-typescript
Releases · backblaze-labs/b2-sdk-typescript
Release list
v0.4.0
Upgrading across the v4 native-API changes below? See MIGRATION.md for per-change migration steps.
Added
- Streaming and SSE-C polish helpers.
IncrementalSha256and the streamssha256Hex()helper are now available for SHA-256 checksum workflows,SseCKeyMaterialis the shared SSE-C key shape, andEncryptionKey.generate()mints random SSE-C keys with the existing redacted key wrapper. - Named bucket/key option constants.
BucketKeyOption.S3andKnownBucketKeyOptiondocument the currently known B2 bucket/application-key option while the response fields remain open to future B2-added option strings. - Local sync symlink policy. Built-in local scans and
synchronize()now acceptlocalSymlinks: 'skip' | 'follow'; follow mode only follows child symlink targets that resolve inside the configured local root and deduplicates repeated followed directory targets. - Transfer progress cadence control. Upload and single-request download options now accept
progressIntervalMillis; set it to0to restore per-chunk byte progress callbacks. - B2Simulator v4 route and GET/query compatibility. The public simulator now accepts canonical
/b2api/v4JSON routes while continuing to support/b2api/v3, rejects unsupported future version segments explicitly, and parses documented GET query forms for supported storage read/list and copy endpoints while preserving POST JSON compatibility. Closes #111. - Partner redaction helpers are public. The
@backblaze-labs/b2-sdk/partnersubpath now exportsPARTNER_TOKEN_REDACTED,APPLICATION_KEY_REDACTED, and the pure*ToRedactedJsonprojection helpers and JSON result types for secret-scrubbed Partner authorization, group-member creation, and B2 Reserve trial-account responses. Closes #225.
Changed
- User-Agent release channel now distinguishes published SDK builds from development traffic.
VERSIONremains the package semver string, while the outbound SDK product token reportsb2-sdk-typescript/<version>only for stable publish-path builds andb2-sdk-typescript/devfor source, CI,npm pack, and prerelease builds. Closes #257. - Partner group
b2Statscounters are numbers, not strings. BREAKING:PartnerB2Stats.b2BytesStoredCount,b2FilesStoredCount, andbucketCountare nownumber— matching what live B2b2_list_groups/b2_list_group_membersactually return — instead of the previously-assumed quoted decimalstring. Callers that coerced these withNumber(...)/parseInt(...)should drop the conversion. The Partner stats timestamps (b2StatsAsOfTimestamp,groupStats.createdTimestamp,groupStats.groupStatsAsOfTimestamp) are documented and modeled as B2'sdYYYYMMDD_mHHMMSSstring format rather than ISO 8601, and theB2Simulatornow emits that shape (andB2_GOOD_STANDING) to match live B2. Confirmed against live B2. Closes #214. b2_list_group_membersreturns a single object, not an array. BREAKING:ListGroupMembersResponseis now the singleListGroupMembersResultobject ({ groupId, groupName, groupMembers, nextEmail }) that live B2 returns, matchingb2_list_groups, rather than a one-element array.PartnerClient.listGroupMembers()andPartnerRawClient.listGroupMembers()resolve to that object — readresponse.groupMembers/response.nextEmaildirectly instead ofresponse[0].PartnerClient.paginateGroupMembers()is unchanged, and theB2Simulatornow emits the object shape. Confirmed against live B2.- Repository Node.js 22 CI and toolchain checks now use the JSDoc lint floor.
CI and contributor docs now use Node 22.22.2+ for full project checks while
the published SDK runtime contract remains Node.js 22.3+. Closes #282. - Progress byte callbacks are coalesced by default. Transfer
onProgressbyte-only callbacks are throttled to the SDK's 100 ms default interval, while part-completion and final progress callbacks still emit immediately. UseprogressIntervalMillis: 0when per-chunk progress sampling is required. - Bucket default retention metadata now matches B2's nested wire shape. BREAKING:
BucketInfo.defaultRetentionwas removed because B2 does not return a top-level default-retention field; readbucket.info.fileLockConfiguration.value?.defaultRetentioninstead.Bucket.getDefaultRetention()now reads that nested field and can returnundefinedwhen file-lock configuration is unreadable. The nested default retention type also includes B2's unset response shape{ mode: null, period: null }; callers that checkedBucketRetentionMode.Nonefor unset bucket defaults should handlenullmode on response metadata. - Bucket replication configuration is now capability-filtered. BREAKING:
BucketInfo.replicationConfigurationchanged from a bareReplicationConfigurationto the wrapped{ isClientAuthorizedToRead: boolean; value: ReplicationConfiguration | null }shape B2 returns, andBucket.getReplication()returns that wrapper. Callers accessing.replicationConfiguration.asReplicationSourcemust move to.replicationConfiguration.value?.asReplicationSource;valueisnullwhen replication is not configured or the caller is not authorized to read it (fail-closed). Request shapes (CreateBucketRequest/UpdateBucketRequest) keep the bareReplicationConfiguration. - Bucket default server-side encryption is now capability-filtered. BREAKING:
BucketInfo.defaultServerSideEncryptionchanged from a bareEncryptionSettingto the wrapped{ isClientAuthorizedToRead: boolean; value: BucketDefaultServerSideEncryption | null }shape B2 returns; checkbucket.info.defaultServerSideEncryption.isClientAuthorizedToReadbefore reading.value, which isnullonly when the caller is not authorized to read it (fail-closed). When readable, an unset bucket default is represented as B2's{ mode: null, algorithm: null }no-encryption wire shape. The readable value typeBucketDefaultServerSideEncryptionisPublicEncryptionSetting, matching the public SSE response union used for file and part metadata; B2 only sets SSE-B2 or none as a bucket default and never exposes SSE-C key material. Request shapes (CreateBucketRequest/UpdateBucketRequestand theB2Client.createBucket/updateBucketoptions) now acceptBucketDefaultServerSideEncryptionSetting(SseB2Setting | NoEncryption) and reject SSE-C, which B2 cannot use as a bucket default. Closes #210. - Event notification custom headers match the B2 wire shape. BREAKING:
EventNotificationRule.targetConfiguration.customHeadersis now the documented array of{ name, value }objects instead of a lookup record, with simulator validation and round-trip behavior aligned tob2_get_bucket_notification_rules/b2_set_bucket_notification_rules. Existing record-shaped caller data can be migrated withrecordToNotificationCustomHeaders(), and responses can be converted back to a lookup withnotificationCustomHeadersToRecord(). Closes #189. - List endpoints model folder and hide entries as a discriminated union. BREAKING:
FileVersion.actionnarrowed fromFileActiontoConcreteFileActionbecause a virtual folder row is no longer aFileVersion.ListFileNamesResponse.filesis nowreadonly ListedFileVersion[]and never includes hide markers;ListFileNamesWithDelimiterResponse.filesis nowreadonly FileNameListEntry[](ListedFileVersion | FolderFileVersion).ListFileVersionsResponse.filesis nowreadonly ListedConcreteFileVersion[](ListedFileVersion | ListedHideFileVersion), andListFileVersionsWithDelimiterResponse.filesis nowreadonly FileVersionListEntry[](ListedConcreteFileVersion | FolderFileVersion).b2_list_file_versionshide markers use the listed hide-row shape with omitted Object Lock/encryption metadata andcontentType: "application/x-bz-hide-marker";Bucket.unhideFile()now returns thatListedHideFileVersion | nullshape.B2SyncPath.allVersionschanged fromFileVersion[]toListedConcreteFileVersion[], so hidden sync version history now uses the listed hide-row shape rather than fullFileVersionmetadata. New literal and dynamicdelimiter?: stringoverloads onRawClient.listFileNames/listFileVersionsand theBucket.listFileNames/listFileVersions/paginateFileNames/paginateFileVersionsfacades surface folder unions only when delimiter may be present;FolderFileVersionvirtual-folder rows havefileId: nullandcontentType: null, and non-delimiter facade calls reject folder/null-ID rows before returning them. The simulator now honors thedelimiter(and itsprefixinteraction), emits folder entries only for visible file-name listings, and keeps hide markers in file-version listings. Closes #191. - Raw native storage endpoints now use the published
/b2api/v4route. All SDK-owned B2 native storage URLs are built from a single centralized v4 policy in the raw URL builder, replacing the previous mix of/b2api/v3and/b2api/v4per-endpoint segments. The version is no longer a per-call parameter, so endpoint/version drift is structurally prevented. This is runtime-compatible (B2 accepts both routes and the auth token is version-agnostic) andRawClientpublic method signatures are unchanged; read/list endpoints remain POST JSON as the docs permit. Closes #104. - Bucket type request and response contracts are now separate. BREAKING:
BucketInfo.bucketTypeis now the openBucketResponseType(KnownBucketResponseType | (string & {})), which adds the response-only'shared'value (KnownBucketResponseType.Shared) and tolerates future B2-added types, so exhaustive switches over the old closedBucketTypeon a response now need a default case. Create/update requests still accept only the settableBucketType(allPublic/allPrivate/snapshot/restricted).ListBucketsRequest.bucketTypes(and theB2Client.listBucketsfilter option) changed from `Buc...
v0.3.0
Added
- Download response headers.
DownloadHeadersnow exposes optionalcontentDisposition,contentLanguage,contentEncoding,cacheControl,expires,contentRange,serverSideEncryption, readablefileRetention/legalHold, typedclientUnauthorizedToRead, andheaderParseIssues; newDownloadHeaderName,DownloadClientUnauthorizedToReadMarker,DownloadServerSideEncryption, andSseCDownloadSettingexports document the added surface. - Large-file part metadata. Raw large-file response types now expose documented v4 metadata fields:
contentMd5onUploadPartResponseandPartInfo,serverSideEncryptionanduploadTimestamponCopyPartResponse,serverSideEncryptiononPartInfo, andreplicationStatuson unfinished large-file metadata via the exportedReplicationStatusalias. - Custom upload timestamps. Upload options now accept numeric
customUploadTimestampvalues to override B2'suploadTimestamp, distinct fromlastModifiedMillissource metadata. Rawb2_upload_fileheaders serialize the value asX-Bz-Custom-Upload-Timestamp; rawStartLargeFileRequestaccepts B2's documented decimal string/null body shape. Multipart uploads now also persistlastModifiedMillisassrc_last_modified_millis, matching the small-file path; this metadata is included in multipart resume identity and older unfinished uploads that lack it can reportfile-info-mismatch. Custom timestamps require B2 account enablement, and resume diagnostics can reportupload-timestamp-mismatchfor incompatible unfinished large files. - Bucket lifecycle-rule capabilities.
Capabilitynow exportsReadBucketLifecycleRulesandWriteBucketLifecycleRules. - Partner authorize runtime surface. New
@backblaze-labs/b2-sdk/partnersubpath exportsPartnerRawClient.authorizePartner(),PartnerAccountInfo, andInMemoryPartnerAccountInfofor Master Application Key authorization against the Partner and Computer Backup suites. - Partner API runtime bindings.
PartnerRawClientnow includescreateGroupMember(),ejectGroupMember(),listGroups(),listGroupMembers(), andreserveTrialCreateAccount()bindings for Partner API group management and B2 Reserve trial-account creation. - High-level Partner facade. The
@backblaze-labs/b2-sdk/partnersubpath now exports the experimentalPartnerClientfacade plusPartnerClientOptions,PartnerAuthorizeOptions,ListGroupsOptions,PaginateGroupsOptions,ListGroupMembersOptions,PaginateGroupMembersOptions,CreateGroupMemberOptions,EjectGroupMemberOptions, andReserveTrialAccountsOptionsfor ergonomic Partner group/member pagination and B2 Reserve trial-account workflows. - Computer Backup runtime facade. The new
@backblaze-labs/b2-sdk/backupsubpath exports experimentalBackupClientandBackupRawClientbindings for Partner-authorized Computer Backup listing, pagination, and delete workflows. - Partner API and Computer Backup typed error subclasses. New exported
TooManyMembersError,InvalidGroupIdError,InvalidEmailError,InvalidRegionError,InvalidSmsPhoneError,MethodFailureError,InvalidMemberAccountIdError,InvalidAccountIdError, andInvalidComputerIdErrorclassify Partner API and Computer Backup error codes; Partner 401 overload codes map to non-auth subclasses so they do not trigger reauth. Compatibility aliases preserve the issue-specifiedTooManyGroupMembersError,MissingSmsPhoneError, andGroupMemberCreationFailedErrornames. - Partner API and Computer Backup type layer. Public exports now include Partner API and Computer Backup request/response types, branded
groupId()/computerId()factories,PartnerCapability, andRegion. The response types document each Partner and Backup endpoint's wire shape (array-shaped or single-object per the API docs) and preserve numeric-looking group IDs and B2 statistics counts as strings. Endpoint types still awaiting runtime methods are marked experimental until those methods are implemented and exercised.
Changed
- Computer Backup facade validates list pages.
BackupRawClient.listComputers()returns the documented single-objectbz_list_computerswire response, andBackupClient.listComputers()validates that page object and returns itscomputersandnextComputerId, rejecting malformed wire shapes before pagination can silently truncate results. - Partner auth cache validation is non-destructive during construction.
PartnerClientandBackupClientignore unsafe cached Partner authorization locally untilauthorize()replaces it, instead of clearing a sharedPartnerAccountInfostore from a client constructor. - Partner authorize JSON serialization redacts tokens. BREAKING:
JSON.stringify()ofPartnerRawClient.authorizePartner(),PartnerClient.authorize(), andPartnerAccountInfo.getAuth()responses now emits[redacted Partner token]instead of round-trippingauthorizationToken. Trusted durable auth caches should stringifypartnerAuthorizeResponseForPersistence(auth)only for encrypted or otherwise credential-grade storage, or storeauthorizationTokendirectly in secure storage before rehydrating withsetAuth(). Rehydrating the redacted placeholder now fails fast instead of sending it as a Partner API bearer token. - Replication status metadata matches B2's wire shape. BREAKING:
ReplicationStatusvalues changed from lowercase ('pending' | 'completed' | 'failed' | 'replica' | null) to B2's documented uppercase values ('PENDING' | 'COMPLETED' | 'FAILED' | 'REPLICA'), andFileVersion.replicationStatus,StartLargeFileResponse.replicationStatus, andUnfinishedLargeFile.replicationStatusare now omitted instead ofnullwhen the file is not covered by a replication rule. Callers switching on lowercase literals ornullmust update those comparisons. - Event notification rule target type narrowed.
EventNotificationRule.targetConfiguration.targetTypeis now the string literal'webhook'instead ofstring(the only value B2 accepts, corrected from the earlier'url'documentation placeholder), and the rule configuration gained an optionalmaxEventsPerBatchfield. Code that annotatedtargetTypeas an arbitrarystringmay need a cast (#123).
Fixed
- Unfinished large-file SHA-1 sentinel normalized.
startLargeFileandlistUnfinishedLargeFilesnow collapse B2'scontentSha1: 'none'wire sentinel tonull, matching finished and file-list endpoints; the optionalUnfinishedLargeFileMetadata.contentSha1type is widened tostring | null. - SHA-1 reader aborts classify as
AbortError. Pending stream reads aborted without an explicit reason now reject with anAbortErrorDOMException, and abort classification is centralized so abort-aware sync and upload-finish paths handle those cancellations consistently. Closes #208. - SSE-C keys serialized into JSON request bodies.
copyFile,copyPart, andstartLargeFilenow serialize customer-managed SSE-C key material into theb2_copy_file/b2_copy_part/b2_start_large_fileJSON request bodies instead of the redactingEncryptionKeywrapper, which previously emitted the[redacted SSE-C key]placeholder and produced a403on server-side copy and large-file start with SSE-C. Header-based upload and download paths were unaffected. Closes #206. - B2 endpoint URL path hardening.
b2Url()now rejects literal and percent-encoded backslashes in prefix, version, and endpoint path components so WHATWG URL normalization cannot smuggle an endpoint into another path segment. - Real-B2 integration evidence is explicit and diagnosable. Same-repo integration workflow runs now fail when required B2 secrets are missing instead of silently accepting an all-skipped suite, integration setup logs per-step timings and timeout failures for authorization, bucket listing, stale cleanup, and bucket creation, and contributor/release docs now spell out simulator-vs-live-B2 expectations.
- B2Simulator upload write-path fidelity. Simulator uploads now reject Content-Length/body mismatches, reject upload_part and copy_part part numbers outside B2's 1-10000 range, classify copy_part malformed ranges as 400 and unsatisfiable ranges as 416, verify large-file finish part SHA-1 entries, and report stored monotonic part timestamps from list_parts. Closes #21.
- B2Simulator SSE-C fidelity. Simulator uploads, large-file parts, downloads, copyFile, and copyPart now validate SSE-C customer-key headers more closely to B2, preserve destination encryption semantics, and keep customer keys out of public response metadata.
- B2Simulator bucket-deletion fidelity.
b2_delete_bucketnow rejects buckets that still contain file versions or unfinished large files with400 cannot_delete_non_empty_bucket, matching real B2. - B2Simulator bucket-configuration fidelity.
b2_create_bucketandb2_update_bucketnow validate CORS, lifecycle, replication, and default retention rule shapes;b2_list_bucketshonors thebucketName,bucketId, andbucketTypesfilters; andb2_update_bucketenforcesifRevisionIswith a409 conflict. Closes #22. - B2Simulator create_key validation.
b2_create_keynow rejects unknown or empty capabilities and out-of-range key names, and rejects capabilities that exceed the creating key's grant, matching real B2. Closes #18. - B2Simulator authorize grant fidelity.
b2_authorize_accountnow derives the responseallowedcapabilities and bucket/name-prefix scope from the authorizing key instead of always returning the full master grant, so a restricted key reports its real scope. Closes #19. - B2Simulator object-lock update fidelity.
b2_update_file_retentionandb2_update_file_legal_holdnow enforce retention and legal-hold update rules, governance-bypass requirements, and retention-clock validation, matching real B2. Closes #122. - **B2Simulator d...
v0.2.0
Added
- New
sha1sync compare mode.CompareModenow accepts'sha1', andSyncPathexposes an optionalcontentSha1field pluscontentSha1Statefor custom scanners that can supply explicit trust state. The synchronizer hashes local files only when cheaper metadata cannot already prove drift and compares against B2 SHA-1 metadata. B2's verified single-partcontentSha1can prove equality; multipartfileInfo.large_file_sha1andunverified:<hex>values are untrusted hints and are verified by hashing the selected B2 version before they can suppress a transfer. Files whose SHA-1 is genuinely unavailable, or whose untrusted B2 bytes cannot be verified before the configured deadline or byte ceiling, are skipped with a surfaced event rather than failing the whole run. SHA-1 comparison uses bounded workers, dry-runs still hash matching-size local files but do not download B2 bytes for untrusted metadata, andcompareevents report local hash reads inbytesHashedplus B2 verification reads inbytesVerified. Local hashing rejects non-regular files and bounds reads to the scanned size; local and B2 SHA-1 reads usesha1ReadTimeoutMillisas an idle/no-progress timeout with a bounded default. Untrusted B2 verification is also bounded by selected-version byte length andsha1VerificationTimeoutMillis, withsha1VerificationMaxBytesavailable as a lower per-file byte ceiling. The SDK does not cache untrusted B2 verification results across runs, so unchanged multipart objects can incur full-object B2 download reads everysha1sync. Custom scanners can use the exportedselectB2ComparableSha1(),parseSyncContentSha1(),syncSha1StateOf(),untrustedSha1(),isUntrustedSha1(), anduntrustedSha1Prefixhelpers to mark or inspect SHA-1 metadata without duplicating sentinel strings. This is an accidental drift detector, not a cryptographic tamper guarantee. Closes #29. - S3-compatible AWS Signature Version 4 presigned URLs and release hardening. New
presignS3GetObjectUrl()andpresignS3PutObjectUrl()helpers generate real S3-compatible presigned URLs for B2 without passing application-key secrets to runtime peer packages. PUT presigns can bindContent-Type,Content-Length, and metadata headers for browser / third-party uploads. Trusted server code can opt into intentionally inline or browser-executable response overrides by passingtrustedUnsafeS3PresignOptIntoallowInlineResponseContentDisposition,allowBrowserExecutableResponseContentType, orallowBrowserExecutableContentType; plain booleans from request JSON are ignored. PUT presigned URLs are replayable until expiry and retries can create duplicate file versions if B2 stored the object but the client missed the response; use unique keys, reconcile by listed file IDs/checksums, and configure lifecycle/version cleanup when needed. The shorterpresignPutObjectUrl()name remains as a deprecated alias for pre-release adopters. The existing B2-nativepresignGetObjectUrl()positional helper remains as a deprecated compatibility alias; usecreateNativeDownloadAuthorizationUrl()when you intentionally want a B2 download-authorization-token URL. The release workflow now verifies a packed artifact before publishing it with npm trusted publishing and GitHub Release artifact reuse. - Sync include/exclude filters.
SyncOptionsnow acceptsincludeandexcludefilters using SDK glob strings or best-effort guarded regular expressions, with exportedSyncFilterOptionsandSyncFilterPatterntypes for reusable configuration. Filters apply to both local and B2 sides during sync, andSyncFolder.scan()accepts the same filter object for standalone scans. Glob filters use the SDK segment dialect (*/?within one segment, whole-segment**across directories, slash-less basename/ancestor matching) and excludes win over includes. RegExp acceptance is a safety heuristic whose exact accepted subset may change as protections tighten; paths beyond the RegExp input guard are skipped whenever any RegExp filter is configured, including exclude-only RegExp deny-lists. - B2 sync scan diagnostics.
SyncFolder.scan()acceptsSyncScanOptions.onSkip, andsynchronize()surfaces built-in scanner diagnostics asskipevents with exportedSyncSkipReasonvalues for objects outside the configured prefix, unsafe relative names, local-filesystem-unsafe names, normalized or local-canonical path collisions, filesystem read errors, paths beyond the RegExp input guard, and aggregated scanner diagnostic overflow. Raw B2 prefixes preserve backslashes as key characters; pass/explicitly for slash-delimited prefixes. Custom scanners can use the exportedpathPassesSyncFilters,directoryMayContainSyncPaths,filterSyncPaths,literalPrefixForSyncFilters, andpathSkippedByRegExpInputLimithelpers to match the SDK filter dialect. Built-in scans sort before yielding and B2 scans group listed versions before yielding, so exclude filters and non-literal includes do not bound the scanner memory footprint.SyncOptions.maxScanEntries/SyncScanOptions.maxScanEntriesprovide a defined scan-limit failure mode for unexpectedly large scans; B2 scans count every listed file-version record, including versions later skipped by prefix, safety, or filter checks, while local and fallback scans count retained sync paths. PassInfinityonly when the process heap is sized for the full result set; raising the limit increases peak scanner memory. - Raw JSON request options bags are public.
RawRequestOptionsis exported, andRawClient.getUploadUrl,getUploadPartUrl,uploadFile, anduploadPartaccept options bags forsignalandretry. The olderJsonPostOptionsexport remains as a deprecated alias for source compatibility. - Multipart resume exposes public diagnostics and tuning controls.
ResumeFileIdMismatchError,onResumeCandidateRejected,onResumePartReused,ResumeCandidateRejectedEvent,ResumeCandidateRejectedReason,ResumePartReusedEvent,ResumePartReusedListener, and theresumeMaxListPages/resumeMaxPartCandidates/resumeMaxPartPages/resumeDiscoveryTimeoutMsoptions are exported or available on high-level upload APIs. - Public B2 response metadata types are exported. New response-facing types include
PublicEncryptionSetting,SseCPublicSetting,NoEncryptionWireSetting,ReadableFileRetention,ReadableLegalHold, andUnfinishedLargeFileMetadata. FileSource(path)/FileSource.fromPath(path)for Node local-file uploads.FileSourceis exported from the main entry and@backblaze-labs/b2-sdk/streams, supports random-accessslice()reads for multipart uploads, rejects non-regular files and leaf path swaps on a best-effort filesystem identity check, and lets local-to-B2 sync upload files without first buffering them withreadFile. It detects size/mtime changes and, on POSIX platforms, ctime changes so same-size rewrites with restored mtime are rejected. Parent directory symlinks are followed by the OS unless the caller validates the containing root first; B2-to-local sync rejects symlinked download parents. On Windows, same-size rewrites with restored mtime can be undetectable through Node's portable stat fields; use an independent digest when tamper-resistant integrity is required.fromPath()performs asynchronous filesystem validation for async hot paths.toContentSource(input, size)also accepts async iterables such as NodeReadablestreams for forward-only uploads.- Multipart cleanup diagnostics. Multipart upload, streaming upload, and multipart copy options now accept
onCleanupFailure, and the root export includesCleanupFailureEvent/CleanupFailureListener, so failed best-effortb2_cancel_large_filecleanup and deliberately skipped cleanup after ambiguous finish responses are observable with the relevantfileId.
Changed
- Sync error summary wording now reports total sync errors. The terminal summary event changed from
N action(s) failedtoN sync error(s) occurredbecause SHA-1 preparation failures are surfaced alongside transfer/action failures. - Sync concurrency validation is now strict.
SyncOptions.concurrencymust be a positive integer; invalid values such as0, negative numbers,NaN, or fractions throwRangeErrorbefore sync scanning begins. - Sync scan errors now preserve readable-file progress. Non-root local scan errors are surfaced as per-path
errorevents while readable siblings continue; if any scan error occurs, destination-only delete/orphan actions are skipped to avoid removing paths hidden by scan failures. compareevents now exposebytesHashed. Insha1mode, local bytes read for hashing are reported ascompare.bytesHashed;compare.sizeremains0for compatibility with the previous metadata-only compare event shape. At the type level,compareis now represented bySyncCompareEventrather thanSyncActionEventType, so TypeScript consumers that narrow on action-event types should handle compare events separately.- Node.js 22.3+ is now the minimum supported Node runtime.
FileSource(path)validates local files synchronously through Node'sprocess.getBuiltinModule()API sosizeis available at construction time; async code should preferFileSource.fromPath(path). REALM_URLSkeeps its mutableRecord<string, string>source shape. Runtime realm resolution still trusts only the built-in verified aliases plus direct custom URLs passed toB2Client; the export remains mutable for compatibility with existing source that adds local aliases.- S3 region derivation now fails closed for custom endpoints.
createS3ClientConfig()and the S3 presign helpers derive the region from standards3.<region>.backblazeb2.comendpoints. Custom, proxied, or non-standard endpoints must passregionexplicitly and should callcreateS3ClientConfig()during startup o...
v0.1.0
First public release of @backblaze-labs/b2-sdk. Everything below is new in this version.
Added — security
- SSRF / URL-substitution guard in the default
FetchTransport. AfterB2Client.authorize(), the transport rejects any URL whose host falls outside the realm's parent domain (backblazeb2.com,backblaze.com) plus user-supplied allow-list entries. Literal IPv4/IPv6 addresses,localhost,metadata.google.internal,*.internal, and*.localare rejected unconditionally. NewB2SsrfError(non-retryable, attaches the offending URL). New publicUrlGuardclass andderiveAllowedSuffixes()helper exported from the main entry. See SSRF guard. B2ClientOptions.allowedHostSuffixes— optional extra hosts merged into the guard's allow-list after authorize, for self-hosted proxies / debugging.- Audit-derived regression tests anchored to specific ecosystem failure modes:
src/upload/resume.safety.node.test.tsfails if the resume module ever importsnode:fs(prevents s3up-style on-disk uploadId leak).- Concurrency invariants on
UploadUrlPool(no double-issue, evict-on-held safety, key isolation, 1000-cycle stress). - Monotonicity assertion on
onProgressevent sequences during multipart uploads.
Added — source-level isomorphism
.tsextensions on every internal relative import.tsconfig.jsonenablesallowImportingTsExtensions+rewriteRelativeImportExtensions. One source tree now runs unmodified in Node 22+, Bun, Deno (no build step, nonode_modules, nonpm:shim), browsers, Cloudflare Workers, and Vercel Edge. Vite rewrites the extensions during build so consumers still see./foo.jsin dist/.- Deno typecheck workflow verifies the property on every push:
deno check examples/...resolves@backblaze-labs/b2-sdkstraight at../src/*.tsviaexamples/deno.json. If a.jsextension ever sneaks back into an internal import, the workflow fails immediately. - JSON-imported version constant.
src/version.tsdoesimport pkg from '../package.json' with { type: 'json' }; export const VERSION = pkg.version. Bumping the package version automatically propagates to the User-Agent header and the published artifact — no separatesrc/version.tsto maintain, no sync script. Rollup tree-shakes the JSON down to a 133-byte module containing only the version field; no devDependency or metadata leak to consumers.
Added — telemetry & identity
- Stable, greppable User-Agent. Format:
b2-sdk-typescript/<version> (typescript; @backblaze-labs/b2-sdk; <runtime>; [os; ][arch]). Bothb2-sdk-typescript/(stable product token) and@backblaze-labs/b2-sdk(npm package name) are part of the documented contract — log queries can match either. Runtime detection covers Node, Bun, Deno, and browser; OS + arch reported on non-browser runtimes. CustomuserAgentfromB2ClientOptionsis prepended verbatim. New exported constantsSDK_PRODUCTandSDK_PACKAGEfrom@backblaze-labs/b2-sdk.
Added — simulator fidelity & test seams
- B2 spec input validation in the simulator.
validateBucketName,validateFileName,validateFileInfo,validateBucketInfo, andvalidateMaxCountenforce the limits B2 documents (6-63 char bucket name withb2-reserved-prefix rule, 1024-byte UTF-8 file-name cap, 2048-byte fileInfo / bucketInfo budgets, per-endpointmaxFileCountceilings). Wired into every state-touching handler. Limit constants (BUCKET_NAME_MIN/MAX,FILE_NAME_MAX_BYTES,FILE_INFO_TOTAL_MAX,BUCKET_INFO_MAX_KEYS, etc.) are re-exported from@backblaze-labs/b2-sdk/simulatorfor tests that want to parameterise around the documented caps. - Opt-in strict-auth mode.
new B2Simulator({ strictAuth: true })enforces application-key capabilities, bucket scoping, prefix scoping, and auth-token expiry on every request (including upload + download paths). Unknown tokens return401 bad_auth_token; expired tokens return401 expired_auth_token; missing capabilities return403 unauthorized. Default remains permissive so existing tests are unaffected. - Virtual clock for expiry tests.
B2Simulator.advanceTime(ms)fast-forwards the simulator's internal clock soauthTokenTtlMsexpiry paths can be exercised withoutsetTimeout. - Pluggable post-upload hooks.
onWebhookDeliverfires after every successful upload / copy /finishLargeFileagainst a bucket with matching event-notification rules;onReplicatefires when the bucket is a replication source. Errors thrown from user hooks are routed to the optionalonHookError(otherwise swallowed — a buggy listener never masks API success).B2Simulator.flushHooks()is a deterministic test seam: awaits every pending hook to settle before assertions. - Wire-level edge cases.
parseRangeHeaderreturns a tagged result (ok/unsatisfiable/malformed); the simulator now returns206with the documentedContent-Range: bytes <start>-<end>/<total>header and416 Range Not Satisfiable(withContent-Range: bytes */<total>) when the start offset is past EOF. Realistic 24-hex IDs (b2_bucket_<hex>,4_z<hex>) replace the previous 12-digit stand-in.b2_finish_large_filevalidatespartNumber ∈ [1, 10000]and thatpartSha1Array.length === uploadedParts.length.b2_delete_keyevicts every outstanding auth token issued from the revoked key. - Fault injection.
B2Simulator.injectFailure({ on, status, code, message, count, skip, retryAfter })registers a synthetic failure that fires on every matched request until itscountbudget is spent. Returns aFaultHandlewhose.clear()retires that specific registration.clearFaults()removes every fault. Faults run before any real handler, so a matched request never touches in-memory state.
Added — CI & examples
real-examplesCI job runs every documentednpx tsx examples/...command against a real B2 account after the integration suite passes (Node 22 + 24, serialised). The runner asserts content round-trip equality for bothnode-downloadandnode-backup-cli restore. A renamed flag, swapped argument order, or stale README command fails CI before reaching users.smoke-examplesCI job runs the same examples against an in-memoryB2Simulatoron every push and PR — zero credentials, zero network, zero cost. Exercises thenpx tsx/exports-map resolution path the same way annpm install-ed consumer would.- Real-B2 integration workflow (
.github/workflows/integration.yml) runs the integration suite sequentially across Node 22 + 24 withmax-parallel: 1, on push, PR, weekly schedule, andworkflow_dispatch. Defensivesdk-test-*bucket sweep at startup absorbs leftovers from crashed runs. - Examples Deno + Bun typecheck jobs.
bunx tsc --noEmit -p examples/tsconfig.jsonanddeno check(viaexamples/deno.jsonimport map) run on every push.
Changed — lint gate
pnpm lintnow usesbiome check --error-on-warnings. Any warning — not just an error — fails CI. The previous 17 baseline warnings (alllint/suspicious/noExplicitAnyin test mocks) were converted toas unknown as <RealType>casts.
Changed — CI matrix timeouts
LARGE_TEST_TIMEOUT = 60_000applied to copy + write-stream tests insrc/copy/copy.test.tsandsrc/upload/stream.test.ts, matching the existing calibration insrc/upload/upload.test.ts. macOS GitHub-hosted runners are ~2-3× slower than typical local Macs for the simulator's per-part SHA-1 computation; the previous hardcoded 30 s budget was getting clipped on bad scheduling ticks.
Added — docs
- Bundle-size table in the Quality section, measured per-subpath via Bun's bundler with tree-shaking enabled (main entry: ~9.6 KB gzipped;
/errors: 670 B gzipped;/streams: 801 B gzipped;/simulator: 5.3 KB gzipped). - Source-isomorphism section in the README documenting how
deno check examples/againstsrc/works without a build step. - Identifying your traffic (User-Agent) section in the README documents the contract and how to prepend an application prefix.
Added — isomorphic test coverage
- Vitest browser-mode test suite under
pnpm test:browser. The full test surface (minus*.node.test.tsfiles) runs in real Chromium, Firefox, and WebKit via Playwright. CI parallelizes per engine viaVITEST_BROWSER_INSTANCE. - Isomorphic
B2Simulator:handleRequestis nowasyncand theb2_copy_parthandler uses the SDK's ownsha1Hex(Nodenode:cryptolazy-loaded, WebCrypto fallback in browsers). Drops the previousnode:crypto.createHashtop-level import. - Pure-JS MD5 fallback in
EncryptionKey.fromBytes. Whennode:crypto.createHashisn't available, the SDK computes MD5 in pure JS so SSE-C key construction stays cross-runtime. Verified against three RFC 1321 vectors in both Node and browsers. - Lazy
node:fs/promisesandnode:pathimports insidesrc/sync/synchronizer.tsaction closures. The synchronizer module itself loads in browsers (B2-to-B2 sync works in a browser); only local-disk actions throw when invoked outside Node. - Test file naming convention:
*.node.test.tsis skipped in browser mode. Renamedsrc/auth/file.test.ts→file.node.test.ts,src/sync/scanners/scanners.test.ts→scanners.node.test.ts. Addedsrc/streams/encryption-key.node.test.tsfor theutil.inspectredaction assertion.
Added — robustness
- Resume support for multipart uploads. Pass
resume: true(or an explicitresumeFileId) touploadLargeFileorBucket.upload. The engine querieslistUnfinishedLargeFiles+listPartsand skips parts whose locally-recomputed SHA-1 matches the server's. Newsrc/upload/resume.tswithfindResumeCandidateandcollectPartSha1shelpers. - Per-range retry in
createParallelDownloadStream. Each ranged GET is retried independently with exponential backoff and jitter (default 5 attempts). New `maxRetri...