UNPKG

@mojojs/core

Version:

Real-time web framework

292 lines (291 loc) 9.55 kB
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 };