Skip to content

fix(http): guard relative baseURL — closes queue #21#77

Open
Goosterhof wants to merge 3 commits into
mainfrom
medic/queue-21-relative-baseurl-guard
Open

fix(http): guard relative baseURL — closes queue #21#77
Goosterhof wants to merge 3 commits into
mainfrom
medic/queue-21-relative-baseurl-guard

Conversation

@Goosterhof
Copy link
Copy Markdown
Contributor

Summary

  • Wrap new URL(baseURL) in createHttpService with a library-attributed error so relative paths like '/api' fail fast with a message that names the package, names the function, explains what's needed, and echoes the offending value — instead of the opaque native TypeError: Invalid URL that points at fs-http internals.
  • Bumps @script-development/fs-http 0.3.0 → 0.3.1 (patch — additive guard on previously-undefined behavior, no API change).
  • Closes enforcement queue #21.

Seed Incident

Latent for 6 days on entreezuil (PR #40 adoption → PR #96 fix). Integration tests mock @script-development/fs-http, so the real factory never ran in CI — the bug surfaced only at runtime in production. Library-side fail-fast prevents the class for every future fs-http adopter.

Error Message Shape

[@script-development/fs-http] createHttpService requires an absolute baseURL (e.g. `${location.origin}/api`). Received: "/api"

Names the package, names the function, gives an actionable example, echoes the offending value (via JSON.stringify so empty strings, whitespace, and quoting are visible).

Out of Scope (per orders)

  • Auto-coercing relative URLs to absolute — silently wrong direction; chose fail-fast.
  • Adding an oxlint call-site rule — alternative path noted in queue chore(deps-dev): bump the oxc group with 2 updates #21; library-layer guard is the path chosen here.
  • Touching streamRequest, withXSRFToken, withCredentials, or any other surface (Armorer is on a parallel docs-only XSRF PR; staying out of that lane).
  • Cascading peer-range bumps — patch bump on fs-http stays within consumer ^0.3.0 ranges; verified with grep on packages/adapter-store/package.json + packages/loading/package.json.

Stash-and-rerun Proof

Pre-fix run of the 4 new guard tests against unmodified source:

× throws a library-attributed error when called with a relative path  → 'Invalid URL'
× throws a library-attributed error when called with an empty string  → 'Invalid URL'
× throws a library-attributed error for malformed URL strings         → 'Invalid URL'
✓ does NOT throw for valid absolute URLs (happy-path regression guard)

Post-fix: 4/4 pass. Bug reproduced as documented; fix verified to be what made the difference.

CI Gates (8/8 PASS locally)

# Gate Result
1 npm audit 0 vulnerabilities
2 npm run format:check clean (133 files)
3 npm run lint 0 warnings / 0 errors (95 rules, 83 files)
4 npm run build dual ESM + CJS produced for fs-http (and all 10 packages)
5 npm run typecheck clean across all packages
6 npm run lint:pkg publint + attw zero advisories on all 10 packages
7 npm run test:coverage 400/400 pass (was 396, +4 new), 100% statements/branches/functions/lines
8 npx stryker run (packages/http) 97.44% mutation (was 97.30% pre-fix), 76/78 killed, 2 surviving — both pre-existing on unregister's index > -1 check, unrelated. No regression of pre-existing survivors.

Lockfile sanity: package-lock.json regenerated; all 10 node_modules/@script-development/* resolve to workspace symlinks ("link": true); no nested registry copies.

Test Plan

  • Pre-fix: 3 negative cases fail with native TypeError: Invalid URL (proof captured)
  • Post-fix: 4 new guard tests pass; existing 45 tests still pass
  • Coverage: 100% maintained (400/400 tests, 100% across all metrics)
  • Mutation: ≥90% maintained (97.44%); pre-existing survivors not regressed
  • All 8 CI gates green locally

🤖 Generated with Claude Code

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 8, 2026

Deploying fs-packages with  Cloudflare Pages  Cloudflare Pages

Latest commit: 22da1c0
Status: ✅  Deploy successful!
Preview URL: https://9b793e41.fs-packages.pages.dev
Branch Preview URL: https://medic-queue-21-relative-base.fs-packages.pages.dev

View logs

Goosterhof and others added 3 commits May 8, 2026 12:47
createHttpService(baseURL) previously called `new URL(baseURL)` directly,
which throws an opaque native `TypeError: Invalid URL` on relative paths
like '/api'. The error pointed at fs-http internals rather than the
consumer's call site. This was latent for 6 days on entreezuil
(PR #40 adoption -> PR #96 fix) because integration tests mock
@script-development/fs-http and the real factory never ran in CI.

Wrap the URL parse in a `parseBaseURL` helper that catches the native
TypeError and re-throws a library-attributed Error naming the package
(@script-development/fs-http), the function (createHttpService), the
expectation (absolute baseURL with example), and the offending value
(JSON.stringify of the input).

Library-side fail-fast prevents the class for every fs-http adopter.
Closes enforcement queue #21.

Tests: 4 new guard cases (relative '/api', empty string, malformed
strings 'not a url' / 'http://', happy-path regression for absolute
URLs). Pre-fix all 3 negative cases failed with 'Invalid URL'; post-fix
all 4 pass. Stash-and-rerun proof captured.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patch bump — additive guard on previously-undefined behavior, no API
change. Existing absolute-URL behavior unchanged. Consumer peer ranges
already include `^0.3.0` (verified packages/adapter-store/package.json
+ packages/loading/package.json) — no peer-range cascade required.

Lockfile regenerated; all @script-development/* still resolve to
workspace symlinks (no nested registry copies).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
One-liner clarification on the existing baseURL row of the
createHttpService API Reference table. The library-attributed error
message remains the primary documentation surface for the failure
path; this is the static-page corollary so consumers reading the API
table before writing the call site see the constraint up front.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Goosterhof Goosterhof force-pushed the medic/queue-21-relative-baseurl-guard branch from 41373b5 to 22da1c0 Compare May 8, 2026 10:48
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