@webjsdev/server 0.8.45 → 0.8.46

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjsdev/server",
3
- "version": "0.8.45",
3
+ "version": "0.8.46",
4
4
  "type": "module",
5
5
  "description": "webjs dev/prod server: SSR, router, API, server actions, live reload",
6
6
  "main": "index.js",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The optional `route(action, opts?)` convenience adapter (#488).
3
3
  *
4
- * REST endpoints in webjs go through `route.ts` (the framework's first-class
4
+ * REST endpoints in WebJs go through `route.ts` (the framework's first-class
5
5
  * HTTP handler). The ALWAYS-WORKS baseline is a hand-written `route.ts` that
6
6
  * imports a `'use server'` action and calls it:
7
7
  *
@@ -28,6 +28,22 @@
28
28
  * export const POST = route(createPost, { validate: createPostSchema });
29
29
  * ```
30
30
  *
31
+ * Passing the action's MODULE NAMESPACE instead of the function auto-applies the
32
+ * action's declared `export const middleware` and `export const validate`, so a
33
+ * guard declared once next to the action protects the REST boundary the same way
34
+ * it protects the RPC boundary (#876). This is the way to keep "declare once,
35
+ * protected on every entry point" true without re-listing the config:
36
+ *
37
+ * ```js
38
+ * // app/api/posts/route.ts
39
+ * import { route } from '@webjsdev/server';
40
+ * import * as postActions from '../../../modules/posts/actions/create-post.server.ts';
41
+ * export const POST = route(postActions); // its declared middleware + validate apply
42
+ * ```
43
+ *
44
+ * The function form still takes explicit `opts`, and an explicit `opts.middleware`
45
+ * / `opts.validate` overrides the module's declared config when both are given.
46
+ *
31
47
  * Adapter rules when invoked over HTTP:
32
48
  * - URL query params, route params (`ctx.params`), and the parsed JSON body
33
49
  * (for a method with a body) are merged into a single object argument
@@ -51,6 +67,7 @@
51
67
  import { runValidate } from './actions.js';
52
68
  import { runWithActionSignal } from './action-signal.js';
53
69
  import { runActionChain } from './action-middleware.js';
70
+ import { actionFunctionNames, actionMiddleware } from './action-config.js';
54
71
  import { readTextBounded, payloadTooLarge, DEFAULT_MAX_BODY_BYTES } from './body-limit.js';
55
72
  import { getBodyLimits } from './context.js';
56
73
 
@@ -69,16 +86,48 @@ function jsonBodyLimit() {
69
86
  * Expose a plain `'use server'` action over REST as a `route.ts`-style handler.
70
87
  *
71
88
  * @template A, R
72
- * @param {(input: A, ctx: { req: Request, params: Record<string,string> }) => R | Promise<R>} action
73
- * the server action to call (its source is unchanged; this only wraps the
74
- * HTTP-to-action adapter around it).
89
+ * @param {((input: A, ctx: { req: Request, params: Record<string,string> }) => R | Promise<R>) | Record<string, unknown>} actionOrModule
90
+ * the server action to call, OR the action's module namespace (`import * as m`)
91
+ * so its declared `middleware` / `validate` config is auto-applied (#876). Its
92
+ * source is unchanged; this only wraps the HTTP-to-action adapter around it.
75
93
  * @param {{
76
94
  * validate?: (input: any) => any,
77
95
  * middleware?: Function[],
78
96
  * }} [opts]
79
97
  * @returns {(req: Request, ctx?: { params?: Record<string,string> }) => Promise<Response>}
80
98
  */
81
- export function route(action, opts = {}) {
99
+ export function route(actionOrModule, opts = {}) {
100
+ // Resolve the callable action plus any config the caller did not pass
101
+ // explicitly. A function is used verbatim (the original form). A module
102
+ // namespace exposes the single action function and its declared config, so
103
+ // `route(mod)` inherits the same `middleware` / `validate` the RPC boundary
104
+ // reads (#876). An explicit `opts` value still wins over the declared one.
105
+ let action;
106
+ /** @type {{ middleware?: Function[], validate?: Function }} */
107
+ let declared = {};
108
+ if (typeof actionOrModule === 'function') {
109
+ action = actionOrModule;
110
+ } else if (actionOrModule && typeof actionOrModule === 'object') {
111
+ const names = actionFunctionNames(actionOrModule);
112
+ if (names.length !== 1) {
113
+ throw new Error(
114
+ `route(module) expects exactly one action function in the module, found ${names.length}` +
115
+ (names.length ? ` (${names.join(', ')})` : ''),
116
+ );
117
+ }
118
+ action = /** @type {Function} */ (actionOrModule[names[0]]);
119
+ declared = {
120
+ middleware: actionMiddleware(actionOrModule),
121
+ validate: typeof actionOrModule.validate === 'function'
122
+ ? /** @type {Function} */ (actionOrModule.validate)
123
+ : undefined,
124
+ };
125
+ } else {
126
+ throw new Error('route() expects an action function or a module namespace');
127
+ }
128
+ const validate = opts.validate ?? declared.validate;
129
+ const middlewareChain = opts.middleware ?? declared.middleware ?? [];
130
+
82
131
  return async function handler(req, ctx) {
83
132
  const params = (ctx && ctx.params) || {};
84
133
  const url = new URL(req.url);
@@ -102,13 +151,13 @@ export function route(action, opts = {}) {
102
151
  }
103
152
 
104
153
  let arg = { ...query, ...params, ...body };
105
- if (typeof opts.validate === 'function') {
154
+ if (typeof validate === 'function') {
106
155
  // Run the validator through the SHARED contract (#245) so the REST adapter
107
156
  // and the RPC path interpret a `{ success, fieldErrors }` envelope, a
108
157
  // throw, and a transform-return identically. A structured failure becomes
109
158
  // a 422 JSON; a throw stays a 400 (keeping a schema lib's `issues`); a
110
159
  // transform-return replaces the input.
111
- const v = runValidate(opts.validate, arg);
160
+ const v = runValidate(validate, arg);
112
161
  if (!v.ok) {
113
162
  if (v.thrown !== undefined) {
114
163
  const msg = v.result.error || 'Invalid input';
@@ -126,10 +175,9 @@ export function route(action, opts = {}) {
126
175
  // The action runs inside the request signal scope (#492) and the per-action
127
176
  // middleware chain (#490). `ranAction` distinguishes a real completion from
128
177
  // a middleware short-circuit (the action never ran).
129
- const middleware = opts.middleware || [];
130
178
  let ranAction = false;
131
179
  const result = await runWithActionSignal(req.signal, () =>
132
- runActionChain(middleware, { request: req, args: [arg], signal: req.signal }, () => {
180
+ runActionChain(middlewareChain, { request: req, args: [arg], signal: req.signal }, () => {
133
181
  ranAction = true;
134
182
  return action(/** @type any */ (arg), { req, params });
135
183
  }));
package/src/actions.js CHANGED
@@ -33,12 +33,12 @@ function jsonBodyLimit() {
33
33
  }
34
34
 
35
35
  /**
36
- * Internal RPC wire-format content type. Distinguishes webjs action
36
+ * Internal RPC wire-format content type. Distinguishes WebJs action
37
37
  * responses from plain `application/json` so the stub can pick the right
38
38
  * parser and external JSON consumers aren't confused.
39
39
  *
40
40
  * Uses the content type from the active serializer (defaults to
41
- * `application/vnd.webjs+json` with the built-in webjs serializer).
41
+ * `application/vnd.webjs+json` with the built-in WebJs serializer).
42
42
  */
43
43
  export const RPC_CONTENT_TYPE = 'application/vnd.webjs+json';
44
44
 
package/src/auth.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * NextAuth/Auth.js-style authentication for webjs.
2
+ * NextAuth/Auth.js-style authentication for WebJs.
3
3
  *
4
4
  * JWT or database sessions, Credentials + OAuth (Google, GitHub) providers.
5
5
  * Uses Web Crypto HMAC-SHA256: no external dependencies.
package/src/body-limit.js CHANGED
@@ -252,7 +252,7 @@ export async function readBytesBounded(req, limit) {
252
252
  /**
253
253
  * Read a request body as text, bounded by `limit`. Used by the RPC endpoint,
254
254
  * `readBody`, and the exposed-action REST path, all of which then parse the
255
- * text (webjs wire or JSON).
255
+ * text (WebJs wire or JSON).
256
256
  *
257
257
  * @param {Request} req
258
258
  * @param {number} limit max bytes (0 / negative = unlimited)
package/src/check.js CHANGED
@@ -14,7 +14,7 @@ import { analyzeElision } from './component-elision.js';
14
14
  import { RESERVED_CONFIG } from './action-config.js';
15
15
 
16
16
  /**
17
- * Convention validator for webjs apps.
17
+ * Convention validator for WebJs apps.
18
18
  *
19
19
  * Scans an app directory and reports correctness violations: things that
20
20
  * crash the app, leak a secret, or fail the build / type-strip. Designed to be
@@ -380,7 +380,7 @@ function findBrowserMemberUses(code) {
380
380
  }
381
381
 
382
382
  /**
383
- * Scan a webjs app directory and report convention violations.
383
+ * Scan a WebJs app directory and report convention violations.
384
384
  *
385
385
  * Every rule is a correctness check (a crash, a security leak, or a
386
386
  * build/type-strip failure), so they all run unconditionally. There is no
@@ -436,7 +436,7 @@ export async function checkConventions(appDir) {
436
436
  // redactor leaves them alone.
437
437
  if (!/class\s+\w+\s+extends\s+WebComponent/.test(scan)) continue;
438
438
  // Accept either registration pattern:
439
- // Counter.register('tag') (webjs idiom)
439
+ // Counter.register('tag') (WebJs idiom)
440
440
  // customElements.define('tag', Counter) (native)
441
441
  if (/\b[A-Z][A-Za-z0-9_$]*\.register\s*\(\s*['"`]/.test(scan)) continue;
