Skip to content

fix: forward abort signal to middleware and chunked requests#1697

Merged
blacha merged 1 commit into
blacha:masterfrom
kylebarron:fix/forward-abort-signal-to-middleware
May 23, 2026
Merged

fix: forward abort signal to middleware and chunked requests#1697
blacha merged 1 commit into
blacha:masterfrom
kylebarron:fix/forward-abort-signal-to-middleware

Conversation

@kylebarron
Copy link
Copy Markdown
Contributor

@kylebarron kylebarron commented May 21, 2026

Fix two instances of signal not correctly being passed on through the middleware

cc @blacha

blacha#1644 plumbed an optional `signal` through `SourceView.fetch` to the
terminal source, but `SourceView.run` only seeds `req.signal` in the
`middleware == null` branch — which never executes, because `fetch()`
returns early when there is no middleware. So middleware never receives
`req.signal`, even though `SourceRequest` declares it. A consumer that
inspects `req.signal` (e.g. a concurrency limiter that drops a queued
request when its caller aborts) therefore never sees the abort.

`SourceChunk.fetchChunks` likewise dropped the signal on its per-chunk
sub-requests.

Seed `req.signal` from `options?.signal` in the middleware branch of
`run()`, and forward the signal from `fetchChunks`, so middleware and
chunked reads observe aborts. Adds tests for both.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kylebarron added a commit to developmentseed/deck.gl-raster that referenced this pull request May 22, 2026
Replace the internal LimiterMiddleware with an internal LimitedSource
that wraps Source.fetch, composed beneath SourceChunk/SourceCache (cache
hits still short-circuit before it). The middleware approach couldn't
observe aborts: chunkd's SourceView doesn't forward the request signal
to middleware, only to the underlying source via its terminal handler.
Wrapping the source is the only layer that receives options.signal, so
a request whose caller aborts while queued for a slot is now dropped
before any network I/O — previously that never fired.

Internal-only: GeoTIFF.fromUrl options, ConcurrencyLimiter, Priority,
and PerOriginSemaphore are unchanged. Revert to a SourceMiddleware once
chunkd forwards the signal (blacha/chunkd#1697); tracked in #565.

Adds a LimitedSource test that aborts a queued read through the real
acquire path (the gap that hid this).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kylebarron added a commit to developmentseed/deck.gl-raster that referenced this pull request May 22, 2026
* docs: spec for coalescing tile fetches through deck.gl getTileData

Design for #273: a TileBatcher in deck.gl-raster that coalesces deck.gl's
per-tile getTileData calls into one getMultiTileData (-> geotiff.fetchTiles)
call per zoom level, plus a chunkd request-scheduler middleware in geotiff so
maxRequests bounds actual concurrent HTTP requests. No public fetchTiles API
change; no loaders.gl dependency in geotiff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(spec): per-origin concurrency limiter (gating only)

Replaces the prior 2026-05-12 design (which scoped both gating and
multi-tile coalescing into one spec). This narrows to gating: a
ConcurrencyLimiter interface, PerOriginSemaphore default impl, Semaphore
primitive (internal), and integration into GeoTIFF.fromUrl plus a
module-level default on COGLayer.defaultProps so two layers on the same
origin share one HTTP/1.1 connection pool out of the box.

Multi-tile request coalescing (TileBatcher, getMultiTileData,
fetchTilesSettled used from a layer) is explicitly deferred — the
maxRequests / _pruneRequests interaction makes it more involved than
expected and it's worth shipping gating first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): Semaphore primitive with signal-aware acquire

A FIFO counting semaphore that hands out up to `maxRequests` concurrent
slots. acquire(signal?) supports cancellation: an already-aborted signal
rejects immediately without consuming a slot; aborting a queued acquire
splices it from the queue and rejects, leaving the queue's FIFO order
intact for surviving waiters.

Internal primitive — not exported from the package. Building block for
PerOriginSemaphore and limitFetch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): ConcurrencyLimiter interface + PerOriginSemaphore

A small public contract — acquire(url, signal?) returning a release fn —
plus the default implementation that scopes slots per url.origin via an
internal Map<origin, Semaphore>. Multiple consumers (e.g. two COGLayers
on the same S3 bucket) targeting one origin share that origin's pool;
consumers on different origins don't compete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): limitFetch helper

Wraps a Source.fetch so each call goes through a ConcurrencyLimiter's
acquire(url, signal?) — holding the slot for the underlying call's
duration, releasing on resolve and on reject, and forwarding the caller's
AbortSignal so a queued call dropped via abort never fires network I/O.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): export ConcurrencyLimiter type and PerOriginSemaphore class

