feat: type the package.json webjs.* config block - #295
Conversation
webjs reads a webjs.* object from package.json (elide, headers, redirects, csp, trailingSlash, and the body-limit / timeout knobs), but there was no type, schema, or validation, so a typo'd key was silently dropped and the feature it toggled stayed at default with no diagnostic. The config equivalent of an untyped API that fails open. Ship a standard draft-07 JSON Schema (packages/server/webjs-config.schema.json, additionalProperties:false so an unknown key is flagged) plus an exported WebjsConfig type (packages/core/src/webjs-config.d.ts), both mirroring exactly what the server readers accept. The scaffold's .vscode/settings.json associates the schema with package.json's webjs property so editors validate it natively. A drift test asserts the schema covers every key the readers consume, and a tsc fixture proves a wrong-typed or unknown key is a compile error. webjs check stays errors-only (an unknown-key error would be a forward-compat hazard), so the editor schema is the diagnostic path. Closes #259
The #259 editor-association feature added packages/cli/templates/.vscode/settings.json (the webjs-config JSON Schema association for package.json), but both the root and template .gitignore exclude .vscode/, so the file was never committed and the scaffold copy step (guarded by existsSync) silently skipped it on any clean checkout or published package. The schema-association half of the feature reached zero scaffolded apps. Re-include the file in both .gitignore files (the same .vscode/* plus !.vscode/settings.json shape the .webjs/ vendor exception uses, since a bare .vscode/ dir exclusion blocks any child negation), stage the template file, and assert in scaffold-integration that a generated app contains .vscode/settings.json with the schema $ref so this cannot regress silently.
Two review follow-ups for the webjs-config typing. Add a drift test asserting the WebjsConfig type's top-level keys equal the reader keys (KNOWN_KEYS), closing the third edge of the lockstep triangle: the schema was already cross-checked against the readers, but the type could silently fall out of sync with both. Tighten a header rule's value from string|null|boolean to string|null|false in both the schema and the type. A value of true is never meaningful (the runtime stringifies it to the literal "true"); only a string sets a header and null/false remove it. A new fixture counterfactual proves value:true is now a compile error.
vivek7405
left a comment
There was a problem hiding this comment.
Reviewed against the readers, since the value of the schema and type is that they mirror what the server actually accepts. All 10 keys check out: statusCode is exactly the redirect-resolver's 301/302/303/307/308, the numeric knobs floor at 0 because 0 disables, and csp stays oneOf(boolean, object) with the directive map left open so a valid CSP config is never false-flagged.
The self-review loop earned its keep. Round 1 found that the scaffold .vscode/settings.json was gitignored by both the root and template .gitignore, so the editor-association half of the feature shipped to nobody (the copy step is existsSync-guarded, so it silently no-ops on a clean checkout). Fixed with the same .vscode/* plus !.vscode/settings.json shape the .webjs vendor exception uses, and I verified empirically in a throwaway repo that a scaffolded app commits its own settings.json while still ignoring other .vscode files. Added a scaffold-integration assertion so it cannot regress.
Also closed the schema-vs-type drift edge (a test now asserts the WebjsConfig type keys equal the reader keys, so schema, type, and readers are a three-way lockstep) and tightened a header value from boolean to string|null|false (true would stringify to the literal 'true'). Round 2 came back clean. Full suite 1880, scaffold tests pass. Good to merge once CI is green.
Closes #259
What
webjs reads a
webjsobject from package.json (elide,headers,redirects,csp,trailingSlash, and the body-limit / timeout knobs), but there was no type, schema, or validation, so a typo'd key was silently dropped and the feature it toggled stayed at default with no diagnostic. The config equivalent of an untyped API that fails open.Surface
packages/server/webjs-config.schema.json, draft-07,additionalProperties: false). Every one of the 10 keys carries a type/enum/description matched to what the server reader actually accepts (statusCodeis exactly the 301/302/303/307/308 the redirect resolver allows; the numeric knobs floor at 0 because 0 disables;cspisoneOf(boolean, object)and the directive map stays open so a valid CSP config is never false-flagged). Shipped in the server packagefiles+ anexportssubpath.WebjsConfigtype (packages/core/src/webjs-config.d.ts, pure types-only) for a typed reference, re-exported from@webjsdev/core.packages/cli/templates/.vscode/settings.jsonassociates the schema with package.json'swebjsproperty viajson.schemas, so a new app validates the block natively (a typo likeredirectforredirectsis flagged inline).webjs checkstays errors-only: an unknown-key error would be a forward-compat hazard (an app using a newer key on an older install would fail check), so the editor schema is the diagnostic path the acceptance allows.A gitignore trap this surfaced
The
.vscode/settings.jsontemplate was silently excluded by both the root and template.gitignore(.vscode/), so the scaffold copy step (guarded byexistsSync) skipped it on any clean checkout and the editor-association half shipped to nobody. Fixed with the same.vscode/*+!.vscode/settings.jsonshape the.webjs/vendor exception uses, with a scaffold-integration assertion that a generated app contains the file. This is exactly what the self-review loop caught.Tests
packages/server/test/config/webjs-config-schema.test.js): asserts the schema covers every reader key and declares no extra, thatadditionalProperties:falseis set, the key shapes match the reader contracts, AND that theWebjsConfigtype's keys equal the reader keys (so schema, type, and readers stay a three-way lockstep). 9/9.test/types/webjs-config.test-d.ts): a valid config compiles;@ts-expect-erroron a wrong-typed value, a bad enum, an unknown/typo'd key, a bad status code, a missing destination, and avalue: trueheader (now rejected). Self-checking via unused-directive detection..vscode/settings.jsonwith the schema$ref.Docs
agent-docs/typescript.md(theWebjsConfig+ JSON Schema section), rootAGENTS.md(core type-export table),packages/server/AGENTS.md(the schema file + the single documented "add a key, update schema + type + reader" procedure),packages/core/AGENTS.md,packages/cli/templates/AGENTS.md(the scaffold association).Dogfood
website / docs / ui-website boot 200/307; scaffold tests 12/12 incl. the new
.vscodeassertion. No version bump (batched core/server release).