UNPKG

@h3ravel/http

Version:

HTTP kernel, middleware pipeline, request/response classes for H3ravel.

393 lines (384 loc) 9.3 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { ApiResource: () => ApiResource, HttpContext: () => import_shared.HttpContext, HttpServiceProvider: () => HttpServiceProvider, JsonResource: () => JsonResource, LogRequests: () => LogRequests, Middleware: () => Middleware, Request: () => Request, Response: () => Response }); module.exports = __toCommonJS(src_exports); // src/Middleware.ts var Middleware = class { static { __name(this, "Middleware"); } }; // src/Request.ts var import_h3 = require("h3"); var import_support = require("@h3ravel/support"); var Request = class { static { __name(this, "Request"); } app; /** * Gets route parameters. * @returns An object containing route parameters. */ params; /** * Gets query parameters. * @returns An object containing query parameters. */ query; /** * Gets the request headers. * @returns An object containing request headers. */ headers; /** * The current H3 H3Event instance */ event; constructor(event, app) { this.app = app; this.event = event; this.query = (0, import_h3.getQuery)(this.event); this.params = (0, import_h3.getRouterParams)(this.event); this.headers = this.event.req.headers; } /** * Get all input data (query + body). */ async all() { let data = { ...(0, import_h3.getRouterParams)(this.event), ...(0, import_h3.getQuery)(this.event) }; if (this.event.req.method === "POST") { data = Object.assign({}, data, Object.fromEntries((await this.event.req.formData()).entries())); } else if (this.event.req.method === "PUT") { data = Object.fromEntries(Object.entries(await (0, import_h3.readBody)(this.event))); } return data; } /** * Get a single input field from query or body. */ async input(key, defaultValue) { const data = await this.all(); return data[key] ?? defaultValue; } getEvent(key) { return (0, import_support.safeDot)(this.event, key); } }; // src/Response.ts var import_support2 = require("@h3ravel/support"); var import_h32 = require("h3"); var Response = class { static { __name(this, "Response"); } app; /** * The current H3 H3Event instance */ event; statusCode = 200; headers = {}; constructor(event, app) { this.app = app; this.event = event; } /** * Set HTTP status code. */ setStatusCode(code) { this.statusCode = code; this.event.res.status = code; return this; } /** * Set a header. */ setHeader(name, value) { this.headers[name] = value; return this; } html(content) { this.applyHeaders(); return (0, import_h32.html)(this.event, content); } /** * Send a JSON response. */ json(data) { this.setHeader("content-type", "application/json; charset=utf-8"); this.applyHeaders(); return data; } /** * Send plain text. */ text(data) { this.setHeader("content-type", "text/plain; charset=utf-8"); this.applyHeaders(); return data; } /** * Redirect to another URL. */ redirect(url, status = 302) { this.setStatusCode(status); return (0, import_h32.redirect)(this.event, url, this.statusCode); } /** * Apply headers before sending response. */ applyHeaders() { Object.entries(this.headers).forEach(([key, value]) => { this.event.res.headers.set(key, value); }); } getEvent(key) { return (0, import_support2.safeDot)(this.event, key); } }; // src/Contracts/HttpContract.ts var import_shared = require("@h3ravel/shared"); // src/Middleware/LogRequests.ts var LogRequests = class extends Middleware { static { __name(this, "LogRequests"); } async handle({ request }, next) { const url = request.getEvent("url"); console.log(`[${request.getEvent("method")}] ${url.pathname + url.search}`); return next(); } }; // src/Providers/HttpServiceProvider.ts var import_h33 = require("h3"); var import_core = require("@h3ravel/core"); var HttpServiceProvider = class extends import_core.ServiceProvider { static { __name(this, "HttpServiceProvider"); } static priority = 998; register() { this.app.singleton("http.app", () => { return new import_h33.H3(); }); this.app.singleton("http.serve", () => import_h33.serve); } }; // src/Resources/JsonResource.ts var JsonResource = class { static { __name(this, "JsonResource"); } event; /** * The request instance */ request; /** * The response instance */ response; /** * The data to send to the client */ resource; /** * The final response data object */ body = { data: {} }; /** * Flag to track if response should be sent automatically */ shouldSend = false; /** * Flag to track if response has been sent */ responseSent = false; /** * @param req The request instance * @param res The response instance * @param rsc The data to send to the client */ constructor(event, rsc) { this.event = event; this.request = event.req; this.response = event.res; this.resource = rsc; for (const key of Object.keys(rsc)) { if (!(key in this)) { Object.defineProperty(this, key, { enumerable: true, configurable: true, get: () => this.resource[key], set: (value) => { this.resource[key] = value; } }); } } } /** * Return the data in the expected format * * @returns */ data() { return this.resource; } /** * Build the response object * @returns this */ json() { this.shouldSend = true; this.response.status = 200; const resource = this.data(); let data = Array.isArray(resource) ? [ ...resource ] : { ...resource }; if (typeof data.data !== "undefined") { data = data.data; } if (!Array.isArray(resource)) { delete data.pagination; } this.body = { data }; if (!Array.isArray(resource) && resource.pagination) { const meta = this.body.meta ?? {}; meta.pagination = resource.pagination; this.body.meta = meta; } if (this.resource.pagination && !this.body.meta?.pagination) { const meta = this.body.meta ?? {}; meta.pagination = this.resource.pagination; this.body.meta = meta; } return this; } /** * Add context data to the response object * @param data Context data * @returns this */ additional(data) { this.shouldSend = true; delete data.data; delete data.pagination; this.body = { ...this.body, ...data }; return this; } /** * Send the output to the client * @returns this */ send() { this.shouldSend = false; if (!this.responseSent) { this.#send(); } return this; } /** * Set the status code for this response * @param code Status code * @returns this */ status(code) { this.response.status = code; return this; } /** * Private method to send the response */ #send() { if (!this.responseSent) { this.event.context.this.response.json(this.body); this.responseSent = true; } } /** * Check if send should be triggered automatically */ checkSend() { if (this.shouldSend && !this.responseSent) { this.#send(); } } }; // src/Resources/ApiResource.ts function ApiResource(instance) { return new Proxy(instance, { get(target, prop, receiver) { const value = Reflect.get(target, prop, receiver); if (typeof value === "function") { if (prop === "json" || prop === "additional") { return (...args) => { const result = value.apply(target, args); setImmediate(() => target["checkSend"]()); return result; }; } else if (prop === "send") { return (...args) => { target["shouldSend"] = false; return value.apply(target, args); }; } } return value; } }); } __name(ApiResource, "ApiResource"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ApiResource, HttpContext, HttpServiceProvider, JsonResource, LogRequests, Middleware, Request, Response }); //# sourceMappingURL=index.cjs.map