Semaphore and limitFetch stay internal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): concurrencyLimiter option on GeoTIFF.fromUrl

When supplied, wraps the data source's .fetch via limitFetch so every
tile-data HTTP fetch holds a slot in the supplied ConcurrencyLimiter for
its duration, forwarding the caller's signal so pan-away aborts drop
queued requests. Header/metadata reads (through the cached SourceView)
are not gated. Default is undefined (no gating) — the deck.gl-geotiff
layers wire a shared PerOriginSemaphore default at their defaultProps
level. Pass `null` to explicitly disable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(deck.gl-geotiff): default PerOriginSemaphore + fetchGeoTIFF option

A module-level defaultConcurrencyLimiter = new PerOriginSemaphore({
maxRequests: 6 }) will be wired into COGLayer.defaultProps and
MultiCOGLayer.defaultProps in the following commits, so layers on the
same origin share one HTTP/1.1 connection pool by default.

fetchGeoTIFF gains an options arg with concurrencyLimiter; forwarded to
GeoTIFF.fromUrl for URL/string inputs. ArrayBuffer and pre-opened GeoTIFF
inputs ignore it (the user already wired their own at open time, or
there's no network to gate).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(deck.gl-geotiff): COGLayer.concurrencyLimiter prop + default

Adds concurrencyLimiter to COGLayerProps with a default of the shared
module-level PerOriginSemaphore({ maxRequests: 6 }). Two COGLayers on the
same origin share one HTTP/1.1 connection pool out of the box; pass a
custom ConcurrencyLimiter to override, pass null to disable. The prop is
threaded into _parseGeoTIFF → fetchGeoTIFF → GeoTIFF.fromUrl.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(deck.gl-geotiff): MultiCOGLayer.concurrencyLimiter prop + default

Same shape as COGLayer's prop: defaults to the shared module-level
PerOriginSemaphore so a COGLayer and a MultiCOGLayer hitting the same
origin share one HTTP/1.1 connection pool. Threaded through
_parseAllSources → fetchGeoTIFF → GeoTIFF.fromUrl.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(geotiff): docstrings on Semaphore internals (PR #557 review)

JSDoc on the Waiter fields and the _makeRelease / _releaseOne private
helpers so each unit of the Semaphore primitive carries its own short
explanation. No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(geotiff): limitFetch → LimiterMiddleware class (PR #557 review)

Replace the limitFetch fetch-wrapper with a LimiterMiddleware class that
implements chunkd's SourceMiddleware, matching the shape of SourceChunk
and SourceCache. Slot it into the existing SourceView middleware list in
GeoTIFF.fromUrl, after SourceChunk + SourceCache, so cache hits skip the
limiter and only uncached network reads consume slots. Header reads
(through the cached header view) are now also gated — they're still
mostly served from cache, but the rare cache miss now counts toward the
per-origin cap, which is what callers actually want.

No type cast (the @chunkd vs @cogeotiff Source-type impedance is avoided
because everything composing the middleware in fromUrl is chunkd-typed
from the start).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cleaner

* feat(geotiff): dynamic priority on ConcurrencyLimiter / Semaphore

Adds an optional `getPriority` callback to `Semaphore.acquire`,
`ConcurrencyLimiter.acquire`, and `LimiterMiddleware`. The callback
returns a `number | readonly number[]` (lex-compared, missing trailing
elements treated as 0); it's re-invoked by the limiter on every
slot-open so dynamic state (e.g. distance from viewport center) re-sorts
the queue without callers having to manage queue position themselves.

Implementation uses an unsorted queue + linear-scan find-min on each
release. A heap doesn't help here because dynamic priorities force us to
re-evaluate every waiter's getPriority on every release anyway (we
extract one minimum per release, not several).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): thread getPriority through GeoTIFF.fromUrl + fetchGeoTIFF

Adds optional getPriority callback to GeoTIFF.fromUrl and to the
deck.gl-geotiff fetchGeoTIFF wrapper. fromUrl bakes it into the
LimiterMiddleware so every header + tile-data fetch through this
GeoTIFF's sources is dynamically prioritised against other waiters in
the shared per-origin queue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(deck.gl-geotiff): MosaicLayer passes distance-from-viewport-center as getPriority

MosaicLayer now computes a dynamic `getPriority` closure per source, based
on euclidean distance from the source's bbox center to the layer's
current viewport center (degree-space — just used as an ordering key,
great-circle isn't needed for sort order). It's threaded into the
user-provided `getSource` callback's options so the consumer can forward
it into `fetchGeoTIFF` / `GeoTIFF.fromUrl`.

Each closure reads `this.context.viewport` fresh at call time, so the
limiter re-evaluates priority on every slot-open — panning the viewport
pulls newly-central sources to the front of the queue ahead of older
edge sources, without callers having to manage queue position.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(examples/naip-mosaic): thread getPriority through getCachedGeoTIFF

MosaicLayer now provides a dynamic `getPriority` closure (distance from
viewport center to source bbox) in `getSource`'s opts. The example
forwards it into `getCachedGeoTIFF` → `GeoTIFF.fromUrl({ getPriority })`,
which bakes it into the LimiterMiddleware so every fetch through that
COG's sources is dynamically prioritised against other waiters in the
shared per-origin queue. Result: center-of-screen COGs jump ahead of
edges in the limiter queue, and re-sort on pan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(examples/naip-mosaic): actually install the limiter so priority can fire

getCachedGeoTIFF was calling GeoTIFF.fromUrl with `getPriority` but no
`concurrencyLimiter` — so fromUrl saw the limiter as undefined, skipped
installing LimiterMiddleware entirely, and the priority closure was
never consulted. Pass the shared defaultConcurrencyLimiter (now exported
from @developmentseed/deck.gl-geotiff) so opens and tile-data fetches
both go through the per-origin queue and dynamically re-sort by
viewport-center distance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(deck.gl-geotiff): MosaicLayer concurrencyLimiter prop

Match COGLayer / MultiCOGLayer by accepting a `concurrencyLimiter` prop
(default: shared `defaultConcurrencyLimiter`, opt out with `null`), and
thread it into `getSource`'s opts alongside `getPriority`. Lets a
consumer's `getSource` forward both straight to `GeoTIFF.fromUrl` (or
spread `opts`), so priority can't silently no-op when the user forgets
to also pass the limiter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): gate header fetches through the concurrency limiter

