@webjsdev/cli 0.10.2 → 0.10.4

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
@@ -15,7 +15,7 @@ const USAGE = `webjs commands:
15
15
  webjs dev [--port 8080] Start dev server with live reload
16
16
  webjs start [--port 8080] Start production server (serves source directly, no build step)
17
17
  webjs test [--server|--browser] Run server + browser tests
18
- webjs check Validate app against conventions
18
+ webjs check Run correctness checks on the app
19
19
  webjs create <name> [--template full-stack|api|saas] [--no-install] Scaffold a new webjs app
20
20
  (only 3 templates exist. default: full-stack with Prisma+SQLite)
21
21
  Auto-runs the detected package manager's install in the new dir
@@ -212,22 +212,16 @@ async function main() {
212
212
  break;
213
213
  }
214
214
  case 'check': {
215
- const { checkConventions, RULES, loadConventionOverrides } = await import('@webjsdev/server/check');
215
+ const { checkConventions, RULES } = await import('@webjsdev/server/check');
216
216
 
217
217
  if (rest.includes('--rules')) {
218
- const overrides = await loadConventionOverrides(process.cwd());
219
- const anyOverride = Object.keys(overrides).length > 0;
220
- console.log('webjs check, available rules:');
221
- console.log(' All rules are ENABLED by default. A rule is only off when');
222
- console.log(' package.json "webjs": { "conventions": { ... } } sets it');
223
- console.log(' to false.\n');
218
+ console.log('webjs check, correctness rules:');
219
+ console.log(' Every rule catches objectively broken code (a crash, a');
220
+ console.log(' security leak, or a build/type-strip failure) and always');
221
+ console.log(' runs. Project conventions (layout, style, process) are');
222
+ console.log(' guidance in CONVENTIONS.md, not rules here.\n');
224
223
  for (const r of RULES) {
225
- const off = overrides[r.name] === false;
226
- const status = off ? '[disabled by override]' : '[enabled]';
227
- console.log(` ${r.name.padEnd(30)} ${status.padEnd(24)} ${r.description}`);
228
- }
229
- if (!anyOverride) {
230
- console.log('\n (no overrides found; every rule above is active in this project)');
224
+ console.log(` ${r.name.padEnd(30)} ${r.description}`);
231
225
  }
232
226
  break;
233
227
  }
@@ -235,7 +229,7 @@ async function main() {
235
229
  const violations = await checkConventions(process.cwd());
236
230
 
237
231
  if (violations.length === 0) {
238
- console.log('webjs check: all conventions pass ✓');
232
+ console.log('webjs check: all checks pass ✓');
239
233
  } else {
240
234
  console.log(`webjs check: ${violations.length} violation(s) found\n`);
241
235
  for (const v of violations) {
package/lib/create.js CHANGED
@@ -536,7 +536,7 @@ export async function POST(req: Request) {
536
536
  return Response.json(await createUser(body));
537
537
  }
538
538
  `);
539
- // Minimal test stub so the scaffold passes `webjs check` (tests-exist)
539
+ // Minimal starter test so a freshly scaffolded app ships with a test
540
540
  // and `webjs test` runs cleanly. Replace these with real assertions
541
541
  // once you wire the action/query to a real data source.
