feat(api/baseline): add web-features/baseline data endpoint#498
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new /api/baseline API surface that serves the web-features “Baseline” dataset from a local on-disk cache, with endpoints for full dataset retrieval, single-feature lookup (including moved/split handling), spec-URL search, and a webhook-triggered background refresh flow.
Changes:
- Introduces
GET /api/baselineandGET /api/baseline/:featureroutes backed by an in-memory store loaded fromDATA_DIR/baseline/baseline.json. - Adds
POST /api/baseline/searchfor spec-URL-based feature matching using a spec→feature index. - Implements a GitHub-releases-based scraper plus
/api/baseline/updatebackground worker integration, and wires the router + update script + env secret.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/update-data-sources.ts | Runs the baseline scraper as part of the existing data-source refresh script. |
| routes/api/baseline/update.worker.ts | Worker entrypoint that invokes the baseline scraper in a background thread. |
| routes/api/baseline/update.ts | Webhook route that enqueues the background update job and reloads the store. |
| routes/api/baseline/search.post.ts | Implements POST search by spec URLs against the in-memory spec index. |
| routes/api/baseline/lib/store.ts | Defines dataset types, URL normalization, and builds in-memory indexes from baseline.json. |
| routes/api/baseline/lib/store-init.ts | Initializes a singleton BaselineStore used by the handlers. |
| routes/api/baseline/lib/scraper.ts | Downloads data.json from the latest web-features GitHub release into DATA_DIR. |
| routes/api/baseline/index.ts | Express router wiring (CORS, JSON body parsing, webhook auth). |
| routes/api/baseline/feature.ts | Implements single-feature lookup with moved/split resolution behavior. |
| routes/api/baseline/all.ts | Implements full dataset retrieval. |
| app.ts | Mounts the new router at /api/baseline. |
| .env.sample | Adds WEB_FEATURES_SECRET for webhook authentication configuration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
403ac39 to
8f9a564
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e80f029 to
5381c80
Compare
Adds endpoints for serving Baseline browser availability data: - GET /api/baseline — full web-features dataset - GET /api/baseline/:feature — single feature lookup - POST /api/baseline/search — spec-URL-based feature search Data sourced from web-platform-dx/web-features GitHub releases. Enables ReSpec's implementationStatus feature (speced/respec#5174) without requiring unpkg.com dependency. Closes #490
Client expects {result: WebFeatureEntry[]}, server was returning
Record<string, {id, feature}[]>. Flatten features, deduplicate by
ID, and wrap in {result: [...]}.
5381c80 to
a8d58be
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@copilot can you fix any unaddressed comments |
- search.post.ts: return 503 when store.data is null (service unavailable) - search.post.ts: reject empty/whitespace-only strings in specs array - store.ts: normalizeUrl() now also clears search params (query string) - scraper.ts: add ETag/If-None-Match support to skip unnecessary re-downloads - scraper.ts: use atomic write (temp file + rename) to prevent corrupt data on interrupted writes - Add tests: normalizeUrl, feature route (moved/split/404), search.post validation Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/41823caf-5a5e-40fc-8bf7-fca753fb37ab
Fixed all unresolved comments in commits 9e87c3a and 1e3cafc:
|
|
@copilot Can you review this and fix any issues that come up? |
|
@copilot Can you confirm that all your comments have been addressed? Please resolve them if you’re happy. Can you fix anything new you see or outstanding from your feedback that hasn’t been addressed? |
…tions, fix XSS - Return 400 (not 200) for non-published webhook actions, consistent with caniuse/update.ts and respec/builds/update.ts patterns - Set res.locals.reason = "action-not-published" for structured logging - Use a static message instead of echoing req.body.action to avoid reflected XSS (CodeQL js/reflected-xss) Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/5af37242-1fe0-4bdd-b54b-c45ab0c4120f
All comments are addressed. The one remaining open thread (
All 62 specs pass, CodeQL is clean.
Reviewed and fixed in f450113:
Everything else was already clean: 503 on missing data, whitespace-spec rejection, |
| } | ||
|
|
||
| // Check if it's a moved or split feature in the raw data | ||
| const rawFeature = store.data?.features[featureId]; |
There was a problem hiding this comment.
What if featureId is "constructor" here?
| "baseline_update", | ||
| ); | ||
|
|
||
| export default async function route(req: Request, res: Response) { |
There was a problem hiding this comment.
This requires setting up a webhook in that repo. Do we know someone who can do it for us?
| afterEach(() => { | ||
| store.data = null; | ||
| store.byFeature = new Map(); | ||
| store.bySpecUrl = new Map(); | ||
| }); |
There was a problem hiding this comment.
Do we care to cleanup if beforeEach is setting data anyway?
* feat(api/baseline): add web-features/baseline data endpoint Adds endpoints for serving Baseline browser availability data: - GET /api/baseline — full web-features dataset - GET /api/baseline/:feature — single feature lookup - POST /api/baseline/search — spec-URL-based feature search Data sourced from web-platform-dx/web-features GitHub releases. Enables ReSpec's implementationStatus feature (speced/respec#5174) without requiring unpkg.com dependency. Closes #490 * fix(api/baseline): return flat {result: [...]} from search endpoint Client expects {result: WebFeatureEntry[]}, server was returning Record<string, {id, feature}[]>. Flatten features, deduplicate by ID, and wrap in {result: [...]}. * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(api/baseline): address unresolved review comments - search.post.ts: return 503 when store.data is null (service unavailable) - search.post.ts: reject empty/whitespace-only strings in specs array - store.ts: normalizeUrl() now also clears search params (query string) - scraper.ts: add ETag/If-None-Match support to skip unnecessary re-downloads - scraper.ts: use atomic write (temp file + rename) to prevent corrupt data on interrupted writes - Add tests: normalizeUrl, feature route (moved/split/404), search.post validation Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/41823caf-5a5e-40fc-8bf7-fca753fb37ab * fix(api/baseline): replace existsSync with try-catch for ETag read, add return type doc Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/41823caf-5a5e-40fc-8bf7-fca753fb37ab * fix(api/baseline): update.ts returns 400 for non-published webhook actions, fix XSS - Return 400 (not 200) for non-published webhook actions, consistent with caniuse/update.ts and respec/builds/update.ts patterns - Set res.locals.reason = "action-not-published" for structured logging - Use a static message instead of echoing req.body.action to avoid reflected XSS (CodeQL js/reflected-xss) Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/5af37242-1fe0-4bdd-b54b-c45ab0c4120f --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Summary
GET /api/baseline— full web-features datasetGET /api/baseline/:feature— single feature lookup (follows moved/split redirects)POST /api/baseline/search— spec-URL-based feature matchingCloses #490