Header reads were temporarily un-gated during the priority work to
isolate whether the data path alone was responsible for the bottom-left
load order. Now that dynamic priority is in place and ordering works as
expected, restore header gating so the browser's HTTP/1.1 6-per-origin
cap isn't the only thing throttling header bursts — the limiter sees
them, can interleave them with data fetches, and consumers keep
explicit control over the queue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(examples/naip-mosaic): forward MosaicLayer opts straight to GeoTIFF.fromUrl

MosaicLayer now defaults `concurrencyLimiter` to the shared
`defaultConcurrencyLimiter` and threads it into `getSource`'s opts
alongside `getPriority`, so the example no longer has to import the
default limiter or stitch the two together by hand. Collapse
`getCachedGeoTIFF` to take an `opts` object that gets spread directly
into `GeoTIFF.fromUrl`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(spec): cover dynamic priority + LimiterMiddleware + MosaicLayer

Update 2026-05-19-concurrency-limiter-design.md to match what's
actually shipped: chunkd `LimiterMiddleware` (not the original
`limitFetch` function), both header and data paths gate (cache hits
short-circuit before the limiter), dynamic `getPriority` re-evaluated
per slot-open with linear-scan find-min, `Priority` type
(`number | readonly number[]`, lex with trailing-zero fill), and
MosaicLayer's viewport-distance closure threaded through `getSource`'s
opts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(geotiff): export GeoTIFFFromUrlOptions; fix stale gating docstring

Extract fromUrl's inline options object into an exported
`GeoTIFFFromUrlOptions` interface so callers can name the type instead
of reaching for `Parameters<typeof GeoTIFF.fromUrl>[1]` (PR #557
review). Also corrects the `concurrencyLimiter` doc, which still
claimed header reads weren't gated — they are now, with cache hits
short-circuiting before the limiter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(deck.gl-geotiff): address PR #557 review round 2

- Cancel in-flight header reads: COGLayer / MultiCOGLayer now hold an
  AbortController per parse, aborting the prior open when the
  geotiff/sources prop changes and on finalizeState, so stale reads
  release their limiter slot immediately. fetchGeoTIFF threads the
  signal through to GeoTIFF.fromUrl.
- MosaicLayer only supplies getPriority for geographic viewports
  (WebMercatorViewport / _GlobeViewport), where the source bbox and
  viewport center share a lon/lat space; otherwise it's omitted and the
  limiter falls back to FIFO.