542
542
  await writeFile(join(appDir, 'test', 'unit', 'users.test.ts'), `import { test } from 'node:test';
@@ -820,7 +820,7 @@ export default function Home() {
820
820
  <p class="text-lede leading-[1.5] text-fg-muted max-w-[56ch] m-0 mb-6">
821
821
  Edit <code class="font-mono text-[0.9em]">app/page.ts</code> to get started.
822
822
  Run \${accentLink('#', 'webjs test')} to run tests and
823
- \${accentLink('#', 'webjs check')} to validate conventions.
823
+ \${accentLink('#', 'webjs check')} to catch correctness issues.
824
824
  </p>
825
825
  <div class="flex gap-3 items-center">
826
826
  <button class=\${buttonClass()}>Get started</button>
@@ -174,7 +174,7 @@ export async function writeSaasFiles(appDir) {
174
174
  ].join('\n'));
175
175
 
176
176
  // test/unit/auth.test.ts: minimal stub so the scaffold passes
177
- // `webjs check` (tests-exist) and `webjs test` runs cleanly out of the
177
+ // `webjs test` runs cleanly out of the
178
178
  // box. The signup/current-user functions import from lib/prisma.server.ts
179
179
  // and lib/auth.server.ts, both of which need `prisma generate` to have run before
180
180
  // they can be imported, so we deliberately test only the runtime-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjsdev/cli",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "type": "module",
5
5
  "description": "webjs CLI - dev, start, create, db",
6
6
  "bin": {
@@ -12,8 +12,9 @@ cover what you need, the full hosted docs are at **https://docs.webjs.com**.
12
12
  ANY data the app stores (todos, posts, messages, products, comments), define
13
13
  a Prisma model. NEVER create `data/*.json`, `db.json`, or any JSON file as a
14
14
  fake database. NEVER use module-scope arrays / Maps as a substitute. NEVER
15
- use localStorage for app data. `webjs check`'s `no-json-data-files` rule
16
- will fail the build if you do.
15
+ use localStorage for app data. These are project conventions in
16
+ CONVENTIONS.md (a JSON file used as a database resets on reload and
17
+ cannot scale).
17
18
  - **The scaffold is reference, not the final product.** Replace `app/page.ts`,
18
19
  the example `User` model, the example users module, etc. with the app the
19
20
  user actually asked for. Do not ship "Hello from <app-name>" as the
@@ -12,8 +12,8 @@ cover what you need, the full hosted docs are at **https://docs.webjs.com**.
12
12
  data the app stores (todos, posts, messages, products, comments…),
13
13
  define a Prisma model. NEVER create `data/*.json`, `db.json`, or any
14
14
  JSON file as a fake database. NEVER use module-scope arrays / Maps as
15
- a substitute. NEVER use localStorage for app data. `webjs check`'s
16
- `no-json-data-files` rule will fail the build if you do.
15
+ a substitute. NEVER use localStorage for app data. These are project conventions in CONVENTIONS.md (a JSON file used as a
16
+ database resets on reload and cannot scale).
17
17
  - **The scaffold is reference, not the final product.** Replace
18
18
  `app/page.ts`, the example `User` model, the example users module, etc.
19
19
  with the app the user actually asked for. Don't ship "Hello from
@@ -12,8 +12,8 @@ the full hosted docs are at **https://docs.webjs.com**.
12
12
  data the app stores (todos, posts, messages, products, comments…),
13
13
  define a Prisma model. NEVER create `data/*.json`, `db.json`, or any
14
14
  JSON file as a fake database. NEVER use module-scope arrays / Maps as
15
- a substitute. NEVER use localStorage for app data. `webjs check`'s
16
- `no-json-data-files` rule will fail the build if you do.
15
+ a substitute. NEVER use localStorage for app data. It resets on reload and cannot scale. This is a project convention
16
+ (CONVENTIONS.md).
17
17
  - **The scaffold is reference, not the final product.** Replace
18
18
  `app/page.ts`, the example `User` model, the example users module, etc.
19
19
  with the app the user actually asked for. Don't ship "Hello from
@@ -24,8 +24,8 @@ the app the user actually asked for.
24
24
  stores (todos, posts, messages, products, comments, anything),
25
25
  define a Prisma model and persist there.
26
26
  - **NEVER** store app data in JSON files (`data/todos.json`,
27
- `db.json`, …). The convention check `no-json-data-files` flags
28
- this and the user's prompt explicitly forbids it.
27
+ `db.json`, …). It resets on reload and cannot scale. This is a project convention,
28
+ and the user's prompt explicitly forbids it.
29
29
  - **NEVER** use in-memory arrays or `Map`s as a substitute for the
30
30
  database. They vanish on every dev-server reload and aren't
31
31
  shared across processes.
@@ -318,12 +318,17 @@ Fully warm means the deterministic analysis AND the first vendor attempt have
318
318
  both completed, so the importmap and its build id are settled. Point your
319
319
  platform's readiness check at `/__webjs/ready` so it holds traffic off a
320
320
  not-yet-warmed instance instead of routing the first user request into the cold
321
- analysis or the brief window where the importmap is still resolving. On
322
- Railway, set `"healthcheckPath": "/__webjs/ready"` under `deploy` in
323
- `railway.json`. For dependency-aware
324
- readiness (gate on a live DB ping), add an optional `readiness.{js,ts}` at the
325
- app root that default-exports an async check; `/__webjs/ready` runs it once warm
326
- and reports 503 if it returns `false` or throws.
321
+ analysis or the brief window where the importmap is still resolving. The
322
+ scaffolded `Dockerfile` and `compose.yaml` already wire this up with a
323
+ `HEALTHCHECK` that probes `/__webjs/ready`, so any Docker-based deploy gets the
324
+ gate with no extra config. On a platform that reads its own config instead,
325
+ point its equivalent knob at the same path: Railway `"healthcheckPath":
326
+ "/__webjs/ready"`, Render `healthCheckPath: /__webjs/ready`, Fly a
327
+ `[[http_service.checks]]` on `/__webjs/ready`, or a Kubernetes `readinessProbe`
328
+ with `httpGet.path: /__webjs/ready`. For dependency-aware readiness (gate on a
329
+ live DB ping), add an optional `readiness.{js,ts}` at the app root that
330
+ default-exports an async check; `/__webjs/ready` runs it once warm and reports
331
+ 503 if it returns `false` or throws.
327
332
 
328
333
  Scripts:
329
334
 
@@ -583,7 +588,8 @@ Practical consequences for agents writing webjs code.
583
588
  | Class-field initializer for a reactive property (`student: Student = {...}`) | Silently breaks reactivity (overwrites the framework accessor) | `declare student: Student` plus constructor default |
584
589
  | `@property()` decorator | Banned by invariant 10 (erasable TS) | `static properties = { ... }` plus `declare` |
585
590
  | `static styles = css` block without `static shadow = true` | Styles leak globally; the framework warns at runtime | Add `static shadow = true`, or use Tailwind utilities |
586
- | `willUpdate` computing SSR-visible derived state | Field is `undefined` in SSR HTML (hook is client-only) | Compute inline in `render()` |
591
+ | `willUpdate` computing SSR-visible derived state | Works (runs at SSR), but overriding it opts the component out of elision | Fine for interactive components; for display-only, derive inline in `render()` |
592
+ | `this.hasAttribute` / `getAttribute` in `render()` | Works (server attribute shim backs the attribute methods at SSR) | Read attributes directly, or via a `static properties` + `declare` reactive prop |
587
593
  | `ContextProvider` for server-known data | Default value during SSR, content shift on hydration | Pass via props from the page function |
588
594
 
589
595
  The full annotated catalog with code examples lives in the framework
@@ -938,5 +944,6 @@ composition, so a nested shell ends up dropped by the HTML parser.
938
944
  5. When unsure how a framework feature works, `grep` or `cat` the
939
945
  relevant `node_modules/@webjsdev/*/src/` file before asking the user.
940
946
 
941
- Project-specific conventions and overrides live in
942
- [CONVENTIONS.md](./CONVENTIONS.md).
947
+ Project conventions live in [CONVENTIONS.md](./CONVENTIONS.md) (guidance
948
+ you follow by judgment). `webjs check` is separate: correctness checks
949
+ only, always on, no per-project disabling.
@@ -9,59 +9,41 @@ Edit the content below the marker to change the convention for your project.
9
9
 
10
10
  ---
11
11
 
12
- ## How `CONVENTIONS.md` relates to `webjs check`
13
-
14
- This markdown file holds **architectural conventions** (modules layout,
15
- styling, testing, git workflow) that the linter can't enforce
16
- programmatically. The `<!-- OVERRIDE -->` markers let you customize
17
- those for this project, and AI agents read them when writing code.
18
-
19
- The **lint rules** are a separate, narrower thing: the boolean checks
20
- that `webjs check` runs (one function per action, components register
21
- themselves, tag names have hyphens, etc.). They are NOT documented in
22
- this file. Their **single source of truth** is the
23
- `"webjs": { "conventions": { … } }` key in `package.json`.
24
-
25
- If that key is absent, **every default rule is enabled** and AI agents
26
- must follow all of them.
27
-
28
- ### Discovering the active rules
29
-
30
- ```sh
31
- webjs check --rules
32
- ```
33
-
34
- prints every available rule with its description and shows which ones
35
- are currently disabled by this project's overrides. That command is the
36
- **authoritative** list. Do not maintain a copy elsewhere; it will drift.
37
-
38
- ### Disabling a rule
39
-
40
- Add the rule name to `package.json` with a value of `false`:
41
-
42
- ```jsonc
43
- {
44
- "webjs": {
45
- "conventions": {
46
- "tests-exist": false,
47
- "actions-in-modules": false
48
- }
49
- }
50
- }
51
- ```
52
-
53
- Only `false` is meaningful. There's no way to tweak rule *behaviour*
54
- via config. A rule is either on or off.
55
-
56
- ### Rule for AI agents
57
-
58
- 1. Run `webjs check --rules` to learn the active rule set for this
59
- project.
60
- 2. Treat every rule not explicitly disabled as binding when writing
61
- code.
62
- 3. To change which rules are active, edit the `webjs.conventions`
63
- block in `package.json`. Never inline a rule list into prose, since
64
- it will drift.
12
+ ## `CONVENTIONS.md` vs `webjs check`: two different things
13
+
14
+ This file is the source of truth for **project conventions**: how code
15
+ is organized, named, and tested. They are preferences a reasonable
16
+ project could do differently, so they are guidance (for humans and AI
17
+ agents), not a hard gate. Customize any of them; sections marked
18
+ `<!-- OVERRIDE -->` are explicit customization points.
19
+
20
+ `webjs check` is a separate, narrower tool: **correctness checks** that
21
+ catch objectively broken code (a crash, a security leak, a build or
22
+ type-strip failure). Those always run, there is no per-project
23
+ disabling, and they are not listed here (run `webjs check --rules` to
24
+ see them). The line between the two: *could a sensible app legitimately
25
+ want this to pass?* If yes, it is a convention (this file); if no, it is
26
+ a check (the tool).
27
+
28
+ ### Project conventions (follow these)
29
+
30
+ These are the architectural conventions for this app. They are not
31
+ enforced by `webjs check`; follow them by judgment.
32
+
33
+ - **Server actions and queries live in `modules/<feature>/actions/` and
34
+ `modules/<feature>/queries/`** (`*.server.{js,ts}`), not loose in the
35
+ app root. Cross-cutting server infrastructure (the Prisma singleton,
36
+ session helpers, auth config) lives in `lib/`.
37
+ - **One exported function per action/query file.** Name the file after
38
+ the function (`create-post.server.ts` exports `createPost`). It keeps
39
+ the action surface greppable.
40
+ - **Every feature has tests.** A `modules/<feature>/` directory should
41
+ have matching test files under `test/<feature>/`. A unit test for
42
+ logic, a browser/e2e test for user-facing behaviour.
43
+ - **Persist data with Prisma + SQLite, never JSON files.** The scaffold
44
+ wires up `prisma/schema.prisma` and `lib/prisma.server.ts`. A
45
+ `data/todos.json` or `db.json` used as a database resets on reload and
46
+ cannot scale; define a Prisma model instead.
65
47
 
66
48
  ---
67
49
 
@@ -125,9 +107,9 @@ checklist mirrors this list.
125
107
  If yes, update it on this PR. Common surfaces (non-exhaustive):
126
108
  - `AGENTS.md` (root and every nested one) for API surface, invariants,
127
109
  file-routing rules, project-wide agent workflow.
128
- - `CONVENTIONS.md` (this file) for architectural conventions. Do NOT
129
- enumerate lint rules in prose; those live in `package.json` under
130
- `"webjs": { "conventions": { … } }`.
110
+ - `CONVENTIONS.md` (this file) for project conventions (layout,
111
+ naming, testing). The `webjs check` correctness rules are a separate
112
+ tool surface, not documented here (run `webjs check --rules`).
131
113
  - `README.md` (root and any nested ones) for install / use / public
132
114
  surface descriptions.
133
115
  - `CHANGELOG.md` for any user-visible change, including the SHA / PR
@@ -267,8 +249,8 @@ deploy`, and `npm run db:migrate` / `db:generate` / `db:studio` scripts.
267
249
  comments, users…), define a Prisma model in `prisma/schema.prisma`
