@mojojs/core
Version:
Real-time web framework
292 lines (291 loc) • 9.55 kB
TypeScript
import type { App } from './app.js';
import type { ChildLogger } from './logger.js';
import type { Plan } from './router/plan.js';
import type { ServerRequest } from './server/request.js';
import type { ServerResponse } from './server/response.js';
import type { BackendInfo, MojoAction, MojoModels, MojoRenderOptions, MojoURLOptions, ScopedNestedHelpers, SessionData, UploadOptions, ValidatorFunction } from './types.js';
import type { UserAgent } from './user-agent.js';
import type { WebSocket } from './websocket.js';
import type Path from '@mojojs/path';
import EventEmitter from 'node:events';
import { Params } from './body/params.js';
import { SafeString } from './util.js';
type WebSocketHandler = (ws: WebSocket) => void | Promise<void>;
interface ContextEvents {
connection: (ws: WebSocket) => void;
finish: () => void;
}
declare interface ContextEventEmitter {
on: <T extends keyof ContextEvents>(event: T, listener: ContextEvents[T]) => this;
emit: <T extends keyof ContextEvents>(event: T, ...args: Parameters<ContextEvents[T]>) => boolean;
}
/**
* Context class.
*/
declare class Context extends EventEmitter implements ContextEventEmitter {
/**
* Application this context belongs to.
*/
app: App;
/**
* Backend information for server that received the request.
* @example
* // Backend name (usually "server", "cgi", or "mock")
* const {name} = ctx.backend;
*
* // Use low level Node.js APIs with "server" backend
* const {res} = ctx.backend;
* res.writeHead(200);
* res.end('Hello World!');
*/
backend: BackendInfo;
/**
* Partial content. Always returns at least an empty string, even for sections that have not been defined with
* `ctx.contentFor()`.
* @example
* // Get content for "head" section
* const head = ctx.content.head;
*/
content: Record<string, string>;
/**
* Format for HTTP exceptions ("html", "json", or "txt").
*/
exceptionFormat: string;
/**
* WebSocket JSON mode.
*/
jsonMode: boolean;
/**
* Logger with request id.
* @example
* // Pass logger with context to model
* const log = ctx.log;
* ctx.model.users.create({name: 'kraih'}, log);
*/
log: ChildLogger;
/**
* Router dispatch plan.
*/
plan: Plan | null;
/**
* HTTP request information.
* @example
* // Extract request information
* const id = ctx.req.requestId;
* const method = ctx.req.method;
* const baseURL = ctx.req.baseURL;
* const url = ctx.req.url;
* const query = ctx.req.query;
* const info = ctx.req.userinfo;
* const agent = ctx.req.get('User-Agent');
* const buffer = await ctx.req.buffer();
* const text = await ctx.req.text();
* const form = await ctx.req.form();
* const value = await ctx.req.json();
* const html = await ctx.req.html();
* const xml = await ctx.req.xml();
*/
req: ServerRequest;
/**
* HTTP response information.
* @example
* // Force file download by setting a response header
* ctx.res.set('Content-Disposition', 'attachment; filename=foo.png;');
*
* // Make sure response is cached correctly
* ctx.res.set('Cache-Control', 'public, max-age=300');
* ctx.res.headers.append('Vary', 'Accept-Encoding');
*/
res: ServerResponse;
/**
* Non-persistent data storage and exchange for the current request.
*/
stash: Record<string, any>;
_flash: SessionData | undefined;
_nestedHelpersCache: Record<string, ScopedNestedHelpers>;
_params: Params | undefined;
_session: Record<string, any> | undefined;
_ws: WeakRef<WebSocket> | null;
constructor(app: App, req: ServerRequest, res: ServerResponse, backend: BackendInfo);
[EventEmitter.captureRejectionSymbol](error: Error): void;
/**
* Select best possible representation for resource.
*/
accepts(allowed?: string[]): string[] | null;
/**
* Application config shortcut.
* @example
* // Longer version
* const config = ctx.app.config;
*/
get config(): Record<string, any>;
/**
* Append partial content to `ctx.content` buffers.
* @example
* // Add content for "head" section
* await ctx.contentFor('head', '<link rel="icon" href="/static/favicon.ico">');
*/
contentFor(name: string, content: string | SafeString | Promise<string | SafeString> | (() => Promise<string | SafeString>)): Promise<void>;
/**
* Data storage persistent only for the next request.
* @example
* // Show message after redirect
* const flash = await ctx.flash();
* flash.message = 'User created successfully!';
* await ctx.redirectTo('show_user', {values: {id: 23}});
*/
flash(): Promise<Record<string, any>>;
/**
* Handle WebSocket upgrade, used by servers.
*/
handleUpgrade(ws: WebSocket): void;
/**
* Home directory shortcut.
* @example
* // Generate path
* const path = ctx.home.child('views', 'foo', 'bar.html.tmpl');
*/
get home(): Path;
/**
* Check if WebSocket connection has been accepted.
*/
get isAccepted(): boolean;
/**
* Check if WebSocket connection has been established.
*/
get isEstablished(): boolean;
/**
* Check if session is active.
*/
get isSessionActive(): boolean;
/**
* Check if HTTP request is a WebSocket handshake.
*/
get isWebSocket(): boolean;
/**
* Accept WebSocket connection and activate JSON mode.
* @example
* // Echo WebSocket messages
* ctx.json(async ws => {
* for await (const data of ws) {
* // Add a Futurama quote to JSON objects
* if (typeof data === 'object') {
* data.quote = 'Shut up and take my money!';
* await ws.send(data);
* }
* }
* });
*/
json(fn: WebSocketHandler): this;
/**
* Model shortcut.
* @example
* // Access arbitrary model objects
* const db = await ctx.models.pg.db();
*/
get models(): MojoModels;
/**
* GET and POST parameters.
* @example
* // Get a specific parameter
* const params = await ctx.params();
* const foo = params.get('foo');
*
* // Ignore all empty parameters
* const params = await ctx.params({notEmpty: true});
*/
params(options?: UploadOptions & {
notEmpty?: boolean;
}): Promise<Params>;
/**
* Accept WebSocket connection.
* @example
* // Echo incoming WebSocket messages
* ctx.plain(async ws => {
* for await (const message of ws) {
* await ws.send(`echo: ${message}`);
* }
* });
*/
plain(fn: WebSocketHandler): this;
/**
* Send `302` redirect response.
* @example
* // Moved Permanently
* await ctx.redirect_to('some_route', {status: 301});
*/
redirectTo(target: string, options?: MojoURLOptions & {
status?: number;
}): Promise<void>;
/**
* Render dynamic content.
* @example
* // Render text
* await ctx.render({text: 'Hello World!'});
*
* // Render JSON
* await ctx.render({json: {hello: 'world'}});
*
* // Render view "users/list.*.*" and pass it a stash value
* await ctx.render({view: 'users/list'}, {foo: 'bar'});
*/
render(options?: MojoRenderOptions, stash?: Record<string, any>): Promise<boolean>;
/**
* Try to render dynamic content to string.
*/
renderToString(options: MojoRenderOptions, stash?: Record<string, any>): Promise<string | null>;
/**
* Automatically select best possible representation for resource.
*/
respondTo(spec: Record<string, MojoAction | MojoRenderOptions>): Promise<void>;
/**
* Send static file.
*/
sendFile(file: Path): Promise<void>;
/**
* Get JSON schema validation function.
*/
schema(schema: Record<string, any> | string): ValidatorFunction;
/**
* Persistent data storage for the next few requests.
*/
session(): Promise<SessionData>;
/**
* HTTP/WebSocket user-agent shortcut.
*/
get ua(): UserAgent;
/**
* Generate URL for route or path.
* @example
* // Current URL with query parameter
* const url = ctx.urlFor('current', {query: {foo: 'bar'}});
*
* // URL for route with placeholder values
* const url = ctx.urlFor('users', {values: {id: 23}});
*
* // Absolute URL for path with fragment
* const url = ctx.urlFor('/some/path', {absolute: true, fragment: 'whatever'});
*/
urlFor(target?: string, options?: MojoURLOptions): string;
/**
* Generate URL for static asset.
*/
urlForAsset(path: string, options?: MojoURLOptions): string;
/**
* Generate URL for static file.
*/
urlForFile(path: string, options?: MojoURLOptions): string;
/**
* Generate URL for route or path and preserve the current query parameters.
* @example
* // Remove a specific query parameter
* const url = ctx.urlWith('current', {query: {foo: null}});
*/
urlWith(target?: string, options?: MojoURLOptions): string;
/**
* Established WebSocket connection.
*/
get ws(): WebSocket | null;
_urlForPath(path: string, isWebSocket: boolean, options: MojoURLOptions): string;
}
export { Context };