docs: update portal for WRNexusJS 0.3.0

This commit is contained in:
2026-07-22 17:53:02 +05:30
parent 38ee481b8a
commit aac3998a78
980 changed files with 4987 additions and 4670 deletions
+988 -974
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -1,4 +1,4 @@
# WRNexusJS 0.2.79 comprehensive documentation index
# WRNexusJS 0.3.0 comprehensive documentation index
Status: Private Developer Preview. Runtime: Bun. UI language: .wrn.
This is the documentation application, not the framework monorepo.
@@ -40,7 +40,7 @@ This is the documentation application, not the framework monorepo.
- https://wrnexusjs.dev/benchmarks
- https://wrnexusjs.dev/roadmap
- https://wrnexusjs.dev/changelog
- https://wrnexusjs.dev/releases/0.2.79
- https://wrnexusjs.dev/releases/0.3.0
- https://wrnexusjs.dev/security
- https://wrnexusjs.dev/support
- https://wrnexusjs.dev/license
@@ -62,12 +62,14 @@ This is the documentation application, not the framework monorepo.
- https://wrnexusjs.dev/packages/mobile
- https://wrnexusjs.dev/packages/native
- https://wrnexusjs.dev/packages/oauth
- https://wrnexusjs.dev/packages/plugin
- https://wrnexusjs.dev/packages/pubsub
- https://wrnexusjs.dev/packages/queue
- https://wrnexusjs.dev/packages/reactive
- https://wrnexusjs.dev/packages/router
- https://wrnexusjs.dev/packages/ssr
- https://wrnexusjs.dev/packages/styles
- https://wrnexusjs.dev/packages/syntax
- https://wrnexusjs.dev/packages/test
- https://wrnexusjs.dev/packages/tracking
- https://wrnexusjs.dev/packages/ui
+437 -271
View File
@@ -1,6 +1,6 @@
# WRNexusJS documentation 0.2.79
# WRNexusJS documentation 0.3.0
Status: Private Developer Preview. This site documents 27 release-aligned packages.
Status: Private Developer Preview. This site documents 29 release-aligned packages.
# WrNexus
@@ -12903,7 +12903,7 @@ Events: none
# Installed package documentation
The following README files and declarations come from the installed private 0.2.79 release.
The following README files and declarations come from the installed private 0.3.0 release.
## @wrnexus/ai
@@ -13833,155 +13833,9 @@ A file opens with `page <Name>` or `component <Name>` followed by a `{ ... }` bo
### Exported TypeScript declarations
```ts
/**
* Recursive-descent parser for `.wrn`, producing a small AST.
*
* Grammar (subset of the vision, but real):
*
* page <Name> {
* types { <TypeScript declarations> }
* props { <ident>: <type> [= <expr>] } // no default means required
* state <ident>: <type> = <expr> // type annotation is optional
* view { <html> } // plain HTML (see parseHtmlView)
* seo { title = "Home" description = "..." }
* ssr { api <name> <METHOD> <path> { <render js> } functions { <raw js> } }
* client { api <name> <METHOD> <path> { <render js> } functions { <raw js> } }
* style { <raw css> } // zero or more, inlined with the page
* functions { <raw js> } // zero or more, shared helpers
* api <METHOD> <path> { <raw js> } // zero or more
* realtime <name> { on <evt>(<args>) { <raw js> } * } // zero or more
* }
*
* The `view` block is written as ordinary HTML — nothing new to learn. Text may
* contain `{expr}` interpolation, attributes may be hyphenated (`data-*`), and
* `@event="..."` declares a client event binding. See `parseHtmlView`.
*/
interface StateDecl {
name: string;
/** Explicit TypeScript-style type annotation, when supplied. */
valueType?: string;
/** Raw JS initializer expression, e.g. `0` or `'x'`. */
expr: string;
}
interface Attr {
name: string;
value: string;
/** True for `@event` bindings (vs. plain HTML attributes). */
event: boolean;
/** True for a valueless boolean attribute, e.g. `<button disabled>`. */
boolean?: boolean;
}
type ViewNode = {
type: "text";
value: string;
} | {
type: "element";
tag: string;
attrs: Attr[];
children: ViewNode[];
}
/**
* A server-side loop: `{#each <list> as <item>[, <index>]} …body… {:empty} …empty… {/each}`.
* `list` is a JS expression (evaluated on the server, may reference an `ssr` data
* binding). The `body` is rendered once per item with `{item.field}` interpolation;
* `empty` renders when the list is empty. See codegen `compileEach`.
*/
| {
type: "each";
list: string;
item: string;
index?: string;
body: ViewNode[];
empty: ViewNode[];
}
/**
* A server-side conditional: `{#if <expr>} … {:else if <expr>} … {:else} … {/if}`.
* Rendered branches are chosen on the server. Each branch's `cond` is a JS expression
* (`null` for the final `{:else}`); the first truthy branch renders. See `compileIfExpr`.
*/
| {
type: "if";
branches: {
cond: string | null;
body: ViewNode[];
}[];
};
interface ApiBlock {
method: string;
path: string;
body: string;
}
type SeoBlock = Record<string, string>;
type DataMode = "ssr" | "client";
interface DataApiBlock {
mode: DataMode;
name: string;
method: string;
path: string;
body: string;
}
interface ModeFunctionsBlock {
mode: DataMode;
body: string;
}
interface LifecycleBlock {
mount?: string;
update?: string;
unmount?: string;
}
interface WatchBlock {
state: string;
body: string;
}
interface RealtimeHandler {
event: string;
args: string[];
body: string;
}
interface RealtimeBlock {
name: string;
handlers: RealtimeHandler[];
}
interface PropDecl {
name: string;
/** Explicit TypeScript-style type annotation, when supplied. */
valueType?: string;
/** Props without a default are required. */
required: boolean;
/** Raw JS default expression, e.g. `0` or `'Count'`. Its type drives coercion. */
default: string;
}
interface PageAst {
type: "page";
/** Static ES module imports declared before the WRN root declaration. */
imports: string[];
/**
* `page` is a route, `component` is a reusable fragment,
* and `layout` is a reusable page wrapper.
*/
kind: "page" | "component" | "layout";
name: string;
/** Name of the page layout (`app/layouts/<layout>.wrn`), if the page sets one. */
layout?: string;
/** Declared component props (empty for pages). */
props: PropDecl[];
/** Raw declarations from `types { ... }`, emitted as TypeScript. */
types: string[];
states: StateDecl[];
seo: SeoBlock;
view: ViewNode[];
styles: string[];
functions: string[];
dataApis: DataApiBlock[];
modeFunctions: ModeFunctionsBlock[];
lifecycle: LifecycleBlock;
watches: WatchBlock[];
apis: ApiBlock[];
realtimes: RealtimeBlock[];
}
declare class ParseError extends Error {
}
declare function parse(source: string): PageAst;
import { PageAst as PageAst$1, WrnDiagnostic } from '@wrnexus/syntax';
export { ActionBlock, ApiBlock, Attr, ComputedDecl, DataApiBlock, DataMode, EffectBlock, LexError, Lexer, LoadBlock, ModeFunctionsBlock, PageAst, ParseError, PropDecl, RealtimeBlock, SeoBlock, StateDecl, ViewNode, WrnDiagnostic, assertValidAst, diagnose, diagnosticFromError, eraseFunctionTypes, formatDiagnostic, inferredRuntimeType, parse, runtimeTypeOf } from '@wrnexus/syntax';
import { PageAst } from '@wrnexus/syntax/parser';
/**
* Code generation: lower a `.wrn` AST to TypeScript that targets the framework's
@@ -14008,99 +13862,32 @@ declare class NativeCompileError extends Error {
/** Compile a parsed `.wrn` page to an Expo Router React Native screen. */
declare function generateNative(ast: PageAst): string;
/**
* Lexer for the `.wrn` language.
*
* `.wrn` mixes a small structural grammar (page/state/view/api/realtime) with
* raw JavaScript bodies. A pure token stream can't represent the raw JS, so the
* lexer is driven on demand by the parser: it yields structural tokens via
* `next()`/`peek()`, and exposes `readBalancedBraces()`, `readPath()` and
* `readToLineEnd()` for the parser to grab raw spans when grammar demands it.
*/
type TokenType = "ident" | "string" | "lbrace" | "rbrace" | "lparen" | "rparen" | "at" | "eq" | "colon" | "comma" | "eof";
interface Token {
type: TokenType;
value: string;
pos: number;
}
declare class LexError extends Error {
}
declare class Lexer {
readonly src: string;
pos: number;
constructor(src: string);
/** Skip whitespace and `// line comments`. */
private skipTrivia;
/** Read and consume the next structural token. */
next(): Token;
/** Look at the next token without consuming it. */
peek(): Token;
private readString;
/** Read a route path like `/users/[id]` up to whitespace or `{`. */
readPath(): string;
/**
* Read a prop default initializer. The initializer may contain nested arrays,
* objects, calls, strings, or template literals. At top level it ends at a
* newline, the closing brace of the props block, or the next inline prop
* declaration (`name = ...` / `name: Type = ...`).
*/
readPropInitializer(): string;
/** Read the rest of the current line (used for `state x = <expr>`). */
readToLineEnd(): string;
/**
* Read a TypeScript-style type annotation after `:`. Reading stops at a
* top-level `=` or line ending, while nested object/tuple/generic syntax is
* preserved. The optional `=` is consumed for the caller.
*/
readTypeAnnotation(): {
type: string;
hasDefault: boolean;
};
/**
* Read a `{ ... }` block and return its INNER text (no outer braces), with
* brace counting that respects string and template literals so a `}` inside a
* string doesn't end the block early.
*/
readBalancedBraces(): string;
private lineAt;
}
/** Utilities shared by typed `.wrn` parsing, validation, and code generation. */
type RuntimeType = "string" | "number" | "boolean" | "bigint" | "array" | "object" | "function" | "unknown";
declare function runtimeTypeOf(annotation: string | undefined): RuntimeType;
declare function inferredRuntimeType(expression: string): RuntimeType;
/**
* Browser behavior is evaluated as JavaScript, so erase TypeScript annotations
* from ordinary function declarations before serializing it into HTML.
* Server output retains the original typed source.
*/
declare function eraseFunctionTypes(source: string): string;
/**
* @wrnexus/compiler — the `.wrn` language compiler.
*
* Pipeline: source ──▶ Lexer ──▶ parse() ──▶ AST ──▶ generate() ──▶ TypeScript
*
* See VISION.md for the language design. The MVP supports `page` with `state`,
* `view`, `api`, and `realtime` blocks, lowering to the framework's primitives.
* Parsing and language diagnostics are provided by the canonical
* `@wrnexus/syntax` package. This package owns platform-specific codegen.
*/
interface CompileResult {
code: string;
ast: PageAst;
ast: PageAst$1;
/** Backward-compatible plain diagnostic messages. */
diagnostics: string[];
/** Structured diagnostics for editors, CI, and the DevToolbar. */
richDiagnostics: WrnDiagnostic[];
}
/** Compile `.wrn` source into an Expo Router React Native screen. */
declare function compileNativeWireFile(source: string): string;
/**
* Compile `.wrn` source into TypeScript source. Throws `ParseError` on invalid
* input (the dev loader surfaces this as a readable error page).
* Compile `.wrn` source into TypeScript source. Errors include a stable code,
* source location, code frame, and actionable hint whenever available.
*/
declare function compileWireFile(source: string, filePath?: string): string;
/** Richer entry point returning the AST and diagnostics alongside the code. */
declare function compile(source: string): CompileResult;
/** Richer entry point returning the AST and structured diagnostics. */
declare function compile(source: string, filePath?: string): CompileResult;
export { type ApiBlock, type Attr, type CompileResult, type DataApiBlock, type DataMode, LexError, Lexer, type ModeFunctionsBlock, NativeCompileError, type PageAst, ParseError, type PropDecl, type RealtimeBlock, type SeoBlock, type StateDecl, type ViewNode, compile, compileNativeWireFile, compileWireFile, eraseFunctionTypes, generate, generateNative, inferredRuntimeType, parse, runtimeTypeOf };
export { type CompileResult, NativeCompileError, compile, compileNativeWireFile, compileWireFile, generate, generateNative };
```
---
@@ -14496,6 +14283,54 @@ return new Response(html.toString(), { headers: { "content-type": "text/html" }
```ts
export { Fragment, Html, Component as JSXComponent, Props as JSXProps, Renderable, jsx, jsxs, mustache } from './jsx-runtime.js';
interface Tenant {
id: string;
slug?: string;
name?: string;
metadata?: Record<string, unknown>;
}
type TenantResolver = (ctx: Context) => Tenant | null | Promise<Tenant | null>;
interface TenantMiddlewareOptions {
required?: boolean;
status?: number;
}
declare function tenantMiddleware(resolveTenant: TenantResolver, options?: TenantMiddlewareOptions): Middleware;
declare function tenantFromSubdomain(lookup: (slug: string, ctx: Context) => Tenant | null | Promise<Tenant | null>, rootDomains?: string[]): TenantResolver;
declare function requireTenant(ctx: Context): Tenant;
/** Wrap a repository so every operation receives the current tenant id. */
declare function tenantScope<T extends object>(tenant: Tenant, repository: T): T & {
tenantId: string;
};
interface SpanRecord {
name: string;
startTime: number;
endTime?: number;
durationMs?: number;
status?: "ok" | "error";
attributes: Record<string, string | number | boolean>;
error?: unknown;
}
interface Tracer {
startSpan(name: string, attributes?: SpanRecord["attributes"]): Span;
records(): readonly SpanRecord[];
}
interface Span {
setAttribute(name: string, value: string | number | boolean): void;
end(status?: "ok" | "error", error?: unknown): SpanRecord;
}
declare function createTracer(clock?: () => number): Tracer;
declare function withSpan<T>(tracer: Tracer, name: string, run: (span: Span) => T | Promise<T>, attributes?: SpanRecord["attributes"]): Promise<T>;
interface TracingMiddlewareOptions {
/** Include W3C Server-Timing response headers. Defaults to true. */
serverTiming?: boolean;
/** Fraction of requests to trace, from 0 to 1. Defaults to 1. */
sampleRate?: number;
/** Called after a traced response completes. */
onComplete?: (ctx: Context, records: readonly SpanRecord[]) => void | Promise<void>;
}
declare function tracingMiddleware(tracerFactory?: (ctx: Context) => Tracer, options?: TracingMiddlewareOptions): Middleware;
interface CookieOptions {
path?: string;
domain?: string;
@@ -14600,6 +14435,10 @@ type Context = {
* by the `sessionAuth` middleware (or `logIn`); read via `getUser(ctx)`.
*/
user?: unknown;
/** Active tenant/workspace resolved by tenant middleware. */
tenant?: Tenant;
/** Request tracer installed by observability middleware. */
tracer?: Tracer;
/**
* The direct socket peer IP, set by the server from `server.requestIP`. This
* is NOT spoofable by request headers — prefer it over `x-forwarded-for` for
@@ -15210,7 +15049,102 @@ declare function createCorsPreflightResponse(req: Request, security?: SecurityCo
declare function resolveRequestUrl(req: Request, trustProxy?: boolean): URL;
declare function withSecurityHeaders(req: Request, res: Response, mode: Mode, security?: SecurityConfig, nonce?: string): Response;
export { type AsyncSessionBackend, type Bucket, CSRF_COOKIE, CSRF_HEADER, type CacheControlOptions, type ContentSecurityPolicyConfig, type Context, type CookieOptions, type CookieStore, type CorsConfig, type CorsOrigin, type CspDirectiveValue, type HstsConfig, type LocalStorageSnapshot, type Middleware, type Mode, type Next, type PageComponent, type PageMeta, type PermissionsPolicyConfig, type RateLimitOptions, type RateLimitStore, type RawSocket, type RealtimeBridge, type RealtimeBus, type RealtimeConnectMeta, type RealtimeEnvelope, type RealtimeHandler, type RealtimeRegistry, type RealtimeSocket, type RequestLoggerOptions, type RequestRecord, type RequireAuthOptions, type Room, type RoomAuthInfo, type RoomClient, type RoomDefinition, type RoomHandlers, SESSION_USER_KEY, type SaveUploadOptions, type SavedUpload, type SecurityConfig, type SeoConfig, type ServerSentEvent, type SessionBackend, type SessionEntry, type SessionStore, type StreamResponseInit, type TFunction, TTLCache, type Target, type TrustedTypesConfig, UploadError, bridgeRealtime, cacheControl, collectUploads, createContext, createCorsPreflightResponse, createRealtimeRegistry, csrfProtection, csrfToken, defaultKey, defineRoom, escapeHtml, etag, getUser, hashPassword, isRoomDefinition, isSafeIslandName, isSafeRequestPath, isWebSocketOriginAllowed, loadSession, logIn, logOut, notModified, peerKey, proxyKey, rateLimit, renderDevError, renderError, renderNotFound, renderProdError, renderStatusPage, requestLogger, requireAuth, resolveRequestUrl, sanitizeFilename, saveUpload, sessionAuth, setSessionBackend, sse, streamResponse, verifyCsrf, verifyPassword, withCacheControl, withContextHeaders, withSecurityHeaders };
interface SchemaLike<T> {
parse(input: unknown): T;
}
interface EndpointErrorBody {
code: string;
message: string;
details?: unknown;
}
declare class EndpointError extends Error {
readonly status: number;
readonly code: string;
readonly details?: unknown | undefined;
constructor(status: number, code: string, message: string, details?: unknown | undefined);
}
interface EndpointDefinition<I, O> {
input?: SchemaLike<I>;
output?: SchemaLike<O>;
auth?: "optional" | "required";
description?: string;
tags?: string[];
handler(input: I, ctx: Context): O | Promise<O>;
}
interface DefinedEndpoint<I, O> {
readonly definition: EndpointDefinition<I, O>;
(ctx: Context, input?: unknown): Promise<Response>;
}
/** Define a validated, typed endpoint that can also drive SDK/OpenAPI generation. */
declare function defineEndpoint<I = unknown, O = unknown>(definition: EndpointDefinition<I, O>): DefinedEndpoint<I, O>;
interface RpcClientOptions {
baseUrl?: string;
fetch?: typeof globalThis.fetch;
headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
}
/** Create a tiny typed RPC caller for endpoints exposed by a WrNexus app. */
declare function createRpcClient(options?: RpcClientOptions): <I, O>(path: string, input: I) => Promise<O>;
interface CachePolicy {
ttlMs?: number;
staleWhileRevalidateMs?: number;
tags?: string[] | ((ctx: Context) => string[]);
}
interface LoaderDefinition<T> {
cache?: CachePolicy;
load(ctx: Context): T | Promise<T>;
}
interface ActionDefinition<I, O> {
csrf?: boolean;
run(input: I, ctx: Context): O | Promise<O>;
invalidate?: string[] | ((output: O, ctx: Context) => string[]);
}
interface DefinedLoader<T> {
readonly definition: LoaderDefinition<T>;
(ctx: Context): Promise<T>;
}
interface DefinedAction<I, O> {
readonly definition: ActionDefinition<I, O>;
(input: I, ctx: Context): Promise<O>;
}
declare function defineLoader<T>(definition: LoaderDefinition<T>): DefinedLoader<T>;
declare function defineAction<I, O>(definition: ActionDefinition<I, O>): DefinedAction<I, O>;
/** Request-local fetch deduplication keyed by a stable string. */
declare function dedupe<T>(ctx: Context, key: string, load: () => T | Promise<T>): Promise<T>;
type FeatureValue = boolean | string | number;
type FeatureRule = FeatureValue | ((ctx: Context) => FeatureValue | Promise<FeatureValue>);
interface FeatureFlags {
get(name: string, ctx: Context): Promise<FeatureValue | undefined>;
enabled(name: string, ctx: Context): Promise<boolean>;
}
declare function defineFeatureFlags(rules: Record<string, FeatureRule>): FeatureFlags;
interface PerformanceBudgets {
routeJsBytes?: number;
routeCssBytes?: number;
htmlBytes?: number;
imageBytes?: number;
hydrationMs?: number;
serverRenderMs?: number;
}
interface PerformanceMeasurement {
routeJsBytes?: number;
routeCssBytes?: number;
htmlBytes?: number;
imageBytes?: number;
hydrationMs?: number;
serverRenderMs?: number;
}
interface BudgetViolation {
metric: keyof PerformanceBudgets;
budget: number;
actual: number;
overBy: number;
}
declare function checkPerformanceBudgets(budgets: PerformanceBudgets, measurement: PerformanceMeasurement): BudgetViolation[];
export { type ActionDefinition, type AsyncSessionBackend, type Bucket, type BudgetViolation, CSRF_COOKIE, CSRF_HEADER, type CacheControlOptions, type CachePolicy, type ContentSecurityPolicyConfig, type Context, type CookieOptions, type CookieStore, type CorsConfig, type CorsOrigin, type CspDirectiveValue, type DefinedAction, type DefinedEndpoint, type DefinedLoader, type EndpointDefinition, EndpointError, type EndpointErrorBody, type FeatureFlags, type FeatureRule, type FeatureValue, type HstsConfig, type LoaderDefinition, type LocalStorageSnapshot, type Middleware, type Mode, type Next, type PageComponent, type PageMeta, type PerformanceBudgets, type PerformanceMeasurement, type PermissionsPolicyConfig, type RateLimitOptions, type RateLimitStore, type RawSocket, type RealtimeBridge, type RealtimeBus, type RealtimeConnectMeta, type RealtimeEnvelope, type RealtimeHandler, type RealtimeRegistry, type RealtimeSocket, type RequestLoggerOptions, type RequestRecord, type RequireAuthOptions, type Room, type RoomAuthInfo, type RoomClient, type RoomDefinition, type RoomHandlers, type RpcClientOptions, SESSION_USER_KEY, type SaveUploadOptions, type SavedUpload, type SchemaLike, type SecurityConfig, type SeoConfig, type ServerSentEvent, type SessionBackend, type SessionEntry, type SessionStore, type Span, type SpanRecord, type StreamResponseInit, type TFunction, TTLCache, type Target, type Tenant, type TenantMiddlewareOptions, type TenantResolver, type Tracer, type TrustedTypesConfig, UploadError, bridgeRealtime, cacheControl, checkPerformanceBudgets, collectUploads, createContext, createCorsPreflightResponse, createRealtimeRegistry, createRpcClient, createTracer, csrfProtection, csrfToken, dedupe, defaultKey, defineAction, defineEndpoint, defineFeatureFlags, defineLoader, defineRoom, escapeHtml, etag, getUser, hashPassword, isRoomDefinition, isSafeIslandName, isSafeRequestPath, isWebSocketOriginAllowed, loadSession, logIn, logOut, notModified, peerKey, proxyKey, rateLimit, renderDevError, renderError, renderNotFound, renderProdError, renderStatusPage, requestLogger, requireAuth, requireTenant, resolveRequestUrl, sanitizeFilename, saveUpload, sessionAuth, setSessionBackend, sse, streamResponse, tenantFromSubdomain, tenantMiddleware, tenantScope, tracingMiddleware, verifyCsrf, verifyPassword, withCacheControl, withContextHeaders, withSecurityHeaders, withSpan };
```
---
@@ -15270,15 +15204,16 @@ getRealtimeRuntime(): string // → REALTIME_RUNTIME
Applied to any subtree containing `data-scope`. Expressions are parsed by a tiny eval-free evaluator, so a strict CSP with no `unsafe-eval` works.
| Directive | Purpose |
| -------------------------------------------------- | ----------------------------------------------------------------------- |
| `data-scope="count: 0, name: 'x'"` | Declare reactive state on a subtree |
| `data-on-<event>="count++"` | Run a statement in scope on a DOM event |
| `data-text="expr"` | Bind an element's `textContent` to an expression |
| `data-show="expr"` | Toggle visibility (`display`) on truthiness |
| `data-for="item in list"` (opt. `item, i in list`) | Per-item list rendering template |
| `{{expr}}` or `{expr}` | Interpolation inside text nodes and attribute values |
| `data-wrnexus-csr="id"` | Target for a generated CSR fetch binding (fetches `/__wrnexus/csr?...`) |
| Directive | Purpose |
| -------------------------------------------------------- | ----------------------------------------------------------------------- |
| `data-scope="count: 0, name: 'x'"` | Declare reactive state on a subtree |
| `data-on-<event>="count++"` | Run a statement in scope on a DOM event |
| `data-text="expr"` | Bind an element's `textContent` to an expression |
| `data-show="expr"` | Toggle visibility (`display`) on truthiness |
| `data-for="item in list"` (opt. index and `key item.id`) | Per-item rendering; stable keys preserve DOM identity during reorder |
| `data-key="item.id"` | Alternative key declaration for `data-for` templates |
| `{{expr}}` or `{expr}` | Interpolation inside text nodes and attribute values |
| `data-wrnexus-csr="id"` | Target for a generated CSR fetch binding (fetches `/__wrnexus/csr?...`) |
Supported expression features: literals, identifiers, member access (`a.b`, `a[b]`), function/method calls, arrays, objects, arithmetic, comparison, equality, logical (`&& ||`), unary (`! - +`), and ternary. Statements support `++`/`--`, assignment operators (`= += -= *= /= %=`), and bare expression/method calls. Rendering is dependency-tracked: a signal change only re-runs the renderers that actually read it.
@@ -16198,10 +16133,11 @@ Pages get only the scripts they use: `nav.js` always, `reactive.js` when a page
```ts
import { Mode, Middleware, SeoConfig, SecurityConfig, RealtimeBus, RealtimeConnectMeta } from '@wrnexus/core';
import { Router } from '@wrnexus/router';
import { ResolvedTheme, MobileConfig, PwaConfig, StylesConfig, ThemeConfig } from '@wrnexus/styles';
import { ResolvedTheme, MobileConfig, PwaConfig, ObservabilityConfig, TenancyConfig, StylesConfig, ThemeConfig } from '@wrnexus/styles';
import { ResolvedI18n, I18nConfig } from '@wrnexus/i18n';
import { StorageConfig } from '@wrnexus/uploader';
import { DevToolbarConfig } from '@wrnexus/dev-toolbar/types';
import { PluginInput } from '@wrnexus/plugin';
import { DevToolbarCollector } from '@wrnexus/dev-toolbar/server';
import { IncomingMessage, ServerResponse, Server } from 'node:http';
@@ -16310,6 +16246,10 @@ interface RuntimeDeps {
pwa?: PwaConfig | false;
/** Framework security headers and CORS policy. */
security?: SecurityConfig;
/** Built-in request tracing and Server-Timing policy. */
observability?: ObservabilityConfig;
/** Built-in tenant identity resolution. */
tenancy?: TenancyConfig;
/** Max request body size in bytes (413 above this). Default 10 MB. */
maxBodyBytes?: number;
/** HMR hub for browser live-update sockets (dev only). */
@@ -16529,6 +16469,10 @@ interface ProdOptions {
pwa?: PwaConfig | false;
/** Framework security headers and CORS policy. */
security?: SecurityConfig;
/** Built-in request tracing and Server-Timing policy. */
observability?: ObservabilityConfig;
/** Built-in tenant identity resolution. */
tenancy?: TenancyConfig;
port?: number;
hostname?: string;
maxBodyBytes?: number;
@@ -16623,6 +16567,9 @@ interface ServeOptions {
mobile?: MobileConfig;
pwa?: PwaConfig | false;
devToolbar?: boolean | DevToolbarConfig;
plugins?: PluginInput;
observability?: ObservabilityConfig;
tenancy?: TenancyConfig;
}
interface RunningServer {
port: number;
@@ -17938,6 +17885,74 @@ export { type CompleteAuthOptions, type OAuthProfile, type OAuthProvider, type O
---
## @wrnexus/plugin
Documentation URL: https://wrnexusjs.dev/packages/plugin
# @wrnexus/plugin
Deterministic WRNexusJS plugin contracts for configuration, AST/code transforms,
diagnostics, development servers, production builds, and DevToolbar extensions.
Use `definePlugin()` and declare `enforce`, `before`, or `after` when ordering matters.
Duplicate names and dependency cycles are rejected.
### Exported TypeScript declarations
```ts
import { PageAst, WrnDiagnostic } from '@wrnexus/syntax';
type PluginOrder = "pre" | "normal" | "post";
interface PluginContext {
root: string;
mode: "development" | "production";
command: "dev" | "build" | "test";
profile?: string;
metadata: Map<string, unknown>;
warn(message: string): void;
}
interface TransformContext extends PluginContext {
file: string;
}
interface WrnexusPlugin {
name: string;
version?: string;
enforce?: PluginOrder;
/** Plugin names that must execute first. */
after?: string[];
/** Plugin names that must execute later. */
before?: string[];
configure?(config: Record<string, unknown>, context: PluginContext): void | Promise<void>;
configResolved?(config: Readonly<Record<string, unknown>>, context: PluginContext): void | Promise<void>;
transformAst?(ast: PageAst, context: TransformContext): PageAst | void | Promise<PageAst | void>;
transformCode?(code: string, context: TransformContext): string | void | Promise<string | void>;
diagnostics?(ast: PageAst, context: TransformContext): WrnDiagnostic[] | Promise<WrnDiagnostic[]>;
routes?(routes: unknown[], context: PluginContext): unknown[] | void | Promise<unknown[] | void>;
configureServer?(server: unknown, context: PluginContext): void | Promise<void>;
buildStart?(context: PluginContext): void | Promise<void>;
buildEnd?(result: unknown, context: PluginContext): void | Promise<void>;
devToolbarPanels?(context: PluginContext): unknown[] | Promise<unknown[]>;
}
type PluginInput = WrnexusPlugin | false | null | undefined | PluginInput[];
declare function definePlugin(plugin: WrnexusPlugin): WrnexusPlugin;
/** Resolve plugin order deterministically and reject duplicates/cycles. */
declare function resolvePlugins(input: PluginInput): WrnexusPlugin[];
interface PluginRunner {
readonly plugins: readonly WrnexusPlugin[];
configure(config: Record<string, unknown>): Promise<void>;
configResolved(config: Readonly<Record<string, unknown>>): Promise<void>;
transformAst(ast: PageAst, file: string): Promise<PageAst>;
transformCode(code: string, file: string): Promise<string>;
diagnostics(ast: PageAst, file: string): Promise<WrnDiagnostic[]>;
hook(name: "buildStart" | "buildEnd" | "configureServer", value?: unknown): Promise<void>;
}
declare function createPluginRunner(input: PluginInput, context: PluginContext): PluginRunner;
export { type PluginContext, type PluginInput, type PluginOrder, type PluginRunner, type TransformContext, type WrnexusPlugin, createPluginRunner, definePlugin, resolvePlugins };
```
---
## @wrnexus/pubsub
Documentation URL: https://wrnexusjs.dev/packages/pubsub
@@ -18298,6 +18313,9 @@ interface Job<T = unknown> {
runAt: number;
/** If set, re-enqueue this job this many ms after each successful run. */
repeat?: number;
priority: number;
idempotencyKey?: string;
createdAt: number;
}
type JobHandler<T = unknown> = (job: Job<T>) => void | Promise<void>;
interface AddOptions {
@@ -18307,6 +18325,10 @@ interface AddOptions {
maxAttempts?: number;
/** Re-enqueue this job this many ms after each successful run (recurring). */
repeat?: number;
/** Higher-priority jobs run first when multiple jobs are due. */
priority?: number;
/** Prevent duplicate queued work with the same stable key. */
idempotencyKey?: string;
}
interface QueueOptions {
/** Default max attempts per job. Default 3. */
@@ -18317,6 +18339,8 @@ interface QueueOptions {
pollMs?: number;
/** Called when a job exhausts its attempts. */
onFailed?: (job: Job, error: unknown) => void;
/** Maximum jobs executed in one drain. Default: unlimited. */
concurrency?: number;
/** Clock injection (tests). Default Date.now. */
now?: () => number;
}
@@ -18328,10 +18352,29 @@ interface Queue {
start(): void;
stop(): void;
size(): number;
get(id: string): Job | undefined;
list(name?: string): Job[];
cancel(id: string): boolean;
}
interface JobDefinition<I> {
name: string;
options?: Omit<AddOptions, "idempotencyKey">;
run: JobHandler<I>;
}
declare function defineJob<I>(definition: JobDefinition<I>): JobDefinition<I>;
interface WorkflowStep<I, O> {
name: string;
run(input: I): O | Promise<O>;
}
declare function defineWorkflow<T>(name: string, steps: Array<WorkflowStep<any, any>>): {
name: string;
steps: WorkflowStep<any, any>[];
run(input: T): Promise<unknown>;
};
declare function cronToInterval(cron: string): number;
declare function createQueue(options?: QueueOptions): Queue;
export { type AddOptions, type Job, type JobHandler, type Queue, type QueueOptions, createQueue };
export { type AddOptions, type Job, type JobDefinition, type JobHandler, type Queue, type QueueOptions, type WorkflowStep, createQueue, cronToInterval, defineJob, defineWorkflow };
```
---
@@ -18444,33 +18487,36 @@ user.set({ name: "Ada" });
```ts
/**
* A minimal, type-safe reactive signal with zero dependencies.
*
* This is the seed of the framework's reactivity. Today it powers nothing on
* its own, but it is shaped so client islands (and later the `.wrn` compiler's
* `state` blocks) can build reactive bindings on top of it.
*
* const count = signal(0)
* count.get() // 0
* count.set(1) // notifies subscribers
* const off = count.subscribe(v => console.log(v))
* off() // unsubscribe
* Fine-grained reactive primitives shared by server utilities and client code.
* Updates are synchronous by default and coalesced inside `batch()`.
*/
type Subscriber<T> = (value: T) => void;
type Subscriber<T> = (value: T, previous?: T) => void;
type Unsubscribe = () => void;
type Cleanup = () => void;
interface Signal<T> {
/** Read the current value. */
get(): T;
/** Write a new value; subscribers run only when the value actually changes. */
set(next: T): void;
/** Apply a function to the current value. */
update(fn: (current: T) => T): void;
/** Subscribe to changes; returns an unsubscribe function. */
subscribe(fn: Subscriber<T>): Unsubscribe;
}
interface ReadonlySignal<T> {
get(): T;
subscribe(fn: Subscriber<T>): Unsubscribe;
}
/** Coalesce every signal notification made by `fn` into one flush. */
declare function batch<T>(fn: () => T): T;
/** Read reactive values without recording dependencies. */
declare function untrack<T>(fn: () => T): T;
declare function signal<T>(initial: T): Signal<T>;
/**
* Run a dependency-tracked side effect. Dependencies are rebuilt after every
* execution, preventing stale subscriptions when conditional reads change.
*/
declare function effect(run: () => void | Cleanup): Cleanup;
/** Create a lazily readable derived signal with automatic dependency tracking. */
declare function computed<T>(read: () => T): ReadonlySignal<T>;
export { type Signal, type Subscriber, type Unsubscribe, signal };
export { type Cleanup, type ReadonlySignal, type Signal, type Subscriber, type Unsubscribe, batch, computed, effect, signal, untrack };
```
---
@@ -18662,9 +18708,18 @@ export { Middleware } from '@wrnexus/core';
/**
* Route compilation + matching.
*
* A "route" is a URL pattern compiled to a RegExp. We support static segments
* and dynamic `[param]` segments, e.g. `/users/[id]` -> `{ id }`.
* Supported segments:
* [id] required parameter
* [id?] optional parameter
* [[id]] optional parameter (directory-friendly form)
* [...slug] required catch-all
* [[...slug]] optional catch-all
*/
interface RouteParam {
name: string;
optional: boolean;
catchAll: boolean;
}
interface Route {
/** The human-readable route pattern, e.g. `/users/[id]`. */
raw: string;
@@ -18674,25 +18729,33 @@ interface Route {
regex: RegExp;
/** Ordered names of dynamic params captured by `regex`. */
paramNames: string[];
/** Rich parameter metadata. Optional for compatibility with old manifests. */
paramMeta?: RouteParam[];
}
interface RouteMatch {
route: Route;
params: Record<string, string>;
}
/** Compile a `/users/[id]` style pattern into a RegExp + param names. */
declare function compileRoutePattern(raw: string): Pick<Route, "regex" | "paramNames">;
/** Return parameter metadata without requiring callers to inspect the regex. */
declare function getRouteParams(raw: string): RouteParam[];
/** Compile a WRNexus route pattern into a RegExp + parameter metadata. */
declare function compileRoutePattern(raw: string): Pick<Route, "regex" | "paramNames" | "paramMeta">;
/**
* Order routes so that static routes win over dynamic ones, and longer/more
* specific routes win over shorter ones. Sorting once keeps matching simple.
* Order routes so static and constrained routes win over optional/catch-all
* routes. The ordering remains deterministic for identical specificity.
*/
declare function sortRoutes(routes: Route[]): Route[];
/** Find duplicate URL patterns before request handling starts. */
declare function findRouteConflicts(routes: Route[]): Array<{
raw: string;
files: string[];
}>;
/** Find the first route whose pattern matches `pathname`. */
declare function matchRoute(routes: Route[], pathname: string): RouteMatch | null;
/**
* Typed-routes codegen. From the scanned page routes, emit `app/routes.gen.ts`
* with a `Routes` map (path param types) and an `href()` builder — so links
* are checked at compile time (unknown path or missing param = type error).
* with a `Routes` map (path -> param types) and an `href()` builder.
*/
declare function generateRoutesFile(pages: Route[]): string;
@@ -18742,10 +18805,17 @@ interface RouterOptions {
*/
componentDirs?: string[];
}
/**
* Convert a scanned file's relative path into a URL route pattern.
* - strips the extension
* - drops a trailing `index` segment
* - prefixes with `prefix` (e.g. "/api")
*/
declare function fileToRoute(rel: string, prefix?: string): string;
/** Scan an app directory and build all route tables. */
declare function buildRouter(appDir: string, opts?: RouterOptions): Router;
export { type ComponentRef, type Route, type RouteMatch, type Router, type RouterOptions, buildRouter, compileRoutePattern, generateRoutesFile, matchRoute, sortRoutes };
export { type ComponentRef, type Route, type RouteMatch, type Router, type RouterOptions, buildRouter, compileRoutePattern, fileToRoute, findRouteConflicts, generateRoutesFile, getRouteParams, matchRoute, sortRoutes };
```
---
@@ -18923,8 +18993,18 @@ interface RenderOptions {
* out of its element or attribute.
*/
declare function renderDocument(opts: RenderOptions): string;
interface StreamRenderOptions extends Omit<RenderOptions, "body"> {
body: string | Promise<string> | AsyncIterable<string>;
}
/**
* Stream a complete document while preserving the exact head/body contract of
* `renderDocument`. Async iterables can flush a shell, primary content, and
* slower fragments without buffering the entire route.
*/
declare function renderDocumentStream(opts: StreamRenderOptions): ReadableStream<Uint8Array>;
declare function streamDocumentResponse(opts: StreamRenderOptions, init?: ResponseInit): Response;
export { type RenderOptions, renderDocument };
export { type RenderOptions, type StreamRenderOptions, renderDocument, renderDocumentStream, streamDocumentResponse };
```
---
@@ -19189,7 +19269,8 @@ In templates, consume tokens via the custom properties:
### Exported TypeScript declarations
```ts
import { SeoConfig, SecurityConfig } from '@wrnexus/core';
import { PerformanceBudgets, SeoConfig, SecurityConfig } from '@wrnexus/core';
import { PluginInput } from '@wrnexus/plugin';
import { StorageConfig } from '@wrnexus/uploader';
/**
@@ -19444,7 +19525,54 @@ interface DevToolbarConfig {
largeImageBytes?: number;
veryLargeImageBytes?: number;
}
interface ExperimentalConfig {
serverComponents?: boolean;
streaming?: boolean;
partialHydration?: boolean;
typedRpc?: boolean;
pluginTransforms?: boolean;
[feature: string]: boolean | undefined;
}
interface PerformanceConfig {
budgets?: PerformanceBudgets;
/** `warn` reports budget violations; `error` fails production builds. */
enforcement?: "off" | "warn" | "error";
analyze?: boolean;
}
interface ObservabilityConfig {
enabled?: boolean;
serviceName?: string;
serverTiming?: boolean;
sampleRate?: number;
exporter?: "console" | "otlp" | "none";
endpoint?: string;
}
interface TenancyConfig {
mode?: "subdomain" | "domain" | "path" | "custom";
required?: boolean;
rootDomains?: string[];
pathPrefix?: string;
}
interface BuildConfig {
cache?: boolean;
cacheDir?: string;
sourceMaps?: boolean;
report?: boolean;
adapter?: "bun" | "node" | "static" | "serverless" | "edge" | string;
}
interface AppConfig {
/** Compiler/dev/build plugins, resolved in deterministic pre/normal/post order. */
plugins?: PluginInput;
/** Opt-in APIs that are not yet covered by stable compatibility guarantees. */
experimental?: ExperimentalConfig;
/** Route and asset budgets plus build analyzer behavior. */
performance?: PerformanceConfig;
/** Request tracing, Server-Timing, and exporter configuration. */
observability?: ObservabilityConfig;
/** First-class tenant resolution defaults. */
tenancy?: TenancyConfig;
/** Build cache, source map, report, and deployment adapter settings. */
build?: BuildConfig;
/** Development-only page diagnostics toolbar. Enabled by default in development. */
devToolbar?: boolean | DevToolbarConfig;
/** Raw HTML appended to every page's `<head>` (e.g. CDN stylesheet links). */
@@ -19530,6 +19658,20 @@ declare function loadAppConfig(appRoot: string, profile?: string): Promise<AppCo
* Returns the variables it loaded.
*/
declare function loadEnv(appRoot: string, profile: string): Record<string, string>;
interface ConfigIssue {
path: string;
severity: "error" | "warning";
message: string;
}
declare function defineConfig(config: AppConfig): AppConfig;
declare function validateAppConfig(config: AppConfig): ConfigIssue[];
interface ExplainedConfig {
profile: string;
config: AppConfig;
issues: ConfigIssue[];
sources: string[];
}
declare function explainAppConfig(appRoot: string, profile?: string): Promise<ExplainedConfig>;
/** Flatten a head config into a single HTML string. */
declare function headToString(head?: string | string[]): string;
@@ -19576,7 +19718,31 @@ declare function bundleCss(entryPath: string, mode: Mode): Promise<string>;
*/
declare function renderStyles(ctx: StyleProcessContext, styles?: StylesConfig): Promise<string>;
export { type AppConfig, type CustomThemePalette, DEFAULT_THEMES, type FontConfig, type FontDisplay, type GoogleFont, type LocalFontFace, type MobileConfig, type Mode, type PwaConfig, type ResolvedTheme, type StyleProcessContext, type StylesConfig, type Mode as StylesMode, THEME_COOKIE, THEME_CSS_HREF, THEME_JS_HREF, THEME_PALETTES, THEME_PALETTE_NAMES, type ThemeConfig, type ThemePaletteName, type ThemeTokens, bundleCss, findStyleEntry, fontCspSources, headToString, loadAppConfig, loadEnv, loadRawConfig, renderFontHead, renderProductionFontHead, renderStyles, renderThemeCss, renderThemeRuntime, resolveProfile, resolveThemeConfig, resolveThemeName };
export { type AppConfig, type BuildConfig, type ConfigIssue, type CustomThemePalette, DEFAULT_THEMES, type DevToolbarConfig, type ExperimentalConfig, type ExplainedConfig, type FontConfig, type FontDisplay, type GoogleFont, type LocalFontFace, type MobileConfig, type Mode, type ObservabilityConfig, type PerformanceConfig, type PwaConfig, type ResolvedTheme, type StyleProcessContext, type StylesConfig, type Mode as StylesMode, THEME_COOKIE, THEME_CSS_HREF, THEME_JS_HREF, THEME_PALETTES, THEME_PALETTE_NAMES, type TenancyConfig, type ThemeConfig, type ThemePaletteName, type ThemeTokens, bundleCss, defineConfig, explainAppConfig, findStyleEntry, fontCspSources, headToString, loadAppConfig, loadEnv, loadRawConfig, renderFontHead, renderProductionFontHead, renderStyles, renderThemeCss, renderThemeRuntime, resolveProfile, resolveThemeConfig, resolveThemeName, validateAppConfig };
```
---
## @wrnexus/syntax
Documentation URL: https://wrnexusjs.dev/packages/syntax
# @wrnexus/syntax
Canonical WRN lexer, parser, AST, language metadata, source positions, and stable
diagnostics. Framework tooling should import this package instead of implementing a
separate `.wrn` parser.
See `docs/WRN-LANGUAGE-SPEC-1.0.md` in the WRNexusJS repository.
### Exported TypeScript declarations
```ts
export { LexError, Lexer } from './tokenizer.js';
export { ActionBlock, ApiBlock, Attr, ComputedDecl, DataApiBlock, DataMode, EffectBlock, LifecycleBlock, LoadBlock, ModeFunctionsBlock, PageAst, ParseError, PropDecl, RealtimeBlock, RealtimeHandler, SeoBlock, StateDecl, VOID_ELEMENTS, ViewNode, WatchBlock, parse, parseHtmlView } from './parser.js';
export { RuntimeType, eraseFunctionTypes, inferredRuntimeType, runtimeTypeOf, validateTypedInitializer } from './types.js';
export { DiagnoseOptions, WrnDiagnostic, WrnDiagnosticSeverity, WrnSourcePosition, assertValidAst, classifyParseError, diagnose, diagnosticFromError, formatDiagnostic, isHydrationStrategy, isRuntimeTarget, positionAt } from './diagnostics.js';
export { WRN_DIAGNOSTIC_CODES, WRN_HYDRATION_STRATEGIES, WRN_LANGUAGE_VERSION, WRN_ROOT_KINDS, WRN_ROOT_MEMBERS, WRN_RUNTIME_TARGETS, WrnHydrationStrategy, WrnRootKind, WrnRootMember, WrnRuntimeTarget } from './spec.js';
```
---
+1 -1
View File
File diff suppressed because one or more lines are too long