268
250
  and persist there.
269
251
  2. **NEVER** create JSON files under `data/`, `db.json`, `posts.json`,
270
- `todos.json`, etc. as a fake database. The `no-json-data-files`
271
- convention check flags this and `webjs check` will fail.
252
+ `todos.json`, etc. as a fake database. It resets on reload and cannot
253
+ scale; this is a project convention (see the conventions section above).
272
254
  3. **NEVER** use module-scope arrays or `Map`s as a "store". They
273
255
  reset on every dev-server reload and can't scale beyond one process.
274
256
  4. **NEVER** use `localStorage` / `sessionStorage` to persist app data -
@@ -878,11 +860,15 @@ toggle, the tab switch) requires JS.
878
860
  JS will fill it in. The first paint must be the right content.
879
861
 
880
862
  **SSR-meaningful component state.** The SSR pipeline constructs the
881
- component, applies its attributes, and calls `render()`. It does NOT
882
- call `connectedCallback`, `firstUpdated`, or any other browser-only
883
- lifecycle hook. Whatever state should appear on first paint MUST be
884
- set in the constructor (after `super()`) or be derivable from
885
- `static properties` + attributes on the rendered tag.
863
+ component, applies its attributes, runs `willUpdate` and controllers'
864
+ `hostUpdate`, and calls `render()`. It does NOT call `connectedCallback`,
865
+ `firstUpdated`, `updated`, or any other browser-only lifecycle hook.
866
+ Whatever state should appear on first paint MUST be set in the
867
+ constructor (after `super()`), derived in `willUpdate`, or derivable
868
+ from `static properties` + attributes on the rendered tag. Reading
869
+ `this.getAttribute` / `hasAttribute` in `render()` works server-side (a
870
+ server attribute shim backs the attribute methods), but a `Task`'s
871
+ fetch still runs only on the client.
886
872
 
887
873
  ```ts
888
874
  import { WebComponent, html, signal } from '@webjsdev/core';
@@ -1019,15 +1005,17 @@ This project enforces a git workflow via agent-specific config files
1019
1005
 
1020
1006
  ---
1021
1007
 
1022
- ## Overriding conventions
1008
+ ## Customizing conventions
1023
1009
 
1024
- See the **"How `CONVENTIONS.md` relates to `webjs check`"** section at
1025
- the top of this file. Short version: set a rule to `false` in
1026
- `package.json` under `"webjs": { "conventions": { … } }`. With no
1027
- override, every default rule is on.
1010
+ The conventions in this file are guidance, so customize them directly:
1011
+ edit the prose under any `<!-- OVERRIDE -->` marker. There is no
1012
+ `package.json` switch and nothing to toggle, because conventions are not
1013
+ enforced by a tool.
1028
1014
 
1029
- Run `webjs check` to validate. Run `webjs check --rules` to list every
1030
- rule with its description and current enabled state.
1015
+ `webjs check` is separate: it runs only correctness checks (a crash, a
1016
+ security leak, a build/type-strip failure), always, with no per-project
1017
+ disabling. Run `webjs check` to validate, and `webjs check --rules` to
1018
+ list those checks.
1031
1019
 
1032
1020
  ---
1033
1021
 
@@ -33,6 +33,17 @@ ENV NODE_ENV=production
33
33
  ENV PORT=8080
34
34
  EXPOSE 8080
35
35
 
36
+ # Platform-neutral readiness gate. webjs answers /__webjs/ready with 503 until
37
+ # the instance is fully warm (analysis + first vendor attempt), then 200. This
38
+ # HEALTHCHECK is honoured by Docker, compose, and most Docker-based platforms,
39
+ # so the gate works the same everywhere instead of needing a per-platform file.
40
+ # The probe is dependency-free (Node 24's built-in fetch, no curl/wget). For
41
+ # platforms that read their own config, point the equivalent knob at the same
42
+ # path (Railway healthcheckPath, Render healthCheckPath, Fly [checks], k8s
43
+ # readinessProbe); see AGENTS.md "Health and readiness probes".
44
+ HEALTHCHECK --interval=15s --timeout=3s --start-period=40s --retries=5 \
45
+ CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||8080)+'/__webjs/ready').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"]
46
+
36
47
  # `npm start` runs `prestart: prisma migrate deploy` (idempotent, a no-op when
37
48
  # there are no migrations yet) and then `webjs start`, which serves on $PORT.
38
49
  CMD ["npm", "start"]
@@ -23,6 +23,14 @@ services:
23
23
  # REDIS_URL: redis://redis:6379
24
24
  volumes:
25
25
  - app-data:/data
26
+ # Readiness gate: hold the service "starting" until /__webjs/ready returns
27
+ # 200 (fully warm). Same probe as the Dockerfile HEALTHCHECK; dependency-free.
28
+ healthcheck:
29
+ test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||8080)+'/__webjs/ready').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"]
30
+ interval: 15s
31
+ timeout: 3s
32
+ start_period: 40s
33
+ retries: 5
26
34
 
27
35
  volumes:
28
36
  app-data: