@webjsdev/server 0.8.14 → 0.8.16

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/index.d.ts ADDED
@@ -0,0 +1,707 @@
1
+ /**
2
+ * Public type surface for `@webjsdev/server`.
3
+ *
4
+ * The runtime is packages/server/index.js + src/*.js (JSDoc-annotated
5
+ * JavaScript, no build step); this overlay exists so a TypeScript app under
6
+ * `strict` + `nodenext`/`node16` resolves real types for the server import
7
+ * instead of emitting TS7016 ("Could not find a declaration file for module
8
+ * '@webjsdev/server'"). The whole package stays plain `.js` + JSDoc at runtime;
9
+ * these declarations are types-only with zero runtime cost.
10
+ *
11
+ * House style follows packages/core/index.d.ts: `export type` for type-only
12
+ * surface, `export declare function` / `export declare const` for runtime
13
+ * values. Shapes the framework consumes from core (`Metadata`, `PageProps`,
14
+ * `ActionResult`, …) are reused, never redefined; the high-traffic public API
15
+ * is precisely typed from each source function's JSDoc; lower-traffic internals
16
+ * (scanner / importmap / module-graph / vendor) get reasonable structural
17
+ * declarations.
18
+ *
19
+ * The drift guard `packages/server/test/types/exports-drift.test.mjs` asserts the set of named
20
+ * exports here exactly matches the runtime named exports of index.js, so a
21
+ * future export added to index.js without a type is caught.
22
+ */
23
+
24
+ import type { LayoutProps, PageProps, RouteHandlerContext } from '@webjsdev/core';
25
+
26
+ // The `./testing` subpath types are re-exported wholesale (the helpers ship
27
+ // from both the main entry and the subpath; this avoids duplicating them).
28
+ export * from './src/testing.d.ts';
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Shared local types
32
+ // ---------------------------------------------------------------------------
33
+
34
+ /** A webjs middleware: receives the request + a `next()` continuation. */
35
+ export type Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response> | Response;
36
+
37
+ // `Handle` is re-exported from ./src/testing.d.ts (the `export *` above), so it
38
+ // is not re-declared here. `RequestHandler.handle` / `Handle` reference it.
39
+
40
+ /**
41
+ * The `ActionResult<T>` envelope a server action / page action returns.
42
+ * Mirrors AGENTS.md's documented shape; `@webjsdev/core` does not export it,
43
+ * so it is defined here (the one server-owned shared type).
44
+ */
45
+ export type ActionResult<T = unknown> =
46
+ | { success: true; data?: T; redirect?: string }
47
+ | {
48
+ success: false;
49
+ error?: string;
50
+ fieldErrors?: Record<string, string>;
51
+ values?: Record<string, string>;
52
+ status?: number;
53
+ };
54
+
55
+ /** The pluggable cache store interface (`memoryStore` / `redisStore` / custom). */
56
+ export interface CacheStore {
57
+ get(key: string): Promise<string | null>;
58
+ set(key: string, value: string, ttlMs?: number): Promise<void>;
59
+ delete(key: string): Promise<void>;
60
+ /** Atomically increment a counter; returns the new value (TTL set on creation only). */
61
+ increment(key: string, ttlMs?: number): Promise<number>;
62
+ }
63
+
64
+ /** The pluggable logger interface. */
65
+ export interface Logger {
66
+ info(msg: string, meta?: Record<string, unknown>): void;
67
+ warn(msg: string, meta?: Record<string, unknown>): void;
68
+ error(msg: string, meta?: Record<string, unknown>): void;
69
+ debug?(msg: string, meta?: Record<string, unknown>): void;
70
+ }
71
+
72
+ /** The wire serializer used by the RPC transport. */
73
+ export interface Serializer {
74
+ serialize(value: unknown): Promise<string> | string;
75
+ deserialize(text: string): unknown;
76
+ }
77
+
78
+ /** Options shared by `createRequestHandler` and `startServer`. */
79
+ export interface RequestHandlerOptions {
80
+ /** The app root directory (the dir containing `app/`). */
81
+ appDir: string;
82
+ /** Dev mode (live reload, TS strip, uncompressed bytes). */
83
+ dev?: boolean;
84
+ /** Pluggable logger; defaults to webjs's `defaultLogger`. */
85
+ logger?: Logger;
86
+ /**
87
+ * APM / Sentry sink invoked on a caught unhandled error (#239). Best-effort:
88
+ * a throw here is swallowed and never affects the response.
89
+ */
90
+ onError?: (
91
+ error: unknown,
92
+ ctx: { request: Request; requestId: string | null; phase: string },
93
+ ) => void;
94
+ }
95
+
96
+ /** A matched page route for a path, as returned by `routeFor`. */
97
+ export interface RouteForResult {
98
+ moduleUrls: string[];
99
+ }
100
+
101
+ /** The object `createRequestHandler` resolves to. */
102
+ export interface RequestHandler {
103
+ /** The request -> response entry point for embedding under any host. */
104
+ handle: Handle;
105
+ /** Re-derive the route table / analysis after a source change (dev). */
106
+ rebuild: () => Promise<void>;
107
+ /** Resolve a pathname to its page-route module URLs (for 103 Early Hints), or null. */
108
+ routeFor: (pathname: string) => RouteForResult | null;
109
+ /** Proactively run the first-request analysis in the background. Idempotent, best-effort. */
110
+ warmup: () => Promise<void>;
111
+ /** Current route table getter (used by the WebSocket subsystem). */
112
+ getRouteTable: () => unknown;
113
+ /** The resolved app root. */
114
+ appDir: string;
115
+ /** Whether the handler is in dev mode. */
116
+ dev: boolean;
117
+ /** The active logger. */
118
+ logger: Logger;
119
+ }
120
+
121
+ /** Options for `startServer` (a superset of `RequestHandlerOptions`). */
122
+ export interface StartServerOptions extends RequestHandlerOptions {
123
+ /** Listen port (default 8080; `PORT` env honored by the CLI). */
124
+ port?: number;
125
+ /** Response compression (default: on in prod, off in dev). */
126
+ compress?: boolean;
127
+ }
128
+
129
+ /** The object `startServer` resolves to. */
130
+ export interface ServerHandle {
131
+ /** The underlying `node:http` server. */
132
+ server: import('node:http').Server;
133
+ /** Gracefully close the server (and abort the dev file watcher). */
134
+ close: () => Promise<void>;
135
+ }
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // Server entry: dev.js
139
+ // ---------------------------------------------------------------------------
140
+
141
+ /**
142
+ * Create an embeddable request handler. Returns `{ handle, rebuild, routeFor,
143
+ * warmup, getRouteTable, appDir, dev, logger }`. Throws at boot on an
144
+ * unsupported Node version or a failed `env.{js,ts}` validation.
145
+ */
146
+ export declare function createRequestHandler(opts: RequestHandlerOptions): Promise<RequestHandler>;
147
+
148
+ /** Start a webjs HTTP server (thin wrapper around `createRequestHandler`). */
149
+ export declare function startServer(opts: StartServerOptions): Promise<ServerHandle>;
150
+
151
+ // ---------------------------------------------------------------------------
152
+ // node-version.js (#238)
153
+ // ---------------------------------------------------------------------------
154
+
155
+ /** Parse a Node version string to its major integer. */
156
+ export declare function parseMajor(version: string): number;
157
+ /** Parse an `engines.node` range string to the minimum acceptable major. */
158
+ export declare function parseRequiredMajor(engines: string): number;
159
+ /** Pure comparison: is `current` at least `requiredMajor`? */
160
+ export declare function checkNodeVersion(
161
+ current: string,
162
+ requiredMajor: number,
163
+ ): { ok: boolean; current: string; currentMajor: number; requiredMajor: number; message: string };
164
+ /** The minimum Node major, sourced from this package's `engines.node`. */
165
+ export declare function requiredNodeMajor(): number;
166
+ /** Throw or exit if the running Node is too old. */
167
+ export declare function assertNodeVersion(opts?: {
168
+ current?: string;
169
+ requiredMajor?: number;
170
+ onFail?: 'exit' | 'throw';
171
+ }): void;
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // env-schema.js (#236)
175
+ // ---------------------------------------------------------------------------
176
+
177
+ /** Pure env validator: check an env object against a schema or validator function. */
178
+ export declare function validateEnv(
179
+ schema: object | ((env: Record<string, string | undefined>) => void),
180
+ env: Record<string, string | undefined>,
181
+ ): { ok: boolean; errors: string[]; coerced: Record<string, string> };
182
+ /** Compose the aggregated boot-failure message from a list of errors. */
183
+ export declare function formatEnvErrors(errors: string[]): string;
184
+ /** Read the optional app-root `env.{js,ts}` default export (null when absent). */
185
+ export declare function loadEnvSchema(
186
+ appDir: string,
187
+ opts?: { dev?: boolean },
188
+ ): Promise<object | ((env: Record<string, string | undefined>) => void) | null>;
189
+ /** Side-effecting boot wrapper: validate `process.env`, write back coerced values, throw on failure. */
190
+ export declare function applyEnvValidation(
191
+ appDir: string,
192
+ opts?: { dev?: boolean; env?: Record<string, string | undefined> },
193
+ ): Promise<void>;
194
+
195
+ // ---------------------------------------------------------------------------
196
+ // router.js
197
+ // ---------------------------------------------------------------------------
198
+
199
+ /** Scan `app/` and build the route table. */
200
+ export declare function buildRouteTable(appDir: string): Promise<unknown>;
201
+ /** Match a pathname against the page routes in a table; null when no page matches. */
202
+ export declare function matchPage(
203
+ table: unknown,
204
+ pathname: string,
205
+ ): { route: { file: string; layouts: string[] }; params: Record<string, string> } | null;
206
+ /** Match a pathname against the API (`route.{js,ts}`) routes in a table; null when none. */
207
+ export declare function matchApi(
208
+ table: unknown,
209
+ pathname: string,
210
+ ): { route: { file: string }; params: Record<string, string> } | null;
211
+
212
+ // ---------------------------------------------------------------------------
213
+ // route-types.js (#258)
214
+ // ---------------------------------------------------------------------------
215
+
216
+ /** Generate the augmentation `.d.ts` text for an app's routes (backs `webjs types`). */
217
+ export declare function generateRouteTypes(appDir: string): Promise<string>;
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // ssr.js
221
+ // ---------------------------------------------------------------------------
222
+
223
+ /** Server-render a matched page route to a `Response`. */
224
+ export declare function ssrPage(
225
+ route: unknown,
226
+ params: Record<string, string>,
227
+ url: string,
228
+ opts?: Record<string, unknown>,
229
+ ): Promise<Response>;
230
+ /** Server-render the nearest `not-found.{js,ts}` to a `Response`. */
231
+ export declare function ssrNotFound(notFoundFile: string, opts?: Record<string, unknown>): Promise<Response>;
232
+
233
+ // ---------------------------------------------------------------------------
234
+ // api.js
235
+ // ---------------------------------------------------------------------------
236
+
237
+ /** Dispatch a matched `route.{js,ts}` handler (GET/POST/...) to a `Response`. */
238
+ export declare function handleApi(
239
+ route: unknown,
240
+ params: Record<string, string>,
241
+ webRequest: Request,
242
+ dev: boolean,
243
+ ): Promise<Response>;
244
+
245
+ // ---------------------------------------------------------------------------
246
+ // actions.js (server-action scanner + RPC endpoint)
247
+ // ---------------------------------------------------------------------------
248
+
249
+ /** Scan the app for `.server.{js,ts}` files and build the RPC + expose index. */
250
+ export declare function buildActionIndex(appDir: string, dev: boolean, opts?: { skipExposeLoad?: boolean }): Promise<unknown>;
251
+ /** Whether a file path is a `.server.{js,ts,mjs,mts}` server file. */
252
+ export declare function isServerFile(file: string): boolean;
253
+ /** SHA-256 hash of an action file's absolute path (the RPC endpoint addressing scheme). */
254
+ export declare function hashFile(file: string): Promise<string>;
255
+ /** Resolve a browser-visible URL path to its server module entry in the action index. */
256
+ export declare function resolveServerModule(idx: unknown, urlPath: string): unknown;
257
+ /** Produce the generated RPC / throw-at-load stub source for a server file. */
258
+ export declare function serveActionStub(idx: unknown, absFile: string): Promise<string>;
259
+ /** Invoke a server action over the RPC endpoint, returning the `Response`. */
260
+ export declare function invokeAction(
261
+ idx: unknown,
262
+ hash: string,
263
+ fnName: string,
264
+ req: Request,
265
+ onError?: (error: unknown) => void,
266
+ ): Promise<Response>;
267
+
268
+ // ---------------------------------------------------------------------------
269
+ // importmap.js
270
+ // ---------------------------------------------------------------------------
271
+
272
+ /** Build the browser import map object (optionally content-hash-fingerprinted). */
273
+ export declare function buildImportMap(opts?: { fingerprint?: boolean }): unknown;
274
+ /** Render the `<script type="importmap">` tag (optionally CSP-nonced). */
275
+ export declare function importMapTag(opts?: { nonce?: string }): string;
276
+ /** Set the resolved vendor importmap entries (+ optional SRI integrity by URL). */
277
+ export declare function setVendorEntries(
278
+ entries: Record<string, string>,
279
+ integrity?: Record<string, string>,
280
+ ): Promise<void>;
281
+
282
+ // ---------------------------------------------------------------------------
283
+ // vendor.js (the `webjs vendor` CLI surface)
284
+ // ---------------------------------------------------------------------------
285
+
286
+ /** Scan a directory's source for bare-specifier npm imports. */
287
+ export declare function scanBareImports(dir: string, skipFiles?: Set<string>): Promise<Set<string>>;
288
+ /** Extract the package name from an import specifier (`dayjs/plugin/utc` -> `dayjs`). */
289
+ export declare function extractPackageName(spec: string): string | null;
290
+ /** Resolve bare imports to CDN importmap entries. */
291
+ export declare function vendorImportMapEntries(
292
+ bareImports: Set<string>,
293
+ appDir: string,
294
+ ): Promise<Record<string, string>>;
295
+ /** Resolve the app's vendor imports (pin file first, else live jspm). */
296
+ export declare function resolveVendorImports(
297
+ appDir: string,
298
+ getBareImports: () => Promise<Set<string>> | Set<string>,
299
+ ): Promise<{ imports: Record<string, string>; integrity?: Record<string, string>; provider?: string } | null>;
300
+ /** Clear the per-process vendor + live-integrity caches (wired to the dev rebuild). */
301
+ export declare function clearVendorCache(): void;
302
+ /** Read a package's installed version from `node_modules`, or null. */
303
+ export declare function getPackageVersion(pkgName: string, appDir: string): string | null;
304
+ /** Resolve a list of `pkg@version` installs to importmap entries via a provider. */
305
+ export declare function jspmGenerate(installs: string[], provider?: string): Promise<Record<string, string>>;
306
+ /** Pin every (or the named) bare imports to `.webjs/vendor/importmap.json`. */
307
+ export declare function pinAll(
308
+ appDir: string,
309
+ opts?: { download?: boolean; from?: string },
310
+ ): Promise<unknown>;
311
+ /** Remove a package from the pin file. */
312
+ export declare function unpinPackage(
313
+ appDir: string,
314
+ pkg: string,
315
+ ): Promise<{ removed: boolean; deletedFile?: string }>;
316
+ /** List the pinned packages. */
317
+ export declare function listPinned(
318
+ appDir: string,
319
+ ): Promise<Array<{ pkg: string; version: string; url: string; bytes?: number }>>;
320
+ /** Run npm security advisories against the pinned versions. */
321
+ export declare function auditPinned(appDir: string): Promise<unknown>;
322
+ /** List pinned packages that have a newer version available. */
323
+ export declare function findOutdated(appDir: string): Promise<unknown>;
324
+ /** Whether the app commits a `.webjs/vendor/importmap.json` pin file. */
325
+ export declare function hasVendorPin(appDir: string): boolean;
326
+ /** Re-pin every outdated package to its latest version. */
327
+ export declare function updatePinned(appDir: string, opts?: { from?: string }): Promise<unknown>;
328
+ /** Read + parse the committed pin file, or null when absent. */
329
+ export declare function readPinFile(
330
+ appDir: string,
331
+ ): Promise<{ imports: Record<string, string>; integrity?: Record<string, string>; provider?: string } | null>;
332
+ /** Serve a downloaded `/__webjs/vendor/*` bundle file (`--download` mode). */
333
+ export declare function serveDownloadedBundle(
334
+ appDir: string,
335
+ pathname: string,
336
+ ): Promise<Response | null>;
337
+ /** The set of supported CDN providers. */
338
+ export declare const SUPPORTED_PROVIDERS: Set<string>;
339
+ /** Normalize / validate a provider name. */
340
+ export declare function normalizeProvider(name: string): string;
341
+
342
+ // ---------------------------------------------------------------------------
343
+ // module-graph.js
344
+ // ---------------------------------------------------------------------------
345
+
346
+ /** Build the app's static import dependency graph. */
347
+ export declare function buildModuleGraph(appDir: string): Promise<unknown>;
348
+ /** Compute the transitive dependency set of a set of entry files (stops at `.server.*`). */
349
+ export declare function transitiveDeps(
350
+ graph: unknown,
351
+ entryFiles: string[],
352
+ appDir: string,
353
+ skip?: Set<string>,
354
+ ): string[];
355
+
356
+ // ---------------------------------------------------------------------------
357
+ // component-scanner.js
358
+ // ---------------------------------------------------------------------------
359
+
360
+ /** Scan the app for webjs component classes and their browser-visible URLs. */
361
+ export declare function scanComponents(
362
+ appDir: string,
363
+ ): Promise<Array<{ tag: string; className: string; moduleUrl: string; file: string }>>;
364
+ /** Register scanned components into the server-side registry. */
365
+ export declare function primeComponentRegistry(
366
+ appDir: string,
367
+ components?: Array<{ tag: string; className: string; moduleUrl: string; file: string }>,
368
+ ): Promise<{ count: number }>;
369
+ /** Extract `{ className, tag }` pairs from a component module's source. */
370
+ export declare function extractComponents(src: string): Array<{ className: string; tag: string }>;
371
+ /** Find component classes that no page / component imports (orphans). */
372
+ export declare function findOrphanComponents(
373
+ appDir: string,
374
+ ): Promise<Array<{ className: string; file: string }>>;
375
+
376
+ // ---------------------------------------------------------------------------
377
+ // context.js (per-request context helpers)
378
+ // ---------------------------------------------------------------------------
379
+
380
+ /** Read-only headers for the in-flight request. Throws outside a request scope. */
381
+ export declare function headers(): Headers;
382
+ /** Read-only cookie jar for the in-flight request. Throws outside a request scope. */
383
+ export declare function cookies(): {
384
+ get(name: string): string | undefined;
385
+ has(name: string): boolean;
386
+ entries(): [string, string][];
387
+ };
388
+ /** The raw `Request` for the in-flight scope, or null at module top-level. */
389
+ export declare function getRequest(): Request | null;
390
+ /** Run `fn` within a request scope. */
391
+ export declare function withRequest<T>(req: Request, fn: () => T): T;
392
+ /** The per-request CSP nonce (`''` when CSP is off). */
393
+ export declare function cspNonce(): string;
394
+ /** The per-request correlation id, or null outside a request scope. */
395
+ export declare function requestId(): string | null;
396
+
397
+ // ---------------------------------------------------------------------------
398
+ // logger.js
399
+ // ---------------------------------------------------------------------------
400
+
401
+ /** The default logger (JSON-shaped in prod, pretty in dev). */
402
+ export declare function defaultLogger(opts?: { dev?: boolean }): Logger;
403
+
404
+ // ---------------------------------------------------------------------------
405
+ // rate-limit.js
406
+ // ---------------------------------------------------------------------------
407
+
408
+ /** Build a rate-limit middleware `(req, next) => Response`. */
409
+ export declare function rateLimit(opts?: {
410
+ window?: number | string;
411
+ max?: number;
412
+ key?: string | ((req: Request) => string | Promise<string>);
413
+ message?: string;
414
+ store?: CacheStore;
415
+ trustProxy?: boolean;
416
+ }): Middleware;
417
+ /** Parse a window string (`'1m'`, `'30s'`) to milliseconds. */
418
+ export declare function parseWindow(w: number | string): number;
419
+ /** Resolve the client IP for a request (honoring proxy-trust posture). */
420
+ export declare function clientIp(req: Request, opts?: { trustProxy?: boolean }): string;
421
+ /** Stamp the socket remote address onto a request for `clientIp` to read. */
422
+ export declare function stampRemoteIp(req: Request, remoteAddress: string): void;
423
+
424
+ // ---------------------------------------------------------------------------
425
+ // cors.js
426
+ // ---------------------------------------------------------------------------
427
+
428
+ /** A single CORS origin rule. */
429
+ export type CorsOriginRule = string | RegExp | ((origin: string) => boolean);
430
+
431
+ /** Options for the `cors()` middleware factory. */
432
+ export interface CorsOptions {
433
+ origin?: '*' | true | CorsOriginRule | CorsOriginRule[];
434
+ credentials?: boolean;
435
+ methods?: string[] | string;
436
+ allowedHeaders?: string[] | string;
437
+ exposedHeaders?: string[] | string;
438
+ maxAge?: number;
439
+ }
440
+
441
+ /** Build a CORS middleware `(req, next) => Response`. */
442
+ export declare function cors(options?: CorsOptions): Middleware;
443
+ /** Resolve the allowed origin for a request given a policy (shared CORS core). */
444
+ export declare function resolveOrigin(
445
+ policy: CorsOptions['origin'],
446
+ origin: string | null,
447
+ credentials: boolean,
448
+ ): { value: string | null; dynamic: boolean };
449
+ /** Apply the resolved CORS headers to a `Headers` object. */
450
+ export declare function applyCorsHeaders(
451
+ headers: Headers,
452
+ resolved: { value: string | null; dynamic: boolean },
453
+ cfg: CorsOptions,
454
+ ): void;
455
+
456
+ // ---------------------------------------------------------------------------
457
+ // cache.js (pluggable store) + cache-fn.js (query caching)
458
+ // ---------------------------------------------------------------------------
459
+
460
+ /** In-memory LRU cache store (single-process). */
461
+ export declare function memoryStore(opts?: { maxSize?: number }): CacheStore;
462
+ /** Redis-backed cache store. */
463
+ export declare function redisStore(opts?: { url?: string }): CacheStore;
464
+ /** Get the default cache store (memory unless `setStore` was called). */
465
+ export declare function getStore(): CacheStore;
466
+ /** Set the default cache store (call at startup to switch to Redis). */
467
+ export declare function setStore(store: CacheStore): void;
468
+
469
+ /**
470
+ * Wrap an async function with TTL caching. Preserves the wrapped signature and
471
+ * adds an `invalidate()` member. `tags` (static `string[]` or a per-arg
472
+ * `(...args) => string[]`) enable `revalidateTag` cross-module eviction.
473
+ */
474
+ export declare function cache<T extends (...args: any[]) => Promise<any>>(
475
+ fn: T,
476
+ opts: {
477
+ key: string;
478
+ ttl?: number;
479
+ tags?: string[] | ((...args: Parameters<T>) => string[]);
480
+ },
481
+ ): T & { invalidate: () => Promise<void> };
482
+
483
+ // ---------------------------------------------------------------------------
484
+ // cache-tags.js (#242) + html-cache.js (#241): server cache invalidation
485
+ // ---------------------------------------------------------------------------
486
+
487
+ /** Evict every `cache()` entry tagged with `tag`. */
488
+ export declare function revalidateTag(tag: string): Promise<void>;
489
+ /** Evict every `cache()` entry tagged with any of `tags`. */
490
+ export declare function revalidateTags(tags: string[]): Promise<void>;
491
+ /** Evict the cached HTML for a path (the next request re-renders). */
492
+ export declare function revalidatePath(path: string): Promise<void>;
493
+ /** Evict all cached HTML (per-process generation bump). */
494
+ export declare function revalidateAll(): Promise<void>;
495
+
496
+ // ---------------------------------------------------------------------------
497
+ // session.js
498
+ // ---------------------------------------------------------------------------
499
+
500
+ /** The session storage adapter interface. */
501
+ export interface SessionStorage {
502
+ read(cookie: string): Promise<Session>;
503
+ save(session: Session): Promise<string | null>;
504
+ }
505
+
506
+ /** A per-request session: a typed key/value bag with flash + destroy. */
507
+ export declare class Session {
508
+ constructor(id: string | null, initial?: Record<string, unknown>);
509
+ readonly id: string | null;
510
+ readonly dirty: boolean;
511
+ readonly destroyed: boolean;
512
+ readonly deleteId: string | null;
513
+ readonly data: { data: Record<string, unknown>; flash: Record<string, unknown> };
514
+ get<T = unknown>(key: string): T | undefined;
515
+ set(key: string, value: unknown): void;
516
+ has(key: string): boolean;
517
+ unset(key: string): void;
518
+ /** Set a value readable once on the next request, then cleared. */
519
+ flash(key: string, value: unknown): void;
520
+ destroy(): void;
521
+ }
522
+
523
+ /** Session middleware factory. */
524
+ export declare function session(opts?: {
525
+ storage?: SessionStorage;
526
+ cookieName?: string;
527
+ secret?: string;
528
+ maxAge?: number;
529
+ path?: string;
530
+ httpOnly?: boolean;
531
+ secure?: boolean;
532
+ sameSite?: string;
533
+ }): Middleware;
534
+ /** Cookie-backed session storage. */
535
+ export declare function cookieSessionStorage(): SessionStorage;
536
+ /** Store-backed session storage. */
537
+ export declare function storeSessionStorage(opts?: Record<string, unknown>): SessionStorage;
538
+ /** Alias of `cookieSessionStorage`. */
539
+ export declare const cookieSession: typeof cookieSessionStorage;
540
+ /** Alias of `storeSessionStorage`. */
541
+ export declare const storeSession: typeof storeSessionStorage;
542
+ /** Read the session for a request (after the session middleware ran). */
543
+ export declare function getSession(req: Request): Session;
544
+
545
+ // ---------------------------------------------------------------------------
546
+ // broadcast.js
547
+ // ---------------------------------------------------------------------------
548
+
549
+ /** Broadcast data to all WebSocket clients connected to a route path. */
550
+ export declare function broadcast(
551
+ path: string,
552
+ data: string | Uint8Array,
553
+ opts?: { except?: unknown },
554
+ ): void;
555
+
556
+ // ---------------------------------------------------------------------------
557
+ // file-storage.js (#247)
558
+ // ---------------------------------------------------------------------------
559
+
560
+ /** A streaming handle returned by `FileStore.get` (body is a stream, never buffered). */
561
+ export interface StoredObjectHandle {
562
+ body: ReadableStream | import('node:stream').Readable;
563
+ size: number;
564
+ contentType: string;
565
+ }
566
+
567
+ /** The result of `FileStore.put`. */
568
+ export interface PutResult {
569
+ key: string;
570
+ size: number;
571
+ contentType: string;
572
+ }
573
+
574
+ /**
575
+ * The pluggable file-storage interface. `diskStore` is the local-disk default;
576
+ * an S3-compatible adapter is a drop-in (same web-standard object shapes).
577
+ */
578
+ export interface FileStore {
579
+ put(
580
+ key: string,
581
+ file: Blob | File | ReadableStream | Uint8Array,
582
+ opts?: { contentType?: string },
583
+ ): Promise<PutResult>;
584
+ get(key: string): Promise<StoredObjectHandle | null>;
585
+ delete(key: string): Promise<void>;
586
+ url(key: string): string;
587
+ has?(key: string): Promise<boolean>;
588
+ }
589
+
590
+ /** The default uploads directory (relative to cwd), gitignore-friendly. */
591
+ export declare const DEFAULT_UPLOAD_DIR: string;
592
+ /** Local-disk file store (the default adapter). Streams writes. */
593
+ export declare function diskStore(opts?: { dir?: string; baseUrl?: string }): FileStore;
594
+ /** Set the default file store (call at startup to use a custom dir or S3). */
595
+ export declare function setFileStore(store: FileStore): void;
596
+ /** Get the default file store (`diskStore` under `<cwd>/.webjs/uploads` unless set). */
597
+ export declare function getFileStore(): FileStore;
598
+ /** Generate a random, opaque, traversal-safe key, preserving a whitelisted extension. */
599
+ export declare function generateKey(filename?: string): string;
600
+ /** Validate a key and return the absolute path it resolves to (throws on traversal). */
601
+ export declare function assertSafeKey(dir: string, key: string): string;
602
+ /** Mint a signed, expiring URL for a stored object (HMAC-SHA256). */
603
+ export declare function signedUrl(
604
+ key: string,
605
+ opts: { secret: string; expiresIn?: number; base?: string },
606
+ ): string;
607
+ /** Verify a signed URL (or parsed params); constant-time, checks expiry + tamper. */
608
+ export declare function verifySignedUrl(
609
+ input: string | URL | URLSearchParams | { key?: string; exp?: string | number; sig?: string },
610
+ secret: string,
611
+ ): { valid: boolean; key: string | null; reason?: string };
612
+
613
+ // ---------------------------------------------------------------------------
614
+ // json.js
615
+ // ---------------------------------------------------------------------------
616
+
617
+ /** Content-negotiated JSON response (rich wire format when the client asks for it). */
618
+ export declare function json<T>(data: T, init?: ResponseInit): Promise<Response>;
619
+ /** Parse a request body (webjs rich format or plain JSON); enforces the body-size limit. */
620
+ export declare function readBody(req: Request): Promise<unknown>;
621
+
622
+ // ---------------------------------------------------------------------------
623
+ // sitemap.js (#276)
624
+ // ---------------------------------------------------------------------------
625
+
626
+ /** A `<urlset>` entry. */
627
+ export interface SitemapEntry {
628
+ url: string;
629
+ lastModified?: string | Date;
630
+ changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
631
+ priority?: number;
632
+ }
633
+ /** A `<sitemapindex>` child-sitemap entry. */
634
+ export interface SitemapIndexEntry {
635
+ url: string;
636
+ lastModified?: string | Date;
637
+ }
638
+ /** Serialize entries into a spec-valid `<urlset>` XML document. */
639
+ export declare function sitemap(entries: SitemapEntry[]): string;
640
+ /** Serialize child sitemaps into a `<sitemapindex>` XML document. */
641
+ export declare function sitemapIndex(sitemaps: SitemapIndexEntry[]): string;
642
+
643
+ // ---------------------------------------------------------------------------
644
+ // websocket.js
645
+ // ---------------------------------------------------------------------------
646
+
647
+ /** Attach WebSocket upgrade handling to an HTTP server (invokes a `route.{js,ts}` `WS` export). */
648
+ export declare function attachWebSocket(server: import('node:http').Server, app: RequestHandler): void;
649
+
650
+ // ---------------------------------------------------------------------------
651
+ // serializer.js
652
+ // ---------------------------------------------------------------------------
653
+
654
+ /** Get the active RPC wire serializer. */
655
+ export declare function getSerializer(): Serializer;
656
+ /** Replace the RPC wire serializer. */
657
+ export declare function setSerializer(serializer: Serializer): void;
658
+ /** The default rich-type serializer. */
659
+ export declare const defaultSerializer: Serializer;
660
+
661
+ // ---------------------------------------------------------------------------
662
+ // auth.js (NextAuth-style)
663
+ // ---------------------------------------------------------------------------
664
+
665
+ /** A provider config produced by `Credentials` / `Google` / `GitHub`. */
666
+ export interface ProviderConfig {
667
+ id: string;
668
+ [key: string]: unknown;
669
+ }
670
+
671
+ /** Auth configuration for `createAuth`. */
672
+ export interface AuthConfig {
673
+ providers: ProviderConfig[];
674
+ session?: { strategy?: 'jwt' | 'database'; maxAge?: number };
675
+ secret: string;
676
+ callbacks?: { session?: Function; jwt?: Function; signIn?: Function; redirect?: Function };
677
+ adapter?: { load?: Function; save?: Function; destroy?: Function };
678
+ pages?: { signIn?: string; signOut?: string; error?: string };
679
+ }
680
+
681
+ /** The auth system created by `createAuth`. */
682
+ export interface AuthInstance {
683
+ auth: (req?: Request) => Promise<{ user: Record<string, unknown> } | null>;
684
+ signIn: (
685
+ provider: string,
686
+ data?: Record<string, unknown>,
687
+ opts?: { redirectTo?: string; req?: Request },
688
+ ) => Promise<Response>;
689
+ signOut: (opts?: { redirectTo?: string; req?: Request }) => Promise<Response>;
690
+ handlers: { GET: (req: Request) => Promise<Response>; POST: (req: Request) => Promise<Response> };
691
+ }
692
+
693
+ /** Create the auth system. */
694
+ export declare function createAuth(config: AuthConfig): AuthInstance;
695
+ /** The credentials (email/password) provider. */
696
+ export declare function Credentials(opts: Record<string, unknown>): ProviderConfig;
697
+ /** The Google OAuth provider. */
698
+ export declare function Google(opts?: Record<string, unknown>): ProviderConfig;
699
+ /** The GitHub OAuth provider. */
700
+ export declare function GitHub(opts?: Record<string, unknown>): ProviderConfig;
701
+
702
+ // ---------------------------------------------------------------------------
703
+ // Re-export the core prop / metadata types so a server consumer can reach them
704
+ // from one place (they are the shapes server functions construct / consume).
705
+ // ---------------------------------------------------------------------------
706
+
707
+ export type { LayoutProps, PageProps, RouteHandlerContext };