- Drop MosaicLayer's redundant `=== undefined` defaulting — defaultProps
  already resolves concurrencyLimiter, so forward the prop straight
  through.
- Rename the shared module-level default to DEFAULT_CONCURRENCY_LIMITER
  (UPPER_CASE constant).
- Example forwards MosaicLayer's opts straight into GeoTIFF.fromUrl via
  the new GeoTIFFFromUrlOptions type; trim the verbose comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(geotiff): thread signal into getTileSize header reads

The tile-fetch path resolves each tile's offset/byte-count via
image.getTileSize before reading the data. Those are header-source
reads (lazy per-entry, served by the chunk cache, but a real network
fetch on a cache miss) and now go through the concurrency limiter too.
Without the signal, an aborted tile fetch left the getTileSize read
running and holding its limiter slot. Forward the signal through
getTile, getTiles, and the band-separate range lookup so the offset
reads abort and release their slot alongside the data fetch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* options object

* fix(deck.gl-geotiff): drop debounceTime from MosaicLayer

A non-zero debounceTime stalls all source loading in MosaicLayer:
deck.gl's RequestScheduler re-checks `isSelected` when the debounce
timer fires and cancels anything not selected at that instant, and the
flat, zoomless MosaicTileset2D model churns selection under viewport
changes, so requests are perpetually cancelled and re-scheduled and
nothing loads. Remove the prop from MosaicLayerProps and stop
forwarding it to the inner TileLayer. COGLayer / MultiCOGLayer keep
debounceTime support (hierarchical RasterTileLayer tiles, where it
works). Tracked for a real fix in #562.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* shorter comment

* refactor(deck.gl-geotiff): simplify COG layer AbortController to finalize-only

Per PR #557 review: the per-parse abort-and-recreate handled the
geotiff/sources prop changing mid-open, which is rare and was the
"overkill" part. Drop it. Keep one controller for the layer's lifetime
(created in initializeState, aborted in finalizeState) so a header read
still in flight when the layer is removed is cancelled and its limiter
slot freed — the one clearly useful case. MosaicLayer needs no
controller of its own; it opens GeoTIFFs inside getSource during a tile
load, where deck.gl already supplies a per-tile abort signal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(deck.gl-geotiff): extract createGetPriorityCallback helper

Per PR #557 review: the inline getPriority construction in
MosaicLayer.getTileData was verbose. Pull it into a module-level
createGetPriorityCallback(bbox, getViewport) helper that returns the
distance-from-viewport-center callback (or undefined for non-geographic
viewports). No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(deck.gl-geotiff): extract openCogSources helper

Per PR #557 review: the inline "open all COGs in parallel" block in
MultiCOGLayer._parseAllSources was verbose. Pull it into a module-level
openCogSources(entries, opts) helper that opens each source's GeoTIFF
and resolves its projection, returning null when the signal aborts
mid-open so the caller bails. No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* remove comment

* fix(geotiff): gate via source wrapper so abort-while-queued works

Replace the internal LimiterMiddleware with an internal LimitedSource
that wraps Source.fetch, composed beneath SourceChunk/SourceCache (cache
hits still short-circuit before it). The middleware approach couldn't
observe aborts: chunkd's SourceView doesn't forward the request signal
to middleware, only to the underlying source via its terminal handler.
Wrapping the source is the only layer that receives options.signal, so
a request whose caller aborts while queued for a slot is now dropped
before any network I/O — previously that never fired.

Internal-only: GeoTIFF.fromUrl options, ConcurrencyLimiter, Priority,
and PerOriginSemaphore are unchanged. Revert to a SourceMiddleware once
chunkd forwards the signal (blacha/chunkd#1697); tracked in #565.

Adds a LimitedSource test that aborts a queued read through the real
acquire path (the gap that hid this).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(geotiff): abort a queued fromUrl header read end-to-end

Proves the full chain (GeoTIFF.fromUrl -> open -> cogeotiff ->
LimitedSource -> limiter) drops a header read still queued for a slot
when its signal aborts, without ever fetching it. Saturate a
maxRequests:1 PerOriginSemaphore with a first open, queue a second open
behind it, abort the second, and assert it rejects and never hits the
network. Closes the coverage gap that hid the chunkd signal bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(deck.gl-geotiff): don't forward undefined maxRequests from MosaicLayer

MosaicLayer forwarded `maxRequests` to the inner TileLayer
unconditionally, and its defaultProps never set it — so it passed
`undefined`. deck.gl's createProps copies `undefined` over the
prototype, shadowing TileLayer's default of 6 with `undefined`. That
left Tileset2D with maxRequests undefined, which disables BOTH request
throttling and `_pruneRequests` (gated on `maxRequests > 0`) — and
`_pruneRequests` is the only thing that calls `tile.abort()`. So the
concurrency limiter never received a cancellation: panned-out source
header reads were never dropped, starving the current viewport.

Only forward `maxRequests` when defined, so TileLayer's own default
applies. Now pruning fires on pan, the tile signal aborts, and the
limiter drops the queued header reads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(deck.gl-geotiff): omit undefined when forwarding TileLayerProps

Generalize the maxRequests fix: forward MosaicLayer's pass-through
TileLayerProps (minZoom, maxZoom, extent, maxCacheByteSize,
maxCacheSize, maxRequests) through a small omitUndefined() helper rather
than tracking per-prop which can safely be undefined. deck.gl's
createProps copies an explicit `undefined` over the prototype, so an
unset prop forwarded as `undefined` shadows TileLayer's own default
instead of falling back to it. Omitting undefined keys lets TileLayer's
defaults apply uniformly, so we don't have to remember which props
tolerate undefined.

Behavior-neutral except the already-fixed maxRequests: the only other
prop whose resolved value changes is minZoom (undefined -> TileLayer's
0), and that just bounds the tileset at viewport zoom >= 0 — the
whole-world view and in — which is the normal range anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cleaner comment

* concise

* concsie

* concise

* concise

* move up abort signal check

* doc comment

* fix(deck.gl-geotiff,geotiff): address round-2 review nits

- comparePriorities: extract a normalizePriorityValue() helper that maps
  undefined/NaN to 0, so a getPriority returning NaN sorts as
  un-prioritized instead of silently comparing as a tie with everything
  (NaN < x and NaN > x are both false).
- MultiCOGLayer._parseAllSources: bail when there are no sources, before
  the cogSources[0] (first source's projection) access that would throw
  on an empty `sources`.
- naip-mosaic example: reword the maxCacheSize: 0 comment (it disables
  the cache, not "smaller"), and drop a leftover `window.data` debug
  assignment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cleaner options

* concise

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@blacha blacha merged commit 372a96d into blacha:master May 23, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request May 23, 2026
blacha pushed a commit that referenced this pull request May 23, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>fs: 11.5.2</summary>

##
[11.5.2](fs-v11.5.1...fs-v11.5.2)
(2026-05-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/source bumped from ^11.4.0 to ^11.4.1
    * @chunkd/source-memory bumped from ^11.2.0 to ^11.2.1
    * @chunkd/source-file bumped from ^11.2.0 to ^11.2.1
    * @chunkd/source-http bumped from ^11.4.0 to ^11.4.1
</details>

<details><summary>fs-aws: 11.6.2</summary>

##
[11.6.2](fs-aws-v11.6.1...fs-aws-v11.6.2)
(2026-05-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/fs bumped from 11.5.1 to 11.5.2
    * @chunkd/source-aws bumped from 11.2.0 to 11.2.1
</details>

<details><summary>middleware: 11.3.1</summary>

##
[11.3.1](middleware-v11.3.0...middleware-v11.3.1)
(2026-05-23)


### Bug Fixes

* forward abort signal to middleware and chunked requests
([#1697](#1697))
([372a96d](372a96d))


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/source bumped from ^11.4.0 to ^11.4.1
</details>

<details><summary>source: 11.4.1</summary>

##
[11.4.1](source-v11.4.0...source-v11.4.1)
(2026-05-23)


### Bug Fixes

* forward abort signal to middleware and chunked requests
([#1697](#1697))
([372a96d](372a96d))
</details>

<details><summary>source-aws: 11.2.1</summary>

##
[11.2.1](source-aws-v11.2.0...source-aws-v11.2.1)
(2026-05-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/source bumped from ^11.4.0 to ^11.4.1
</details>

<details><summary>source-file: 11.2.1</summary>

##
[11.2.1](source-file-v11.2.0...source-file-v11.2.1)
(2026-05-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/source bumped from ^11.4.0 to ^11.4.1
</details>

<details><summary>source-http: 11.4.1</summary>

##
[11.4.1](source-http-v11.4.0...source-http-v11.4.1)
(2026-05-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/source bumped from ^11.4.0 to ^11.4.1
</details>

<details><summary>source-memory: 11.2.1</summary>

##
[11.2.1](source-memory-v11.2.0...source-memory-v11.2.1)
(2026-05-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @chunkd/source bumped from ^11.4.0 to ^11.4.1
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants