fix(http): guard relative baseURL — closes queue #21#77
Conversation
Deploying fs-packages with
|
| Latest commit: |
222991f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://fe9d1f89.fs-packages.pages.dev |
| Branch Preview URL: | https://medic-queue-21-relative-base.fs-packages.pages.dev |
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>
41373b5 to
22da1c0
Compare
|
Library-attributed error met de echte call-site is de goede keuze ipv stille coercion — de entreezuil-incident class is hiermee voor elke adopter weggevangen. CHANGELOG noemt het pakket, de functie, het echo'd de bad input, en attribueert de latency naar de mock-in-tests root cause. Happy-path regression test in dezelfde describe-block is mooi. CONFLICTING op de moment — pls rebase op main na #95 (npm audit) + #88 (sideEffects) landen, dan kan deze door. |
PR Reviewer · 9/10 · PASS
Findings
Actionmerge-ready |
…ve-baseurl-guard # Conflicts: # docs/packages/http.md # package-lock.json # packages/http/CHANGELOG.md # packages/http/package.json
Goosterhof
left a comment
There was a problem hiding this comment.
No blockers. One concern, two nits, and one load-bearing decision worth naming. This is a tight, well-scoped patch that does exactly what queue #21 asked.
Concern
The malformed-URL guard catches more than "relative baseURL" — and that's good, but the framing undersells it. parseBaseURL (packages/http/src/http.ts:39-47) wraps any new URL(baseURL) failure, so it also fires on 'not a url', 'http://', and '' — all confirmed in tests/http.spec.ts:60-74. The error message, however, is hard-coded to requires an absolute baseURL. For 'http://' (a malformed-but-arguably-absolute input) the message is slightly misleading — the real failure is "unparseable", not "relative". This is defensible: the dominant real-world failure mode is the relative path, and a single clear message beats branching on URL failure subtypes that the platform doesn't cleanly expose. Flagging it only so the choice is conscious — if a consumer ever passes 'http://' and reads "requires an absolute baseURL", the message points them slightly off. Not worth a code change unless you want to soften the wording to "requires a valid absolute baseURL".
Nits
The PR body Summary says the bump is 0.3.0 → 0.3.1, but the actual diff bumps 0.4.0 → 0.4.1 (packages/http/package.json:3, package-lock.json:10231) — verified against origin/main, which sits at 0.4.0. The diff is correct; the body text is stale. Worth fixing the description so the changelog narrative and the PR record agree.
The malformed-URL test (tests/http.spec.ts:60-74) asserts the package-name prefix on every case but only spot-checks absolute baseURL on the relative-path and empty-string cases, not on 'http://'. If the message ever diverges by input class (per the concern above), that case wouldn't catch it. Minor — the current single-message implementation makes this redundant, not wrong.
Praise
The 6-day-latency provenance baked into the parseBaseURL docblock (packages/http/src/http.ts:32-38) is the right call — it records why the guard exists (consumers mock @script-development/fs-http in integration tests, so the real factory never runs in CI; the bug only surfaces at runtime) directly at the code that would otherwise look like defensive over-engineering. That comment is what stops a future contributor from deleting the guard as "the platform already throws on bad URLs." It does throw — opaquely, pointed at library internals — and the comment captures exactly that distinction. Library-layer fail-fast over consumer-side lint is also the correct lever for a defect class that recurs across every adopter.
Verdict: COMMENT — mergeable as-is. The version-number discrepancy in the body is cosmetic (the diff is authoritative and correct); fix it before merge for record hygiene, but it doesn't block.
jasperboerhof
left a comment
There was a problem hiding this comment.
Approved — reviewed, no blockers.
Summary
new URL(baseURL)increateHttpServicewith 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 nativeTypeError: Invalid URLthat points at fs-http internals.@script-development/fs-http0.4.0 → 0.4.1 (patch — additive guard on previously-undefined behavior, no API change).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
Names the package, names the function, gives an actionable example, echoes the offending value (via
JSON.stringifyso empty strings, whitespace, and quoting are visible).Out of Scope (per orders)
streamRequest,withXSRFToken,withCredentials, or any other surface (Armorer is on a parallel docs-only XSRF PR; staying out of that lane).^0.4.0ranges; verified with grep onpackages/adapter-store/package.json+packages/loading/package.json.Stash-and-rerun Proof
Pre-fix run of the 4 new guard tests against unmodified source:
Post-fix: 4/4 pass. Bug reproduced as documented; fix verified to be what made the difference.
CI Gates (8/8 PASS locally)
npm auditnpm run format:checknpm run lintnpm run buildnpm run typechecknpm run lint:pkgnpm run test:coveragenpx stryker run(packages/http)unregister'sindex > -1check, unrelated. No regression of pre-existing survivors.Lockfile sanity:
package-lock.jsonregenerated; all 10node_modules/@script-development/*resolve to workspace symlinks ("link": true); no nested registry copies.Test Plan
TypeError: Invalid URL(proof captured)🤖 Generated with Claude Code