Skip to content

Releases: backblaze-labs/b2-sdk-typescript

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 18:50
v0.4.0
d549068

Upgrading across the v4 native-API changes below? See MIGRATION.md for per-change migration steps.

Added

  • Streaming and SSE-C polish helpers. IncrementalSha256 and the streams sha256Hex() helper are now available for SHA-256 checksum workflows, SseCKeyMaterial is the shared SSE-C key shape, and EncryptionKey.generate() mints random SSE-C keys with the existing redacted key wrapper.
  • Named bucket/key option constants. BucketKeyOption.S3 and KnownBucketKeyOption document 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 accept localSymlinks: '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 to 0 to restore per-chunk byte progress callbacks.
  • B2Simulator v4 route and GET/query compatibility. The public simulator now accepts canonical /b2api/v4 JSON 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/partner subpath now exports PARTNER_TOKEN_REDACTED, APPLICATION_KEY_REDACTED, and the pure *ToRedactedJson projection 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. VERSION remains the package semver string, while the outbound SDK product token reports b2-sdk-typescript/<version> only for stable publish-path builds and b2-sdk-typescript/dev for source, CI, npm pack, and prerelease builds. Closes #257.
  • Partner group b2Stats counters are numbers, not strings. BREAKING: PartnerB2Stats.b2BytesStoredCount, b2FilesStoredCount, and bucketCount are now number — matching what live B2 b2_list_groups / b2_list_group_members actually return — instead of the previously-assumed quoted decimal string. Callers that coerced these with Number(...) / parseInt(...) should drop the conversion. The Partner stats timestamps (b2StatsAsOfTimestamp, groupStats.createdTimestamp, groupStats.groupStatsAsOfTimestamp) are documented and modeled as B2's dYYYYMMDD_mHHMMSS string format rather than ISO 8601, and the B2Simulator now emits that shape (and B2_GOOD_STANDING) to match live B2. Confirmed against live B2. Closes #214.
  • b2_list_group_members returns a single object, not an array. BREAKING: ListGroupMembersResponse is now the single ListGroupMembersResult object ({ groupId, groupName, groupMembers, nextEmail }) that live B2 returns, matching b2_list_groups, rather than a one-element array. PartnerClient.listGroupMembers() and PartnerRawClient.listGroupMembers() resolve to that object — read response.groupMembers / response.nextEmail directly instead of response[0]. PartnerClient.paginateGroupMembers() is unchanged, and the B2Simulator now 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 onProgress byte-only callbacks are throttled to the SDK's 100 ms default interval, while part-completion and final progress callbacks still emit immediately. Use progressIntervalMillis: 0 when per-chunk progress sampling is required.
  • Bucket default retention metadata now matches B2's nested wire shape. BREAKING: BucketInfo.defaultRetention was removed because B2 does not return a top-level default-retention field; read bucket.info.fileLockConfiguration.value?.defaultRetention instead. Bucket.getDefaultRetention() now reads that nested field and can return undefined when file-lock configuration is unreadable. The nested default retention type also includes B2's unset response shape { mode: null, period: null }; callers that checked BucketRetentionMode.None for unset bucket defaults should handle null mode on response metadata.
  • Bucket replication configuration is now capability-filtered. BREAKING: BucketInfo.replicationConfiguration changed from a bare ReplicationConfiguration to the wrapped { isClientAuthorizedToRead: boolean; value: ReplicationConfiguration | null } shape B2 returns, and Bucket.getReplication() returns that wrapper. Callers accessing .replicationConfiguration.asReplicationSource must move to .replicationConfiguration.value?.asReplicationSource; value is null when replication is not configured or the caller is not authorized to read it (fail-closed). Request shapes (CreateBucketRequest / UpdateBucketRequest) keep the bare ReplicationConfiguration.
  • Bucket default server-side encryption is now capability-filtered. BREAKING: BucketInfo.defaultServerSideEncryption changed from a bare EncryptionSetting to the wrapped { isClientAuthorizedToRead: boolean; value: BucketDefaultServerSideEncryption | null } shape B2 returns; check bucket.info.defaultServerSideEncryption.isClientAuthorizedToRead before reading .value, which is null only 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 type BucketDefaultServerSideEncryption is PublicEncryptionSetting, 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 / UpdateBucketRequest and the B2Client.createBucket / updateBucket options) now accept BucketDefaultServerSideEncryptionSetting (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.customHeaders is now the documented array of { name, value } objects instead of a lookup record, with simulator validation and round-trip behavior aligned to b2_get_bucket_notification_rules / b2_set_bucket_notification_rules. Existing record-shaped caller data can be migrated with recordToNotificationCustomHeaders(), and responses can be converted back to a lookup with notificationCustomHeadersToRecord(). Closes #189.
  • List endpoints model folder and hide entries as a discriminated union. BREAKING: FileVersion.action narrowed from FileAction to ConcreteFileAction because a virtual folder row is no longer a FileVersion. ListFileNamesResponse.files is now readonly ListedFileVersion[] and never includes hide markers; ListFileNamesWithDelimiterResponse.files is now readonly FileNameListEntry[] (ListedFileVersion | FolderFileVersion). ListFileVersionsResponse.files is now readonly ListedConcreteFileVersion[] (ListedFileVersion | ListedHideFileVersion), and ListFileVersionsWithDelimiterResponse.files is now readonly FileVersionListEntry[] (ListedConcreteFileVersion | FolderFileVersion). b2_list_file_versions hide markers use the listed hide-row shape with omitted Object Lock/encryption metadata and contentType: "application/x-bz-hide-marker"; Bucket.unhideFile() now returns that ListedHideFileVersion | null shape. B2SyncPath.allVersions changed from FileVersion[] to ListedConcreteFileVersion[], so hidden sync version history now uses the listed hide-row shape rather than full FileVersion metadata. New literal and dynamic delimiter?: string overloads on RawClient.listFileNames / listFileVersions and the Bucket.listFileNames / listFileVersions / paginateFileNames / paginateFileVersions facades surface folder unions only when delimiter may be present; FolderFileVersion virtual-folder rows have fileId: null and contentType: null, and non-delimiter facade calls reject folder/null-ID rows before returning them. The simulator now honors the delimiter (and its prefix interaction), 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/v4 route. 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/v3 and /b2api/v4 per-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) and RawClient public 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.bucketType is now the open BucketResponseType (KnownBucketResponseType | (string & {})), which adds the response-only 'shared' value (KnownBucketResponseType.Shared) and tolerates future B2-added types, so exhaustive switches over the old closed BucketType on a response now need a default case. Create/update requests still accept only the settable BucketType (allPublic / allPrivate / snapshot / restricted). ListBucketsRequest.bucketTypes (and the B2Client.listBuckets filter option) changed from `Buc...
Read more

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 18 Aug 08:53
v0.3.0
b78b07b

Added

  • Download response headers. DownloadHeaders now exposes optional contentDisposition, contentLanguage, contentEncoding, cacheControl, expires, contentRange, serverSideEncryption, readable fileRetention/legalHold, typed clientUnauthorizedToRead, and headerParseIssues; new DownloadHeaderName, DownloadClientUnauthorizedToReadMarker, DownloadServerSideEncryption, and SseCDownloadSetting exports document the added surface.
  • Large-file part metadata. Raw large-file response types now expose documented v4 metadata fields: contentMd5 on UploadPartResponse and PartInfo, serverSideEncryption and uploadTimestamp on CopyPartResponse, serverSideEncryption on PartInfo, and replicationStatus on unfinished large-file metadata via the exported ReplicationStatus alias.
  • Custom upload timestamps. Upload options now accept numeric customUploadTimestamp values to override B2's uploadTimestamp, distinct from lastModifiedMillis source metadata. Raw b2_upload_file headers serialize the value as X-Bz-Custom-Upload-Timestamp; raw StartLargeFileRequest accepts B2's documented decimal string/null body shape. Multipart uploads now also persist lastModifiedMillis as src_last_modified_millis, matching the small-file path; this metadata is included in multipart resume identity and older unfinished uploads that lack it can report file-info-mismatch. Custom timestamps require B2 account enablement, and resume diagnostics can report upload-timestamp-mismatch for incompatible unfinished large files.
  • Bucket lifecycle-rule capabilities. Capability now exports ReadBucketLifecycleRules and WriteBucketLifecycleRules.
  • Partner authorize runtime surface. New @backblaze-labs/b2-sdk/partner subpath exports PartnerRawClient.authorizePartner(), PartnerAccountInfo, and InMemoryPartnerAccountInfo for Master Application Key authorization against the Partner and Computer Backup suites.
  • Partner API runtime bindings. PartnerRawClient now includes createGroupMember(), ejectGroupMember(), listGroups(), listGroupMembers(), and reserveTrialCreateAccount() bindings for Partner API group management and B2 Reserve trial-account creation.
  • High-level Partner facade. The @backblaze-labs/b2-sdk/partner subpath now exports the experimental PartnerClient facade plus PartnerClientOptions, PartnerAuthorizeOptions, ListGroupsOptions, PaginateGroupsOptions, ListGroupMembersOptions, PaginateGroupMembersOptions, CreateGroupMemberOptions, EjectGroupMemberOptions, and ReserveTrialAccountsOptions for ergonomic Partner group/member pagination and B2 Reserve trial-account workflows.
  • Computer Backup runtime facade. The new @backblaze-labs/b2-sdk/backup subpath exports experimental BackupClient and BackupRawClient bindings 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, and InvalidComputerIdError classify 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-specified TooManyGroupMembersError, MissingSmsPhoneError, and GroupMemberCreationFailedError names.
  • Partner API and Computer Backup type layer. Public exports now include Partner API and Computer Backup request/response types, branded groupId() / computerId() factories, PartnerCapability, and Region. 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-object bz_list_computers wire response, and BackupClient.listComputers() validates that page object and returns its computers and nextComputerId, rejecting malformed wire shapes before pagination can silently truncate results.
  • Partner auth cache validation is non-destructive during construction. PartnerClient and BackupClient ignore unsafe cached Partner authorization locally until authorize() replaces it, instead of clearing a shared PartnerAccountInfo store from a client constructor.
  • Partner authorize JSON serialization redacts tokens. BREAKING: JSON.stringify() of PartnerRawClient.authorizePartner(), PartnerClient.authorize(), and PartnerAccountInfo.getAuth() responses now emits [redacted Partner token] instead of round-tripping authorizationToken. Trusted durable auth caches should stringify partnerAuthorizeResponseForPersistence(auth) only for encrypted or otherwise credential-grade storage, or store authorizationToken directly in secure storage before rehydrating with setAuth(). 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: ReplicationStatus values changed from lowercase ('pending' | 'completed' | 'failed' | 'replica' | null) to B2's documented uppercase values ('PENDING' | 'COMPLETED' | 'FAILED' | 'REPLICA'), and FileVersion.replicationStatus, StartLargeFileResponse.replicationStatus, and UnfinishedLargeFile.replicationStatus are now omitted instead of null when the file is not covered by a replication rule. Callers switching on lowercase literals or null must update those comparisons.
  • Event notification rule target type narrowed. EventNotificationRule.targetConfiguration.targetType is now the string literal 'webhook' instead of string (the only value B2 accepts, corrected from the earlier 'url' documentation placeholder), and the rule configuration gained an optional maxEventsPerBatch field. Code that annotated targetType as an arbitrary string may need a cast (#123).

Fixed

  • Unfinished large-file SHA-1 sentinel normalized. startLargeFile and listUnfinishedLargeFiles now collapse B2's contentSha1: 'none' wire sentinel to null, matching finished and file-list endpoints; the optional UnfinishedLargeFileMetadata.contentSha1 type is widened to string | null.
  • SHA-1 reader aborts classify as AbortError. Pending stream reads aborted without an explicit reason now reject with an AbortError DOMException, 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, and startLargeFile now serialize customer-managed SSE-C key material into the b2_copy_file / b2_copy_part / b2_start_large_file JSON request bodies instead of the redacting EncryptionKey wrapper, which previously emitted the [redacted SSE-C key] placeholder and produced a 403 on 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_bucket now rejects buckets that still contain file versions or unfinished large files with 400 cannot_delete_non_empty_bucket, matching real B2.
  • B2Simulator bucket-configuration fidelity. b2_create_bucket and b2_update_bucket now validate CORS, lifecycle, replication, and default retention rule shapes; b2_list_buckets honors the bucketName, bucketId, and bucketTypes filters; and b2_update_bucket enforces ifRevisionIs with a 409 conflict. Closes #22.
  • B2Simulator create_key validation. b2_create_key now 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_account now derives the response allowed capabilities 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_retention and b2_update_file_legal_hold now enforce retention and legal-hold update rules, governance-bypass requirements, and retention-clock validation, matching real B2. Closes #122.
  • **B2Simulator d...
Read more

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 08 Jul 14:16
v0.2.0
46404ad

Added

  • New sha1 sync compare mode. CompareMode now accepts 'sha1', and SyncPath exposes an optional contentSha1 field plus contentSha1State for 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-part contentSha1 can prove equality; multipart fileInfo.large_file_sha1 and unverified:<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, and compare events report local hash reads in bytesHashed plus B2 verification reads in bytesVerified. Local hashing rejects non-regular files and bounds reads to the scanned size; local and B2 SHA-1 reads use sha1ReadTimeoutMillis as an idle/no-progress timeout with a bounded default. Untrusted B2 verification is also bounded by selected-version byte length and sha1VerificationTimeoutMillis, with sha1VerificationMaxBytes available 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 every sha1 sync. Custom scanners can use the exported selectB2ComparableSha1(), parseSyncContentSha1(), syncSha1StateOf(), untrustedSha1(), isUntrustedSha1(), and untrustedSha1Prefix helpers 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() and presignS3PutObjectUrl() helpers generate real S3-compatible presigned URLs for B2 without passing application-key secrets to runtime peer packages. PUT presigns can bind Content-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 passing trustedUnsafeS3PresignOptIn to allowInlineResponseContentDisposition, allowBrowserExecutableResponseContentType, or allowBrowserExecutableContentType; 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 shorter presignPutObjectUrl() name remains as a deprecated alias for pre-release adopters. The existing B2-native presignGetObjectUrl() positional helper remains as a deprecated compatibility alias; use createNativeDownloadAuthorizationUrl() 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. SyncOptions now accepts include and exclude filters using SDK glob strings or best-effort guarded regular expressions, with exported SyncFilterOptions and SyncFilterPattern types for reusable configuration. Filters apply to both local and B2 sides during sync, and SyncFolder.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() accepts SyncScanOptions.onSkip, and synchronize() surfaces built-in scanner diagnostics as skip events with exported SyncSkipReason values 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 exported pathPassesSyncFilters, directoryMayContainSyncPaths, filterSyncPaths, literalPrefixForSyncFilters, and pathSkippedByRegExpInputLimit helpers 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.maxScanEntries provide 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. Pass Infinity only 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. RawRequestOptions is exported, and RawClient.getUploadUrl, getUploadPartUrl, uploadFile, and uploadPart accept options bags for signal and retry. The older JsonPostOptions export remains as a deprecated alias for source compatibility.
  • Multipart resume exposes public diagnostics and tuning controls. ResumeFileIdMismatchError, onResumeCandidateRejected, onResumePartReused, ResumeCandidateRejectedEvent, ResumeCandidateRejectedReason, ResumePartReusedEvent, ResumePartReusedListener, and the resumeMaxListPages / resumeMaxPartCandidates / resumeMaxPartPages / resumeDiscoveryTimeoutMs options 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, and UnfinishedLargeFileMetadata.
  • FileSource(path) / FileSource.fromPath(path) for Node local-file uploads. FileSource is exported from the main entry and @backblaze-labs/b2-sdk/streams, supports random-access slice() 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 with readFile. 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 Node Readable streams for forward-only uploads.
  • Multipart cleanup diagnostics. Multipart upload, streaming upload, and multipart copy options now accept onCleanupFailure, and the root export includes CleanupFailureEvent / CleanupFailureListener, so failed best-effort b2_cancel_large_file cleanup and deliberately skipped cleanup after ambiguous finish responses are observable with the relevant fileId.

Changed

  • Sync error summary wording now reports total sync errors. The terminal summary event changed from N action(s) failed to N sync error(s) occurred because SHA-1 preparation failures are surfaced alongside transfer/action failures.
  • Sync concurrency validation is now strict. SyncOptions.concurrency must be a positive integer; invalid values such as 0, negative numbers, NaN, or fractions throw RangeError before sync scanning begins.
  • Sync scan errors now preserve readable-file progress. Non-root local scan errors are surfaced as per-path error events while readable siblings continue; if any scan error occurs, destination-only delete/orphan actions are skipped to avoid removing paths hidden by scan failures.
  • compare events now expose bytesHashed. In sha1 mode, local bytes read for hashing are reported as compare.bytesHashed; compare.size remains 0 for compatibility with the previous metadata-only compare event shape. At the type level, compare is now represented by SyncCompareEvent rather than SyncActionEventType, 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's process.getBuiltinModule() API so size is available at construction time; async code should prefer FileSource.fromPath(path).
  • REALM_URLS keeps its mutable Record<string, string> source shape. Runtime realm resolution still trusts only the built-in verified aliases plus direct custom URLs passed to B2Client; 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 standard s3.<region>.backblazeb2.com endpoints. Custom, proxied, or non-standard endpoints must pass region explicitly and should call createS3ClientConfig() during startup o...
Read more

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 29 May 00:59
a45dbdf

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. After B2Client.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 *.local are rejected unconditionally. New B2SsrfError (non-retryable, attaches the offending URL). New public UrlGuard class and deriveAllowedSuffixes() 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.ts fails if the resume module ever imports node: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 onProgress event sequences during multipart uploads.

Added — source-level isomorphism

  • .ts extensions on every internal relative import. tsconfig.json enables allowImportingTsExtensions + rewriteRelativeImportExtensions. One source tree now runs unmodified in Node 22+, Bun, Deno (no build step, no node_modules, no npm: shim), browsers, Cloudflare Workers, and Vercel Edge. Vite rewrites the extensions during build so consumers still see ./foo.js in dist/.
  • Deno typecheck workflow verifies the property on every push: deno check examples/... resolves @backblaze-labs/b2-sdk straight at ../src/*.ts via examples/deno.json. If a .js extension ever sneaks back into an internal import, the workflow fails immediately.
  • JSON-imported version constant. src/version.ts does import 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 separate src/version.ts to 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]). Both b2-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. Custom userAgent from B2ClientOptions is prepended verbatim. New exported constants SDK_PRODUCT and SDK_PACKAGE from @backblaze-labs/b2-sdk.

Added — simulator fidelity & test seams

  • B2 spec input validation in the simulator. validateBucketName, validateFileName, validateFileInfo, validateBucketInfo, and validateMaxCount enforce the limits B2 documents (6-63 char bucket name with b2- reserved-prefix rule, 1024-byte UTF-8 file-name cap, 2048-byte fileInfo / bucketInfo budgets, per-endpoint maxFileCount ceilings). 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/simulator for 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 return 401 bad_auth_token; expired tokens return 401 expired_auth_token; missing capabilities return 403 unauthorized. Default remains permissive so existing tests are unaffected.
  • Virtual clock for expiry tests. B2Simulator.advanceTime(ms) fast-forwards the simulator's internal clock so authTokenTtlMs expiry paths can be exercised without setTimeout.
  • Pluggable post-upload hooks. onWebhookDeliver fires after every successful upload / copy / finishLargeFile against a bucket with matching event-notification rules; onReplicate fires when the bucket is a replication source. Errors thrown from user hooks are routed to the optional onHookError (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. parseRangeHeader returns a tagged result (ok / unsatisfiable / malformed); the simulator now returns 206 with the documented Content-Range: bytes <start>-<end>/<total> header and 416 Range Not Satisfiable (with Content-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_file validates partNumber ∈ [1, 10000] and that partSha1Array.length === uploadedParts.length. b2_delete_key evicts 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 its count budget is spent. Returns a FaultHandle whose .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-examples CI job runs every documented npx 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 both node-download and node-backup-cli restore. A renamed flag, swapped argument order, or stale README command fails CI before reaching users.
  • smoke-examples CI job runs the same examples against an in-memory B2Simulator on every push and PR — zero credentials, zero network, zero cost. Exercises the npx tsx/exports-map resolution path the same way an npm install-ed consumer would.
  • Real-B2 integration workflow (.github/workflows/integration.yml) runs the integration suite sequentially across Node 22 + 24 with max-parallel: 1, on push, PR, weekly schedule, and workflow_dispatch. Defensive sdk-test-* bucket sweep at startup absorbs leftovers from crashed runs.
  • Examples Deno + Bun typecheck jobs. bunx tsc --noEmit -p examples/tsconfig.json and deno check (via examples/deno.json import map) run on every push.

Changed — lint gate

  • pnpm lint now uses biome check --error-on-warnings. Any warning — not just an error — fails CI. The previous 17 baseline warnings (all lint/suspicious/noExplicitAny in test mocks) were converted to as unknown as <RealType> casts.

Changed — CI matrix timeouts

  • LARGE_TEST_TIMEOUT = 60_000 applied to copy + write-stream tests in src/copy/copy.test.ts and src/upload/stream.test.ts, matching the existing calibration in src/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/ against src/ 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.ts files) runs in real Chromium, Firefox, and WebKit via Playwright. CI parallelizes per engine via VITEST_BROWSER_INSTANCE.
  • Isomorphic B2Simulator: handleRequest is now async and the b2_copy_part handler uses the SDK's own sha1Hex (Node node:crypto lazy-loaded, WebCrypto fallback in browsers). Drops the previous node:crypto.createHash top-level import.
  • Pure-JS MD5 fallback in EncryptionKey.fromBytes. When node:crypto.createHash isn'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/promises and node:path imports inside src/sync/synchronizer.ts action 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.ts is skipped in browser mode. Renamed src/auth/file.test.tsfile.node.test.ts, src/sync/scanners/scanners.test.tsscanners.node.test.ts. Added src/streams/encryption-key.node.test.ts for the util.inspect redaction assertion.

Added — robustness

  • Resume support for multipart uploads. Pass resume: true (or an explicit resumeFileId) to uploadLargeFile or Bucket.upload. The engine queries listUnfinishedLargeFiles + listParts and skips parts whose locally-recomputed SHA-1 matches the server's. New src/upload/resume.ts with findResumeCandidate and collectPartSha1s helpers.
  • Per-range retry in createParallelDownloadStream. Each ranged GET is retried independently with exponential backoff and jitter (default 5 attempts). New `maxRetri...
Read more