@webjsdev/cli 0.10.5 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/webjs.js CHANGED
@@ -42,6 +42,7 @@ const USAGE = `webjs commands:
42
42
  webjs start [--port 8080] Start production server (serves source directly, no build step)
43
43
  webjs test [--server|--browser] Run server + browser tests
44
44
  webjs check Run correctness checks on the app
45
+ webjs types Generate .webjs/routes.d.ts (typed Route union + per-route params)
45
46
  webjs create <name> [--template full-stack|api|saas] [--no-install] Scaffold a new webjs app
46
47
  (only 3 templates exist. default: full-stack with Prisma+SQLite)
47
48
  Auto-runs the detected package manager's install in the new dir
@@ -277,6 +278,27 @@ async function main() {
277
278
  }
278
279
  break;
279
280
  }
281
+ case 'types': {
282
+ // Generate `.webjs/routes.d.ts` from the app's `app/` routes (#258),
283
+ // narrowing the @webjsdev/core `Route` href union + per-route `params`.
284
+ // Opt-in codegen: the static types in @webjsdev/core work without it
285
+ // (un-generated apps see `Route = string`).
286
+ const { generateRouteTypes } = await import('@webjsdev/server');
287
+ const { mkdir, writeFile } = await import('node:fs/promises');
288
+ const appDir = process.cwd();
289
+ const text = await generateRouteTypes(appDir);
290
+ const outDir = join(appDir, '.webjs');
291
+ await mkdir(outDir, { recursive: true });
292
+ const outFile = join(outDir, 'routes.d.ts');
293
+ await writeFile(outFile, text);
294
+ // Count the typed routes (each `WebjsRoutes` key is one route literal).
295
+ const count = (text.match(/^\s+".*": true;$/gm) || []).length;
296
+ console.log(
297
+ `webjs types: wrote .webjs/routes.d.ts (${count} route${count === 1 ? '' : 's'} typed). ` +
298
+ `Ensure tsconfig "include" lists ".webjs/routes.d.ts" so tsserver picks it up.`,
299
+ );
300
+ break;
301
+ }
280
302
  case 'create': {
281
303
  const name = rest[0];
282
304
  if (!name || name.startsWith('-')) {
package/lib/create.js CHANGED
@@ -346,6 +346,22 @@ export async function scaffoldApp(name, cwd, opts = {}) {
346
346
  { name: '@webjsdev/ts-plugin' },
347
347
  ],
348
348
  },
349
+ // `.webjs/routes.d.ts` is the OPT-IN generated route-types overlay (#258):
350
+ // run `webjs types` (or `webjs dev`, which emits it) to narrow the
351
+ // @webjsdev/core `Route` href union + per-route `params`. Listed in
352
+ // `include` so tsserver picks it up; it is gitignored (regenerated per
353
+ // machine), so a fresh clone runs `webjs dev` / `webjs types` to recreate
354
+ // it, and the static @webjsdev/core types work even when it is absent.
355
+ include: [
356
+ 'app/**/*',
357
+ 'components/**/*',
358
+ 'modules/**/*',
359
+ 'lib/**/*',
360
+ 'middleware.js',
361
+ 'middleware.ts',
362
+ '.webjs/routes.d.ts',
363
+ ],
364
+ exclude: ['node_modules', '.webjs/vendor', 'prisma/migrations'],
349
365
  }, null, 2) + '\n');
350
366
 
351
367
  // --- Templates (AGENTS.md, CONVENTIONS.md, CLAUDE.md, test files, Claude hooks) ---
@@ -397,6 +413,10 @@ export async function scaffoldApp(name, cwd, opts = {}) {
397
413
  // to main, mirroring the webjs framework's own CI.
398
414
  '.github/workflows/ci.yml',
399
415
  '.editorconfig',
416
+ // VS Code: associate the published webjs-config JSON Schema with the
417
+ // package.json `webjs` block, so an unknown / typo'd key (#259) is
418
+ // flagged natively in the editor instead of silently dropped.
419
+ '.vscode/settings.json',
400
420
  // Production / deploy scaffolding. `docker compose up --build` runs
401
421
  // the app locally with the same Dockerfile production builds from.
402
422
  'Dockerfile',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjsdev/cli",
3
- "version": "0.10.5",
3
+ "version": "0.10.6",
4
4
  "type": "module",
5
5
  "description": "webjs CLI - dev, start, create, db",
6
6
  "bin": {
@@ -0,0 +1,15 @@
1
+ {
2
+ "json.schemas": [
3
+ {
4
+ "fileMatch": ["/package.json"],
5
+ "schema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "webjs": {
9
+ "$ref": "./node_modules/@webjsdev/server/webjs-config.schema.json"
10
+ }
11
+ }
12
+ }
13
+ }
14
+ ]
15
+ }
@@ -112,6 +112,15 @@ layered on top:
112
112
  See [docs.webjs.com → Editor setup](https://docs.webjs.com/docs/editor-setup)
113
113
  for the full walkthrough.
114
114
 
115
+ **Config validation in `package.json`.** The scaffold ships
116
+ `.vscode/settings.json`, which associates the published webjs-config JSON
117
+ Schema (`@webjsdev/server/webjs-config.schema.json`) with the `webjs` block
118
+ of `package.json`. In VS Code an unknown / typo'd `webjs.*` key (`redirect`
119
+ for `redirects`, say) is then flagged inline instead of silently dropped to
120
+ the default. The same shape is typed by the `WebjsConfig` type from
121
+ `@webjsdev/core` (`import type { WebjsConfig } from '@webjsdev/core'`) for a
122
+ typed reference.
123
+
115
124
  ## UI components: Webjs UI (preinstalled)
116
125
 
117
126
  This scaffold ships with the standard Webjs UI component kit
@@ -267,6 +276,28 @@ test/<feature>/ feature-scoped tests, one folder per concern
267
276
  middleware.ts root middleware (optional, outermost)
268
277
  ```
