refactor(dashboard): align server conventions with wolfstar.rocks - #48
Merged
Conversation
Install the `nitro` skill from antfu/skills (the source this repo already uses for `tsdown` and `turborepo`) and the `nuxt` skill from onmax/nuxt-skills (the source of the existing `nuxt-content`, `nuxt-i18n`, `nuxt-modules`, and `nuxt-seo` skills), so server-side work on `apps/dashboard` has the framework references it currently lacks. `skilld add --agent codex` writes only `.agents/skills/`, so the `.claude/skills/` symlinks are added alongside, matching every other installed skill.
Adopt the Nitro server conventions wolfstar.rocks uses, minus the ones this repository's own rules already decide differently (Nitro auto-imports and `#server/*` aliases stay out: `server/**` and `app/**` keep explicit imports so every symbol's origin is visible at the call site). - Export each route handler directly as the module default rather than binding it to a `const` first, so the one shape Nitro scans for is the one the file declares. - Add `server/utils/errors.ts`, a catalogue of the transport-level failures routes return (`notFound`, `misconfigured`), so a disposition cannot drift into two shapes across the RPC and OpenAPI transports. Bodies and statuses are unchanged; successful dispositions still serialise through `json`. - Rename `server/utils/auth-environment.ts` to `server/utils/environment.ts` and move the webhook's `GITHUB_WEBHOOK_SECRET` and `AGENT_ZERO_CHECKOUT_PATH` reads into it, one resolver each, taking the environment record as an argument. They deliberately stay off Nuxt's `runtimeConfig`, whose defaults are baked at build time and would force every variable into a `NUXT_`-prefixed name a deployment does not set. Safety: the webhook still fails closed on either missing variable, with the same 503 body, and neither resolver reports a value — only the variable's name. Covered by unit tests for the fail-closed paths and the error catalogue. Verified with `aube run test --filter @agent-zero/dashboard` (49 passing), `lint`, `knip`, `nuxt build` (all four routes present in `.output`), and `typecheck` (no errors under `server/` or `test/`).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
Contributor
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Mechanical refactor aligning server conventions: centralizes error handling into a standardized errors utility, consolidates environment resolvers, and switches to Nitro auto-imports. Functional behavior is preserved with comprehensive test coverage for new utilities. Notes:
You can add or adjust custom eligibility rules. Learn more. |
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com> Signed-off-by: RedStar <redstar071@proton.me>
Follow wolfstar.rocks' server layer the rest of the way, and Nuxt's own guidance with it: routes stop importing what Nitro already provides and stop building `Response` objects by hand. - Remove `server/utils/respond.ts`. Its `json`/`errorResponse` helpers duplicated what Nitro does for a returned object and a thrown `H3Error`. - `server/utils/errors.ts` now returns `H3Error`s built with `createError`, including `errors.internal(error)` for the unexpected case. Routes throw them, and Nitro serialises and logs the result — the same envelope the app's own `resolveErrorStatus` already reads on the client side. - Route files rely on Nitro's auto-imports for h3 helpers and for this app's `server/utils/**` exports. Only workspace and third-party packages are imported explicitly, plus `createError` inside `errors.ts`, which the plain-Node unit suite loads directly. - The webhook returns plain objects, with `setResponseStatus(event, 400)` for a rejected delivery, instead of serialising each disposition itself. Safety: `errors.internal` still redacts through `redactSecrets`, and now deliberately attaches no `cause`, since Nitro logs a thrown error whole and the original message is the value most likely to carry a token. The webhook still fails closed on a missing secret or checkout path, with the same message. Covered by unit tests, including a redaction case that asserts the credential appears nowhere on the thrown error. Verified with `check:repo`, `lint:ci`, `typecheck`, `test` (25/25 tasks, dashboard 51 tests), and `build` (16/16). A `nuxt dev` smoke run confirms the wire behavior: `POST /webhooks/github` without a secret answers 503 `GITHUB_WEBHOOK_SECRET is not configured`, `/rpc/does/not/exist` and `/api/v1/nope` answer 404 `Not found`, and `/api/v1/health` still answers 200 with the health payload.
The review feedback that dropped `.trim()` from `githubWebhookSecretFromEnvironment` left its unit tests asserting the old behavior, so the suite was red. GitHub signs each delivery with the exact bytes configured on the hook, so the resolver must not alter them; only an absent or empty variable counts as unconfigured. Record that reason on the resolver and assert it instead.
- Webhook documented as OpenAPI 3.1 webhook, not a routed path - Clarify why plain Nitro handler avoids body parsing - Ensure error messages reach client via Nitro's error handler - Add tests for webhook spec integration and error message preservation
The prior commit annotated `githubWebhookPathItem` as `NonNullable<OpenAPIDocument['webhooks']>[string]`, which widens it to `PathItemObject | ReferenceObject`. `openapi.test.ts` then failed typecheck reading `.post` and `.post.parameters`, since a `ReferenceObject` has neither. `satisfies` checks the literal against that same union without widening the binding, so the object keeps its own concrete shape.
CI's Lint project job failed: `server/**/*.ts` now relies on Nitro's auto-imports (`defineEventHandler`, `errors`, `taskStore`, ...), which oxlint's `--type-aware --type-check` pass can only resolve once `nuxt prepare` has generated `.nuxt/tsconfig.server.json` and its ambient declarations. `typecheck` (`nuxt typecheck`) runs that step internally, and `test` already had a `pretest: nuxt prepare` hook for the same reason, but `lint`/`lint:fix` had no equivalent — so a clean checkout's first lint run saw undeclared names and failed with 30 `Cannot find name` errors. Add matching `prelint`/`prelint:fix` hooks, following the existing `pretest` pattern in this same file. Verified by deleting `apps/dashboard/.nuxt` and `node_modules/.cache/nuxt` (reproducing a cold checkout) and re-running `aube run lint:ci`, `test`, `typecheck`, and `build` from that state: all pass.
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.
Summary
Aligns
apps/dashboard/server/with the Nitro server conventions used bywolfstar-project/wolfstar.rocks, and installs the
nitroandnuxtAgent Skills that server-side work on this app was missing.export default defineEventHandler(...))instead of binding it to a
constfirst.server/utils/errors.ts— a catalogue of the transport-level failures routes return(
errors.notFound(),errors.misconfigured(variable)), mirroring wolfstar.rocks' ownserver/utils/errors.ts.Statuses and bodies are unchanged; successful dispositions still serialise through
json(...).server/utils/auth-environment.tsbecomesserver/utils/environment.tsand gains the webhook'sGITHUB_WEBHOOK_SECRETandAGENT_ZERO_CHECKOUT_PATHresolvers, so every environment read the server doeslives in one module.
nitrofromantfu/skills(the source already used fortsdownandturborepo) andnuxtfromonmax/nuxt-skills(the source of the existingnuxt-content,nuxt-i18n,nuxt-modules,nuxt-seo).No observable HTTP behavior changes: same paths, same statuses, same response bodies.
Why
server/had the same disposition spelled out inline in several places — a 404 literal in both transports,two 503 literals in the webhook route — and read
process.envdirectly at one call site while a neighbouringutil already existed for another variable. Naming the failure and centralising the reads keeps the two
transports from drifting apart and makes the fail-closed paths testable.
Boundary is unchanged and stays where the
orpc-serverskill puts it:server/remains the transportadapter and composition root,
packages/apikeeps the router, and nothing new reaches the runtime.Two wolfstar.rocks conventions are deliberately not adopted, because this repository decides them
differently and the reasons are recorded in
.skills/orpc-server/SKILL.md:#server/*aliases —server/**andapp/**keep explicit imports so everysymbol's origin stays visible at the call site.
useRuntimeConfigin place ofprocess.env—runtimeConfigdefaults are baked at build time andwould force every variable into a
NUXT_-prefixed name, while a deployment setsGITHUB_WEBHOOK_SECRETand
AGENT_ZERO_CHECKOUT_PATHat run time. The resolvers stay lazy, and take the environment record as anargument so tests never mutate the real process environment.
Formatting (tabs, double quotes) is also not copied:
tooling/oxc/.oxfmtrc.jsongoverns the whole monorepo.Verification
Run on this branch, rebased onto
origin/main(be40c80):aube run check:repo—Repository metadata valid; 8 Agent Skills available.aube run lint:ci— 25/25 tasks,Found 0 warnings and 0 errors, knip cleanaube run typecheck— 25/25 tasks, no errorsaube test— 25/25 tasks (dashboard: 10 files, 49 tests)aube run build— 16/16 tasksAdditionally,
apps/dashboard/.outputwas inspected afternuxt build:/rpc/**,/api/v1/**,/api/dashboard, and/webhooks/githubare all present, so nothing was dropped by moving the handlerexports.
New deterministic tests:
apps/dashboard/test/unit/errors.test.ts(both catalogue entries, status and body)and four cases added to
apps/dashboard/test/unit/environment.test.tsfor the fail-closed webhook resolvers(absent and blank values).
Safety and compatibility
observemode as read-only, or explained the policy change above.The webhook route still fails closed on either missing variable, with the byte-identical 503 body it returned
before.
errors.misconfigurednames the variable only — never a value — and the 500 path still redactsthrough
redactSecrets.Reviewer notes
apps/dashboard/server/utils/auth-environment.ts→environment.tsis a rename plus two added resolvers;its test file was renamed to match.
dashboardUrlFromEnvironmentis unchanged..skills/orpc-server/SKILL.mdgains three rules (direct default export, error catalogue, environmentmodule) so the next change to
server/follows the same shape.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Note
Align dashboard server error handling and environment utilities with wolfstar.rocks conventions
errorscatalog (errors.ts) with factory functions fornotFound(404),misconfigured(503), andinternal(500, with secret redaction), replacing customerrorResponse/jsonhelpers across server routes.NUXT_PUBLIC_SITE_URL,GITHUB_WEBHOOK_SECRET, andAGENT_ZERO_CHECKOUT_PATH, replacing ad-hocruntimeConfigaccess./api/v1catch-all to use the new errors catalog and environment resolvers, and inlines handler exports to match the wolfstar.rocks convention.webhooksinstead ofpaths./api/v1routes now throw H3 404 errors instead of returning custom JSON bodies; unexpected errors surface as H3 500s with redacted messages instead of custom error responses.Macroscope summarized 8d2eba8.