feat(ui): render the API reference in-app instead of a CDN#266
Merged
Conversation
The /docs page loaded Scalar from cdn.jsdelivr.net, so it rendered blank on any air-gapped / restricted network (a core self-hosting audience) and quietly contradicted the "zero telemetry, no phone-home" promise on every visit. Replace it with a small self-contained OpenAPI renderer (a Nuxt page plus app/components/docs/*) that renders the auto-generated /_openapi.json entirely in-app: no third-party CDN, works offline, and makes no outbound calls. The page now lives in the standard dashboard shell, is theme-aware and responsive, groups endpoints by tag with a filter, and shows the required "Windows users" curl tip at the top. If the spec itself is unreachable it falls back to a link to the raw JSON. Works the same in the static demo (client-side fetch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX
Enrich the self-contained /docs reference with the interactivity Scalar provided, while keeping it CDN-free and zero-outbound-by-default. Each expanded operation now has a "Try it out" console: fill path/query params, a bearer token, and a JSON body (prefilled from the schema), then Send a real same-origin request and see the status, timing, and pretty response body. Every operation also shows copy-paste cURL and fetch code samples that reflect the current inputs. Requests only fire on click and only to the same origin the dashboard is served from (the demo's service worker handles them in the static build), so nothing phones home. Pure helpers live in openapi-console.ts (unit-tested); the shared bearer token in useApiConsole. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX
Every expanded endpoint now shows an "Access" line (Public / Any signed-in
user / Administrator / Administrator or Reporter), and admin- or reporter-only
routes get a compact role chip in the list header so they stand out.
Routes declare their allowed roles once as REQUIRED_ROLES (used by requireAuth),
but Nitro's OpenAPI extractor can't fold those enum references into the spec, so
they never reached the docs. A generator mirrors them into a committed
route-roles map keyed by "{method} {path}" that the reference reads; the
file→operation mapping was validated against the live spec (all 96 entries
match). A unit test regenerates and fails on drift, and the extraction/mapping
is shared between the generator and the test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX
…ne-support-lql5nd # Conflicts: # application/package.json
Contributor
Coverage Report for Reporter (./reporter)
File CoverageNo changed files found. |
Contributor
Coverage Report for Application (./application)
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The /docs role display previously read a generated side map because Nitro's OpenAPI extractor dropped the routes' enum/variable role references. Fix it at the source instead: each route's defineRouteMeta now declares its roles as a string-literal x-required-roles array, which the extractor folds into the spec, so the reference reads them straight from /_openapi.json (and any other spec consumer sees them too). Enforcement is untouched — requireAuth still gates on the typed Role[]; only the doc metadata changed, and the now-orphaned REQUIRED_ROLES consts + Role imports (documentation-only in routes that just require sign-in) were removed. Drops the generated route-roles map, its generator/extractor, the drift test, and the app:gen:route-roles script. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX
Make each route's x-required-roles OpenAPI meta the single source of truth for authorization. requireAuth now reads the current route's roles from the compiled route metas (matched with rou3, the same router Nitro dispatches with) and 403s a user who lacks them, so routes no longer repeat the roles: the REQUIRED_ROLES consts and the explicit requireAuth/requireProjectAccess role arguments are gone. The argument stays as an override for the rare handler that computes its own authorization (e.g. users self-or-admin edit). Also corrects two metas whose old REQUIRED_ROLES const was documented but never enforced (users list, search) to match their real any-signed-in-user access, so switching to meta enforcement changes no behavior. Verified end to end against an auth-enabled server: a reporter is 403'd on admin-only routes and allowed on any-auth ones, an admin is allowed, and anon is 401'd; the matcher is unit-tested and a role-enforcement case was added to the auth E2E spec. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX
Meta-based enforcement fixed the under-enforcement this test documented: a "user"-role caller (not in the route's ['administrator', 'reporter'] x-required-roles) is now rejected with 403 before reaching the AI-config check, instead of falling through to a 503. Update the assertion and its notes to the corrected behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The /docs page loaded Scalar from cdn.jsdelivr.net, so it rendered blank on
any air-gapped / restricted network (a core self-hosting audience) and quietly
contradicted the "zero telemetry, no phone-home" promise on every visit.
Replace it with a small self-contained OpenAPI renderer (a Nuxt page plus
app/components/docs/*) that renders the auto-generated /_openapi.json entirely
in-app: no third-party CDN, works offline, and makes no outbound calls. The
page now lives in the standard dashboard shell, is theme-aware and responsive,
groups endpoints by tag with a filter, and shows the required "Windows users"
curl tip at the top. If the spec itself is unreachable it falls back to a link
to the raw JSON. Works the same in the static demo (client-side fetch).
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01RJWPM2eGX9PE2cjecfv3MX