269
278
 
279
+ ### Typed page / layout / route-handler props
280
+
281
+ Type page / layout / route-handler arguments with the exported helpers so a
282
+ param typo is a compile-time error:
283
+
284
+ ```ts
285
+ import type { PageProps, LayoutProps, RouteHandlerContext } from '@webjsdev/core';
286
+
287
+ export default function Post({ params }: PageProps<'/blog/[slug]'>) {
288
+ return html`<h1>${params.slug}</h1>`; // params typed { slug: string }
289
+ }
290
+ export default function RootLayout({ children }: LayoutProps) { /* ... */ }
291
+ export async function GET(req: Request, ctx: RouteHandlerContext) { /* ctx.params */ }
292
+ ```
293
+
294
+ Run `webjs types` once (and ensure `tsconfig.json` `include` lists
295
+ `.webjs/routes.d.ts`, the scaffold already does) to generate the route union:
296
+ `PageProps<'/blog/[slug]'>['params']` then narrows to `{ slug: string }` and
297
+ `navigate()` only accepts real app routes. `webjs dev` regenerates the file on
298
+ startup, so it stays current. Without it, `params` is `Record<string, string>`
299
+ and `navigate()` accepts any string (non-breaking).
300
+
270
301
  ## Database (Prisma + SQLite by default)
271
302
 
272
303
  Every scaffold includes a Prisma setup pointed at a local SQLite file.
@@ -709,8 +740,13 @@ return html`
709
740
  ```
710
741
 
711
742
  The router's `closest('webjs-frame')` detection takes precedence over
712
- layout markers. Only the frame's content swaps. Use this sparingly -
713
- folder-based layouts handle 99% of cases.
743
+ layout markers. Only the frame's content swaps. Use this sparingly,
744
+ folder-based layouts handle 99% of cases. When a frame nav's response
745
+ lacks the matching `<webjs-frame id>` (e.g. an auth redirect), the router
746
+ fires a cancelable, bubbling `webjs:frame-missing` event (detail
747
+ `{ frameId, url, document }`) and leaves the frame unchanged rather than
748
+ silently swapping the whole page; call `preventDefault()` to take over
749
+ the outcome (e.g. `location.assign(e.detail.url)`).
714
750
 
715
751
  ### 5. `loading.ts` for per-segment skeletons
716
752