CHANGES IN VERSION 0.99.5
-------------------------

NEW FEATURES

    o S3-compatible services: `gdsCloudConfigS3()` gains `endpoint=` and
      `path_style=` (also read from AWS_ENDPOINT_URL_S3 / AWS_ENDPOINT_URL
      and GDSCLOUD_S3_PATH_STYLE), so `s3://` URLs can point at MinIO,
      Ceph RGW, Cloudflare R2, Wasabi, Backblaze B2, DigitalOcean Spaces
      and other services implementing the S3 API

    o Azure: `gdsCloudConfigAzure()` gains `access_token=` (OAuth2 /
      Microsoft Entra ID), `endpoint_suffix=` (sovereign clouds such as
      Azure China or Azure Government) and `endpoint=` (Azurite emulator
      or any self-hosted blob endpoint); the corresponding
      AZURE_STORAGE_* environment variables and the fields of
      AZURE_STORAGE_CONNECTION_STRING are read as fallbacks

    o The token arguments `access_token` (`gdsCloudConfigGCS()`,
      `gdsCloudConfigAzure()`) and `bearer_token` (`gdsCloudConfigHTTP()`)
      may be a function returning the token; it is called each time a
      file is opened, so expiring tokens (Google OAuth2, Microsoft Entra
      ID) can be refreshed by plugging in gargle, AzureAuth or similar
      packages. Keys remain plain strings

    o `gdsCloudConfigS3(credentials=)` takes a function returning the
      access key, secret and session token as one set, called each time a
      file is opened, for AWS temporary credentials (STS, SSO, instance
      roles) obtained e.g. from `aws configure export-credentials` or
      aws.signature

    o Cloud requests now have a connect timeout (30 s) and a low-speed
      timeout (60 s below 1 byte/s), so a stalled connection no longer
      blocks R indefinitely

    o New `gdsCloudOptions()` to get or set the package options in one
      place: `connect_timeout`, `timeout`, `max_retries` and `cache_size`.
      The initial
      values can be set via the R options `gdscloud.connect_timeout`,
      `gdscloud.timeout`, `gdscloud.cache_size_mb` or the corresponding
      GDSCLOUD_* environment variables; `gdsCloudExportCredentials()`
      copies the options to the workers as well

    o Transfers can be interrupted with Ctrl-C; the interrupt is detected
      from libcurl's progress callback and reported as an error

    o Transient failures (connection resets, timeouts, HTTP 408/429/5xx)
      are retried with exponential back-off, by default up to 3 times;
      `gdsCloudOptions(max_retries=)` controls this and
      `gdsCloudCacheInfo()` reports the number of retried requests

USER-VISIBLE CHANGES

    o Continuous integration: `R CMD check` and BiocCheck run on GitHub
      Actions (Linux, macOS, Windows) for every push and pull request;
      the tests use a local HTTP server (httpuv, callr) and need no
      network or cloud account

    o The four backends now share one generic libcurl backend
      (src/curl_backend.c): transfers, Range validation, timeouts,
      retries, interrupts, size detection and error formatting are
      implemented once; a provider only resolves the URL and signs the
      request. Error messages for HTTP failures now include the service's
      request id when the response carries one

    o Object keys and blob names are percent-encoded when building the
      request URL (and the AWS SigV4 canonical URI), so keys containing
      spaces, '+' or non-ASCII characters can be opened

BUG FIXES

    o Range reads now verify the server's response: a server that ignores
      the HTTP Range header (answering 200 with the whole file) or reports
      a different Content-Range start is rejected with a clear error;
      previously the wrong bytes were silently cached as the requested
      block. The transfer is aborted as soon as the mismatch is detected,
      so the whole file is not downloaded.

    o The Azure Shared Key is now base64-decoded once, into a bounded
      buffer, when the file is opened; an invalid or over-long key gives an
      immediate error instead of a stack buffer overflow (over-long input)
      or an HMAC over garbage (decoding failure was ignored).


CHANGES IN VERSION 0.99.4
-------------------------

USER-VISIBLE CHANGES

    o the cloud URL handlers are now registered with the exported
      `gdsfmt::gdsRegisterCloudHandler()` / `gdsfmt::gdsUnregisterCloudHandler()`
      instead of reaching into the gdsfmt namespace; gdsfmt (>= 1.49.7) is
      required

BUG FIXES

    o `.onUnload()` now actually unregisters the cloud handlers from gdsfmt;
      the hook it previously called did not exist in gdsfmt


CHANGES IN VERSION 0.99.3
-------------------------

NEW FEATURES

    o The default block-cache size can now be set persistently via the
      `gdscloud.cache_size_mb` option or the `GDSCLOUD_CACHE_SIZE_MB`
      environment variable, in addition to `gdsCloudCacheSize()`

    o Cloud requests now send a descriptive HTTP User-Agent identifying
      gdscloud instead of the default libcurl user agent

    o Added a package-level manual page (`?gdscloud`)

BUG FIXES

    o Protected the GDS file object during attribute assignment in the C
      code, addressing an rchk warning about a missing `PROTECT()`

    o Cloud URL handler registration in `.onLoad()` is now performed
      defensively, so the package can still load even if the gdsfmt
      registration hook is unavailable

USER-VISIBLE CHANGES

    o `gdsCloudOpen()` now derives the set of accepted URL schemes from
      `gdsCloudSchemes()`

    o Added a keyring-based example in the vignette for keeping
      credentials out of the R and shell history


CHANGES IN VERSION 0.99.0
-------------------------

NEW FEATURES

    o Direct support for HTTP/HTTPS URLs (`http://` and `https://`) in
      `gdsCloudOpen()`, allowing GDS files to be opened from any web server
      that supports HTTP Range requests

    o Cloud storage access for GDS files via Amazon S3 (`s3://`), Google
      Cloud Storage (`gs://`), and Azure Blob Storage (`az://`)

    o Transparent integration with `openfn.gds()` from the gdsfmt package,
      loading gdscloud enables cloud URL support automatically

    o LRU block cache (1 MB blocks, default 64 MB) for efficient random
      access with minimal HTTP requests

    o `gdsCloudConfigHTTP()` for configuring optional Bearer token
      authentication for HTTP/HTTPS endpoints; also reads the
      `GDSCLOUD_HTTP_TOKEN` environment variable as a fallback

    o Credential configuration functions: `gdsCloudConfigS3()`,
      `gdsCloudConfigGCS()`, `gdsCloudConfigAzure()`, with fallback to
      environment variables

    o `gdsCloudExportCredentials()` copies configured cloud credentials
      to child processes of a parallel cluster, for use with
      `SeqArray::seqParallel()`

    o Cache control: `gdsCloudCacheSize()`, `gdsCloudCacheClear()`,
      `gdsCloudCacheInfo()`

    o `gdsCloudList()` to list all open cloud streams with per-stream
      cache statistics