442
442
  if (/\bcustomElements\.define\s*\(/.test(scan)) continue;
@@ -1208,7 +1208,7 @@ function findImportChain(graph, from, to) {
1208
1208
  * @param {Violation[]} violations appended to in place
1209
1209
  */
1210
1210
  async function checkServerImportInBrowserModule(appDir, violations) {
1211
- // No `app/` directory means this is not a routable webjs app (e.g. a bare
1211
+ // No `app/` directory means this is not a routable WebJs app (e.g. a bare
1212
1212
  // component library, or a fixture with only `lib/`); nothing ships, so the
1213
1213
  // rule has nothing to police. Skip rather than do the heavy analysis.
1214
1214
  if (!(await pathExists(join(appDir, 'app')))) return;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Static analyser deciding whether a webjs component module can be
2
+ * Static analyser deciding whether a WebJs component module can be
3
3
  * ELIDED from the browser, that is, never downloaded as JS because its
4
4
  * SSR'd HTML is the complete, final output and the component does no
5
5
  * client-side work.
@@ -34,7 +34,7 @@
34
34
  * packages/core/AGENTS.md and the MAINTAINER NOTE on the
35
35
  * WebComponent lifecycle in packages/core/src/component.js both
36
36
  * direct anyone adding an interactivity surface to update these
37
- * lists, since webjs development is largely AI-agent driven.
37
+ * lists, since WebJs development is largely AI-agent driven.
38
38
  */
39
39
 
40
40
  import {
@@ -101,7 +101,7 @@ export const CLIENT_LIFECYCLE_HOOKS = [
101
101
  'connectedCallback',
102
102
  'disconnectedCallback',
103
103
  'attributeChangedCallback',
104
- // Standard custom-element callback webjs does not itself define (so it
104
+ // Standard custom-element callback WebJs does not itself define (so it
105
105
  // is absent from the prototype guard's CLASSIFICATION), but an author
106
106
  // can still override it to do client work. Kept for conservatism.
107
107
  'adoptedCallback',
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Server-side scanner that walks the app tree and records the
3
- * browser-visible URL for every webjs component module.
3
+ * browser-visible URL for every WebJs component module.
4
4
  *
5
5
  * Called once on the first request (lazily, via `ensureReady`), then memoized. Results are used to prime the core
6
6
  * registry (`primeModuleUrl`) BEFORE any SSR render: so when a page
7
7
  * renders a component tag, `lookupModuleUrl(tag)` already has the URL
8
8
  * ready for `<link rel="modulepreload">` hints.
9
9
  *
10
- * The convention webjs uses is the web-standard one:
10
+ * The convention WebJs uses is the web-standard one:
11
11
  *
12
12
  * class Counter extends WebComponent { … }
13
13
  * customElements.define('my-counter', Counter);
package/src/cors.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Reusable CORS primitive for webjs.
2
+ * Reusable CORS primitive for WebJs.
3
3
  *
4
- * `cors(options)` returns a webjs MIDDLEWARE `(req, next) => Response`,
4
+ * `cors(options)` returns a WebJs MIDDLEWARE `(req, next) => Response`,
5
5
  * usable in `middleware.js` (root or per-segment) or wrapped around a
6
6
  * `route.js` handler. This is the public app-facing API. The shared
7
7
  * origin-resolution + header-building core (`resolveOrigin` /
package/src/csp.js CHANGED
@@ -181,7 +181,7 @@ export function readCspConfig(pkg) {
181
181
  export function mintNonce() {
182
182
  const bytes = new Uint8Array(16);
183
183
  crypto.getRandomValues(bytes);
184
- // Buffer is available in every webjs server runtime (Node 24+). Avoids a
184
+ // Buffer is available in every WebJs server runtime (Node 24+). Avoids a
185
185
  // hand-rolled base64 of a binary string.
186
186
  return Buffer.from(bytes).toString('base64');
187
187
  }
package/src/csrf.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * `cop-middleware` and Go 1.25's `http.CrossOriginProtection` use, and the
5
5
  * spiritual sibling of Next.js / Astro's Origin-vs-Host check.
6
6
  *
7
- * Why not a token cookie: webjs previously issued a per-request `webjs_csrf`
7
+ * Why not a token cookie: WebJs previously issued a per-request `webjs_csrf`
8
8
  * double-submit cookie on every SSR response. That made SSR HTML
9
9
  * un-cacheable at a CDN (a CDN skips a response with `Set-Cookie`, and a
10
10
  * cached one would share / poison the token across visitors). A header check
package/src/dev-error.js CHANGED
@@ -19,7 +19,7 @@ import { readFileSync } from 'node:fs';
19
19
  /**
20
20
  * Pull the first useful `file:line:column` out of an error stack. Prefers a
21
21
  * frame under `appDir` (the user's own code) over a framework / node_modules
22
- * frame, so the overlay points at the edit that broke, not webjs internals.
22
+ * frame, so the overlay points at the edit that broke, not WebJs internals.
23
23
  *
24
24
  * Handles the V8 stack forms `at fn (/abs/file.ts:12:5)`, `at /abs/file.ts:12:5`,
25
25
  * and `at file:///abs/file.ts:12:5`.
package/src/dev.js CHANGED
@@ -136,7 +136,7 @@ const MIME = {
136
136
  * `namespace` with values, parameter properties, legacy decorators
137
137
  * with `emitDecoratorMetadata`, `import = require`) throws at strip
138
138
  * time. The `erasable-typescript-only` and `no-non-erasable-typescript`
139
- * lint rules catch these at edit time. webjs is buildless end-to-end:
139
+ * lint rules catch these at edit time. WebJs is buildless end-to-end:
140
140
  * there is no bundler fallback.
141
141
  *
142
142
  * The transformed bytes are cached per request handler in `state.tsCache`
@@ -441,7 +441,7 @@ export async function readServerTimeoutsFromApp(appDir) {
441
441
  }
442
442
 
443
443
  /**
444
- * Create a reusable, framework-agnostic request handler for a webjs app.
444
+ * Create a reusable, framework-agnostic request handler for a WebJs app.
445
445
  * The returned `handle(req)` takes a standard `Request` and resolves to a
446
446
  * standard `Response`: suitable for Node http, Deno, Bun, Cloudflare Workers,
447
447
  * or embedding inside an Express/Fastify app.
@@ -456,7 +456,7 @@ export async function readServerTimeoutsFromApp(appDir) {
456
456
  * }} opts
457
457
  */
458
458
  export async function createRequestHandler(opts) {
459
- // Preflight: webjs needs Node 24+ (built-in TS strip + recursive fs.watch).
459
+ // Preflight: WebJs needs Node 24+ (built-in TS strip + recursive fs.watch).
460
460
  // Throw a clear Error here so an embedded host (Express/Fastify/Bun/Deno)
461
461
  // gets the actionable message at boot, not a cryptic API failure mid-request.
462
462
  assertNodeVersion({ onFail: 'throw' });
@@ -1464,7 +1464,7 @@ export async function createRequestHandler(opts) {
1464
1464
  }
1465
1465
 
1466
1466
  /**
1467
- * Start a webjs HTTP server. Thin wrapper around `createRequestHandler`.
1467
+ * Start a WebJs HTTP server. Thin wrapper around `createRequestHandler`.
1468
1468
  *
1469
1469
  * Speaks plain HTTP/1.1. TLS termination + HTTP/2 to the browser is
1470
1470
  * expected to be handled by a reverse proxy (PaaS edge, nginx, Caddy,
@@ -2138,7 +2138,7 @@ async function loadMiddleware(appDir, dev, logger) {
2138
2138
  * @param {import('./logger.js').Logger} logger
2139
2139
  */
2140
2140
  /**
2141
- * Create a plain HTTP/1.1 server. webjs deploys are expected to sit
2141
+ * Create a plain HTTP/1.1 server. WebJs deploys are expected to sit
2142
2142
  * behind a reverse proxy (PaaS edge, nginx, Caddy, etc.) that handles
2143
2143
  * TLS termination and speaks HTTP/2 to clients: Node's http2 module
2144
2144
  * doesn't need to be involved on the framework side.
@@ -2327,7 +2327,7 @@ async function exists(p) {
2327
2327
  * dev server returns the error to the caller. The
2328
2328
  * `erasable-typescript-only` and `no-non-erasable-typescript` lint
2329
2329
  * rules catch these at edit time. There is no bundler fallback;
2330
- * webjs is buildless end-to-end.
2330
+ * WebJs is buildless end-to-end.
2331
2331
  *
2332
2332
  * The backend is the runtime-appropriate stripper (#508): Node 24+'s built-in
2333
2333
  * `module.stripTypeScriptTypes`, or `amaro` on Bun (byte-identical, equally
@@ -2,7 +2,7 @@
2
2
  * App-level elision report (#646).
3
3
  *
4
4
  * A reporting layer over the `analyzeElision` verdict, NOT a second analysis
5
- * and NOT a build (webjs is no-build; elision is the server's analysis pass,
5
+ * and NOT a build (WebJs is no-build; elision is the server's analysis pass,
6
6
  * run at dev-server start and re-derived after each fs.watch rebuild). It
7
7
  * builds the module graph, runs `analyzeElision`, and returns the page / layout
8
8
  * route modules that SHIP WHOLE to the browser, each with the first
package/src/env-schema.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Startup env-var validation with a typed schema hook (issue #236).
3
3
  *
4
- * webjs auto-loads `<appDir>/.env` into `process.env` at boot, but does no
4
+ * WebJs auto-loads `<appDir>/.env` into `process.env` at boot, but does no
5
5
  * validation, so a missing or misconfigured required var (DATABASE_URL,
6
6
  * AUTH_SECRET, ...) fails late and cryptically (a database connect error
7
7
  * mid-request, an undefined secret signing a token). This module adds an
@@ -2,7 +2,7 @@
2
2
  * File storage primitive: a pluggable `FileStore` with a streaming local-disk
3
3
  * default adapter (issue #247).
4
4
  *
5
- * webjs already round-trips a native `File` / `Blob` / `FormData` over the RPC
5
+ * WebJs already round-trips a native `File` / `Blob` / `FormData` over the RPC
6
6
  * wire (the serializer), but nothing decided WHERE the bytes land. This module
7
7
  * is that answer. The model mirrors `cache.js` exactly: a documented interface,
8
8
  * a default adapter (`diskStore`), and a module singleton (`setFileStore` /
@@ -35,7 +35,7 @@
35
35
  * (`File` / `Blob` / `ReadableStream` / `Uint8Array` in, a `{ body, size,
36
36
  * contentType }` handle out), so an S3 / R2 / GCS adapter is a drop-in: it
37
37
  * implements the same `put` / `get` / `delete` / `url` and the call sites do
38
- * not change. webjs ships no S3 SDK; see the JSDoc on `FileStore` below.
38
+ * not change. WebJs ships no S3 SDK; see the JSDoc on `FileStore` below.
39
39
  *
40
40
  * @module file-storage
41
41
  */
package/src/forwarded.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Build a full URL from a Node IncomingMessage, respecting standard
3
3
  * reverse-proxy headers (`X-Forwarded-Proto`, `X-Forwarded-Host`).
4
4
  *
5
- * Why: webjs apps are almost always deployed behind a reverse proxy
5
+ * Why: WebJs apps are almost always deployed behind a reverse proxy
6
6
  * (Railway, Fly, Render, Vercel, Cloudflare, nginx, Caddy, Traefik -
7
7
  * see the no-build architecture docs). The proxy terminates TLS and
8
8
  * speaks plain HTTP/1.1 to the container, so `req.url` inside the
package/src/headers.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Secure-by-default response headers plus a small declarative per-path
3
3
  * header config (issue #232).
4
4
  *
5
- * webjs sets a baseline of standard security headers on every document
5
+ * WebJs sets a baseline of standard security headers on every document
6
6
  * and asset response, so a scaffolded app is not clickjackable or
7
7
  * MIME-sniffable out of the box (no reverse proxy required for the
8
8
  * baseline). The defaults are LITERAL HTTP headers, no abstraction.
package/src/json.js CHANGED
@@ -15,7 +15,7 @@ import { readTextBounded, BodyLimitError, DEFAULT_MAX_BODY_BYTES } from './body-
15
15
  * The helper reads the in-flight Request from the AsyncLocalStorage
16
16
  * request context. If the caller sent `Accept: application/vnd.webjs+json`
17
17
  * (e.g. via the `richFetch` client helper), the response body is
18
- * encoded with the webjs serializer so rich types (Date, Map, Set,
18
+ * encoded with the WebJs serializer so rich types (Date, Map, Set,
19
19
  * BigInt, TypedArrays, Blob, File, FormData, cycles) survive. Otherwise
20
20
  * the response is plain `application/json`, unchanged behaviour for
21
21
  * curl / external consumers.
@@ -47,7 +47,7 @@ export async function json(data, init = {}) {
47
47
  }
48
48
 
49
49
  /**
50
- * Parse a request body using the webjs serializer when the client sent
50
+ * Parse a request body using the WebJs serializer when the client sent
51
51
  * our content type, otherwise as plain JSON. Handy for route handlers
52
52
  * that accept rich bodies from the `richFetch` helper but plain JSON
53
53
  * from everyone else.
@@ -73,7 +73,7 @@ export function startBunListener(ctx) {
73
73
  const server = Bun.serve({
74
74
  port,
75
75
  idleTimeout: bunIdleTimeout(timeouts),
76
- // webjs owns its dev error overlay (over SSE) and handles thrown errors in
76
+ // WebJs owns its dev error overlay (over SSE) and handles thrown errors in
77
77
  // `fetch`, so Bun's own development error page must never interfere; keep it
78
78
  // deterministic (off) rather than tied to NODE_ENV.
79
79
  development: false,
@@ -172,7 +172,7 @@ export function startBunListener(ctx) {
172
172
  * the `open` handler; messages/close are forwarded to its emitter from the
173
173
  * `websocket.message` / `websocket.close` handlers.
174
174
  *
175
- * Only `'message'` and `'close'` are forwarded (the events webjs WS handlers and
175
+ * Only `'message'` and `'close'` are forwarded (the events WebJs WS handlers and
176
176
  * `broadcast()` use). Bun exposes no per-socket `'error'` / `'ping'` / `'pong'`
177
177
  * handler to bridge; a socket failure on Bun surfaces as a `'close'`, so
178
178
  * `'close'`-keyed cleanup still runs. Documented in the WebSockets doc.
package/src/logger.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Minimal pluggable logger.
3
3
  *
4
- * webjs doesn't pick pino/winston/bunyan for you. The default in prod emits
4
+ * WebJs doesn't pick pino/winston/bunyan for you. The default in prod emits
5
5
  * one JSON object per line to stdout: trivially ingestable by any log
6
6
  * aggregator. In dev, lines are plain text for readability.
7
7
  *
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Node-version preflight guard (issue #238).
3
3
  *
4
- * webjs depends on Node 24+ built-ins: `module.stripTypeScriptTypes` (the
4
+ * WebJs depends on Node 24+ built-ins: `module.stripTypeScriptTypes` (the
5
5
  * no-build TypeScript strip) and recursive `fs.watch` (dev live-reload). On an
6
6
  * older Node the failure surfaces late and cryptically (a strip error or a
7
7
  * missing API deep inside a request), not as a clear "you need Node 24+". This
package/src/redirects.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Declarative permanent / temporary redirects (issue #254).
3
3
  *
4
- * webjs already ships `redirect(url)` (a per-request throw sentinel) for
4
+ * WebJs already ships `redirect(url)` (a per-request throw sentinel) for
5
5
  * imperative, request-time redirects. This module adds the missing
6
6
  * DECLARATIVE surface: a config of old-path -> new-path rules an app
7
7
  * declares once and the framework applies at the very start of request
package/src/serializer.js CHANGED
@@ -2,7 +2,7 @@ import { stringify, parse } from '@webjsdev/core';
2
2
 
3
3
  /**
4
4
  * @typedef {Object} Serializer
5
- * A pluggable serializer that controls how webjs server actions encode and
5
+ * A pluggable serializer that controls how WebJs server actions encode and
6
6
  * decode values on the RPC wire.
7
7
  *
8
8
  * **AI hint:** The default serializer uses webjs's built-in
@@ -50,7 +50,7 @@ let current = defaultSerializer;
50
50
  *
51
51
  * **AI hint:** Use this in server-side code that needs to encode or decode
52
52
  * RPC payloads. It returns whatever serializer was set via `setSerializer`,
53
- * or the default webjs serializer if none was set.
53
+ * or the default WebJs serializer if none was set.
54
54
  *
55
55
  * @returns {Serializer}
56
56
  */
package/src/testing.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Server-side test harness helpers (issue #267).
3
3
  *
4
- * `createRequestHandler(...).handle(request)` drives the FULL webjs pipeline
4
+ * `createRequestHandler(...).handle(request)` drives the FULL WebJs pipeline
5
5
  * (middleware, routing, SSR, page actions, server-action RPC, auth + CSRF), and
6
6
  * the framework's own suite already drives it. These helpers are THIN builders
7
7
  * over the native `Request` / `Response` around that `handle()`, so an app test
@@ -350,7 +350,7 @@ export async function rawActionRequest(app, serverFilePath, fnName, args = [], o
350
350
  }
351
351
 
352
352
  /**
353
- * Browser-test harness (#806): build a webjs handler that a `web-test-runner`
353
+ * Browser-test harness (#806): build a WebJs handler that a `web-test-runner`
354
354
  * config can proxy module requests to, so a `test/**​/browser/*.test.js` file
355
355
  * can import a real `.ts` component that imports a `'use server'` action and it
356
356
  * loads + hydrates in a real browser. Plain WTR serves raw TS with no webjs
@@ -369,7 +369,7 @@ export async function rawActionRequest(app, serverFilePath, fnName, args = [], o
369
369
  * of `@webjsdev/server/testing` stays light (they pull the full server + the
370
370
  * `ws` WebSocket subsystem).
371
371
  *
372
- * @param {string} appDir the webjs app root (usually `process.cwd()`)
372
+ * @param {string} appDir the WebJs app root (usually `process.cwd()`)
373
373
  * @returns {Promise<{ handle: Handle, warmup: () => Promise<void>, importmapHtml: () => string }>}
374
374
  */
375
375
  export async function createBrowserTestHandler(appDir) {
package/src/ts-strip.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Pluggable TypeScript stripper (#508), the one seam that lets webjs run on both
2
+ * Pluggable TypeScript stripper (#508), the one seam that lets WebJs run on both
3
3
  * Node and Bun.
4
4
  *
5
- * webjs serves `.ts` / `.mts` source to the browser as JavaScript by ERASING the
5
+ * WebJs serves `.ts` / `.mts` source to the browser as JavaScript by ERASING the
6
6
  * type syntax in place (position-preserving whitespace replacement, so no
7
7
  * sourcemap is shipped and stack traces stay byte-exact). On Node 24+ that is the
8
8
  * built-in `module.stripTypeScriptTypes`. Bun has no such built-in, so this
package/src/vendor.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Resolve bare npm imports to browser-loadable URLs via jspm.io.
3
3
  *
4
- * webjs follows the Rails 7 + importmap-rails posture exactly. When user
4
+ * WebJs follows the Rails 7 + importmap-rails posture exactly. When user
5
5
  * code imports a bare specifier (e.g. `import dayjs from 'dayjs'`), the
6
6
  * browser can't resolve it natively. The framework's job is to emit an
7
7
  * importmap that translates each bare specifier to a real URL.
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * importmap: { "dayjs": "https://ga.jspm.io/npm:dayjs@1.11.13/index.js" }
12
12
  *
13
- * The browser fetches the bundle directly from jspm.io. The webjs server
13
+ * The browser fetches the bundle directly from jspm.io. The WebJs server
14
14
  * does not proxy, cache, or bundle anything. jspm.io has done the work
15
15
  * server-side (CJS-to-ESM conversion, transitive bundling, browser
16
16
  * polyfills).
@@ -85,7 +85,7 @@ const FRAMEWORK_SERVER_ONLY = new Set(['@webjsdev/cli', '@webjsdev/server', '@we
85
85
  * Excludes:
86
86
  * - `node_modules`, `.webjs`, `public` directories
87
87
  * - Any directory starting with `_` (webjs `_private/` convention)
88
- * - `test/` and `tests/` (server-only by webjs convention)
88
+ * - `test/` and `tests/` (server-only by WebJs convention)
89
89
  * - Files whose name marks them as server-only:
90
90
  * * `*.server.{js,ts,mjs,mts}` (path-level boundary)
91
91
  * * `route.{js,ts,mjs,mts}` (file-router HTTP handler)
@@ -1030,7 +1030,7 @@ export async function readPinFile(appDir) {
1030
1030
  * When `integrity` is provided and non-empty, it's included alongside
1031
1031
  * `imports` as a sibling key (matching the browser importmap-integrity
1032
1032
  * spec: a flat `{url: 'sha384-...'}` map). Omitted entirely when empty
1033
- * so older webjs versions read the file as before.
1033
+ * so older WebJs versions read the file as before.
1034
1034
  *
1035
1035
  * `provider` is persisted alongside imports when non-default. It lets
1036
1036
  * `webjs vendor update` know which CDN to re-resolve against, and
@@ -1343,7 +1343,7 @@ export async function pinAll(appDir, opts = {}) {
1343
1343
  }
1344
1344
 
1345
1345
  // The app legitimately has zero bare-specifier imports (or the
1346
- // scanner is running outside a webjs project). Don't create an
1346
+ // scanner is running outside a WebJs project). Don't create an
1347
1347
  // empty `.webjs/vendor/importmap.json`. Without this guard the file
1348
1348
  // gets written as `{ imports: {} }` in whatever cwd the CLI was
1349
1349
  // invoked from, then immediately rejected by readPinFile's empty