Skip to content

feat: align async STAC resolver with Python client - #12

Open
0xSwego wants to merge 6 commits into
mainfrom
agent/native-async-stac-parity
Open

feat: align async STAC resolver with Python client#12
0xSwego wants to merge 6 commits into
mainfrom
agent/native-async-stac-parity

Conversation

@0xSwego

@0xSwego 0xSwego commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • Export the existing asynchronous STAC CID resolvers from the package root and document direct resolver usage.
  • Share one bounded pagination implementation between CID resolution and catalog listing.
  • Reject cross-origin, credential-bearing, and unsupported-method pagination links.
  • Disable automatic redirect following and avoid forwarding server-provided continuation headers over plaintext HTTP.
  • Detect repeated pagination requests and use all search pages when listing datasets.
  • Add focused resolver/listing parity tests and repository-level guidance for keeping the Python and JavaScript clients aligned.
  • Bump the package version from 0.6.0 to 0.7.0.

Why

The JavaScript client was already asynchronous and already used the resolver internally, so Python event-loop pooling and explicit client cleanup do not apply. However, the resolver was not exported from the package root, catalog listing stopped after one page, and pagination did not have the request hardening added in dClimate/dclimate-client-py#16.

Impact

Consumers can resolve a CID directly through the public package API. Existing high-level loading behavior is unchanged. Resolver and listing pagination now have the same trust boundary and bounded-walk behavior as the Python client, adapted to the platform-owned fetch transport.

Validation

  • npm run lint: passed
  • Focused STAC suite: 26 passed
  • npm run build: browser and Node builds passed
  • Full suite attempted: 195 passed and 13 live integration tests failed because the current external IPFS/catalog data timed out or now requires an explicit grouped-Zarr level; the focused unit suite is green.

Summary by CodeRabbit

  • New Features

    • Added public tools for resolving dataset CIDs from STAC servers.
    • Added paginated STAC search for CID resolution and dataset discovery.
    • Added support for GET and POST searches with safer link handling.
  • Documentation

    • Added usage guidance and API references for STAC CID resolution and dataset discovery.
  • Bug Fixes

    • Improved pagination limits, redirects, credential handling, and protection against untrusted links.
    • Improved handling of empty pages and repeated pagination requests.
    • Corrected loading options for the fpar dataset.
  • Chores

    • Updated the package version to 0.7.0.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The client now uses shared, bounded STAC pagination for CID resolution and dataset discovery. It validates continuation requests, supports GET and POST pages, handles redirects manually, exposes related APIs and types, updates documentation and version metadata, and adds parity and pagination tests.

Changes

STAC pagination and public API

Layer / File(s) Summary
Public API and release surface
AGENTS.md, src/index.ts, package.json, README.md
Added JavaScript/Python parity guidance, exported STAC resolution APIs and types, updated the package version to 0.7.0, and documented the STAC helpers.
Shared STAC pagination
src/stac/stac-server.ts
Added normalized and validated pagination with GET/POST support, protected continuation links, manual redirects, response validation, bounded iteration, and integration with CID resolution and dataset listing.
Pagination and parity validation
tests/review-fixes/stac-server-pagination.test.ts, tests/review-fixes/stac-server-parity.test.ts, tests/geotemporal-dataset.test.ts
Updated empty-page and truncation coverage. Added tests for untrusted links, repeated requests, POST bodies, headers, redirects, paginated dataset discovery, and dataset-loading options.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant resolveCidFromStacServer
  participant searchPages
  participant STACServer
  Client->>resolveCidFromStacServer: request CID resolution
  resolveCidFromStacServer->>searchPages: start paginated search
  searchPages->>STACServer: send validated search request
  STACServer-->>searchPages: return features and continuation link
  searchPages->>STACServer: request validated next page
  STACServer-->>searchPages: return additional features
  searchPages-->>resolveCidFromStacServer: return collected features
  resolveCidFromStacServer-->>Client: return resolved CID
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: aligning the asynchronous STAC resolver with the Python client.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/native-async-stac-parity

Comment @coderabbitai help to get the list of available commands.

@0xSwego
0xSwego marked this pull request as ready for review August 7, 2026 09:43

@da-code-reviewer da-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Automated Review

Found one pagination correctness regression.
Posted 1 inline comment(s).

Comment thread src/stac/stac-server.ts Outdated
yield page;

const features = Array.isArray(page.features) ? page.features : [];
if (features.length === 0) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
Returning when a page has no features ignores an explicit rel="next" link. An empty intermediate page therefore prevents later pages from being fetched, causing false “not found” errors and incomplete catalog listings. Treat the absence of a next request—not an empty feature array—as the terminal condition.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 18e5a21 by making the absence of a valid next request the pagination terminator, regardless of whether the current page is empty. Added a regression test with an empty second page linking to a non-empty third page; all 27 focused STAC tests, lint, and both builds pass.

@da-code-reviewer da-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Automated Review

Found two pagination correctness issues.
Posted 2 inline comment(s).

Comment thread src/stac/stac-server.ts Outdated
stableJson(request.body),
stableJson(request.headers),
].join("\n");
if (seen.has(pageKey)) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
A repeated request is treated as successful completion. This return lets callers consume a partial feature set when a malformed next link cycles: CID resolution can report “not found” or select the wrong variant, while catalog listing returns incomplete data without triggering its fallback. Throw a pagination/truncation error instead.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in f569492. A repeated pagination request key now throws an explicit truncation error instead of returning accumulated partial features. The regression verifies the resolver rejects after the first request; all 29 focused STAC tests, lint, and both builds pass.

Comment thread src/stac/stac-server.ts Outdated
? { "Content-Type": "application/json", ...request.headers }
: request.headers,
...(request.method === "POST"
? { body: JSON.stringify(request.body ?? null) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
Do not serialize an absent POST continuation body as null. A POST next link may paginate solely through its URL or headers, leaving request.body undefined; this then sends literal JSON null, although STAC search bodies are objects, so compliant servers may reject the continuation. Send {} or omit the body when absent. STAC pagination specification

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in f569492. A POST continuation without a body now sends an empty JSON object instead of literal null, preserving a valid STAC search body for URL- or header-only cursors. Regression coverage passes with all 29 focused STAC tests, lint, and both builds.

@da-code-reviewer da-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Automated Review

Found one actionable pagination reliability issue.
Posted 1 inline comment(s).

Comment thread src/stac/stac-server.ts Outdated
for (let pageNumber = 0; pageNumber < MAX_STAC_SEARCH_PAGES; pageNumber++) {
const pageKey = [
request.method,
request.url,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
pageKey uses the raw link URL, but fragments are never sent in HTTP requests. Links such as /search#1, /search#2, etc. therefore trigger up to 50 identical requests while appearing unique to seen. Build the key from the final request URL and remove its fragment before checking for repetition.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 8856f7c. The repetition key now uses the final request URL after GET parameter expansion and fragment removal, and POST bodies are keyed exactly as transmitted. A regression cycles fragment-only next links and verifies the duplicate request is rejected; all 30 focused STAC tests, lint, and both builds pass.

@da-code-reviewer da-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Automated Review

Found one actionable pagination compatibility regression.
Posted 1 inline comment(s).

Comment thread src/stac/stac-server.ts Outdated
function stringHeaders(value: unknown): StacSearchHeaders {
if (!isRecord(value)) return {};
const entries = Object.entries(value);
if (!entries.every(([, headerValue]) => typeof headerValue === "string")) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
STAC 1.1 Link headers permit values to be strings or arrays of strings. This all-or-nothing check drops every continuation header when any value is an array, so header-based cursors can fetch the wrong page and end in a truncation error. Normalize valid arrays and reject only invalid entries.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 54a2c9b. Continuation headers now accept strings and arrays of strings, join valid arrays using the standard comma-separated representation, and discard only invalid entries while preserving valid siblings. The regression covers all three cases. I also updated the live grouped FPAR fixture to select its advertised Zarr group 0; all 213 tests, lint, and both builds pass.

@da-code-reviewer da-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Automated Review

Found two actionable regressions in the pagination hardening.
Posted 2 inline comment(s).

Comment thread src/stac/stac-server.ts
}

function requestUrl(request: StacSearchRequest): string {
const url = new URL(request.url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
Relative STAC server URLs now fail before the first request. Browser callers could previously use a same-origin URL such as /stac, which fetch resolves normally. new URL(request.url) has no base and throws for /stac/search, breaking both resolution and catalog listing. Resolve relative configuration against location.href before pagination and origin validation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 1020b87. STAC server URLs are now resolved against location.href when a browser supplies one, before request construction and same-origin validation. Catalog listing reuses the same resolved base for /collections. Regressions cover /stac, a relative next link, and both catalog endpoints; all 216 tests, lint, and both builds pass.

Comment thread src/stac/stac-server.ts Outdated
parsedNextUrl.password !== ""
) {
throw new Error(
`STAC pagination link must use the configured server origin ${normalizedOrigin(serverUrl)}: ${nextUrl}`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW
Rejected pagination links expose embedded credentials. nextUrl retains username, password, and query tokens, so interpolating the full URL into the exception can disclose them through application error handling or logs. Report a sanitized URL with userinfo and sensitive query data removed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 1020b87. Rejected pagination URLs are now sanitized before interpolation: userinfo, the complete query string, and fragments are removed while the safe origin/path remain useful for diagnosis. The regression verifies the error contains only https://attacker.example/collect; all 216 tests, lint, and both builds pass.

@da-code-reviewer da-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Automated Review

No high-confidence actionable issues found.
No inline issues were posted.

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.

1 participant