UNPKG

@moostjs/event-http

Version:
297 lines (291 loc) 10.8 kB
import { Intercept, Resolve, TInterceptorPriority, defineInterceptorFn, defineMoostEventHandler, getMoostMate } from "moost"; import { attachHook } from "@wooksjs/event-core"; import { HttpError, WooksHttp, createHttpApp, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useSearchParams, useSetCookie, useSetCookies, useSetHeader, useStatus } from "@wooksjs/event-http"; import { useBody } from "@wooksjs/http-body"; import { createProvideRegistry } from "@prostojs/infact"; import { Server } from "http"; import { Server as Server$1 } from "https"; //#region packages/event-http/src/decorators/http-method.decorator.ts function HttpMethod(method, path) { return getMoostMate().decorate("handlers", { method, path, type: "HTTP" }, true); } const All = (path) => HttpMethod("*", path); const Get = (path) => HttpMethod("GET", path); const Post = (path) => HttpMethod("POST", path); const Put = (path) => HttpMethod("PUT", path); const Delete = (path) => HttpMethod("DELETE", path); const Patch = (path) => HttpMethod("PATCH", path); //#endregion //#region packages/event-http/src/decorators/resolve.decorator.ts const StatusHook = () => Resolve((metas, level) => { const hook = useStatus(); if (level === "PARAM") return hook; if (level === "PROP" && metas.instance && metas.key) { const initialValue = metas.instance[metas.key]; attachHook(metas.instance, { get: () => hook.value, set: (v) => hook.value = v }, metas.key); return typeof initialValue === "number" ? initialValue : 200; } }, "statusCode"); const HeaderHook = (name) => Resolve((metas, level) => { const hook = useSetHeader(name); if (level === "PARAM") return hook; if (level === "PROP" && metas.instance && metas.key) { const initialValue = metas.instance[metas.key]; attachHook(metas.instance, { get: () => hook.value, set: (v) => hook.value = v }, metas.key); return typeof initialValue === "string" ? initialValue : ""; } }, name); const CookieHook = (name) => Resolve((metas, level) => { const hook = useSetCookie(name); if (level === "PARAM") return hook; if (level === "PROP" && metas.instance && metas.key) { const initialValue = metas.instance[metas.key]; attachHook(metas.instance, { get: () => hook.value, set: (v) => hook.value = v }, metas.key); return typeof initialValue === "string" ? initialValue : ""; } }, name); const CookieAttrsHook = (name) => Resolve((metas, level) => { const hook = useSetCookie(name); if (level === "PARAM") return attachHook({}, { get: () => hook.attrs, set: (v) => hook.attrs = v }); if (level === "PROP" && metas.instance && metas.key) { const initialValue = metas.instance[metas.key]; attachHook(metas.instance, { get: () => hook.attrs, set: (v) => hook.attrs = v }, metas.key); return typeof initialValue === "object" ? initialValue : {}; } }, name); function Authorization(name) { return Resolve(() => { const auth = useAuthorization(); switch (name) { case "username": return auth.isBasic() ? auth.basicCredentials()?.username : undefined; case "password": return auth.isBasic() ? auth.basicCredentials()?.password : undefined; case "bearer": return auth.isBearer() ? auth.authorization : undefined; case "raw": return auth.authRawCredentials(); case "type": return auth.authType(); } }, "authorization"); } function Header(name) { return Resolve(() => { const headers = useHeaders(); return headers[name]; }, `header: ${name}`); } function Cookie(name) { return Resolve(() => useCookies().getCookie(name), `cookie: ${name}`); } function Query(name) { const isItem = !!name; const _name = isItem ? name : "Query"; return getMoostMate().apply(getMoostMate().decorate("paramSource", isItem ? "QUERY_ITEM" : "QUERY"), getMoostMate().decorate("paramName", _name), Resolve(() => { const { jsonSearchParams, urlSearchParams } = useSearchParams(); if (isItem) { const p = urlSearchParams(); const value = p.get(name); return value === null ? undefined : value; } const json = jsonSearchParams(); return Object.keys(json).length > 0 ? json : undefined; }, _name)); } function Url() { return Resolve(() => useRequest().url || "", "url"); } function Method() { return Resolve(() => useRequest().method, "http_method"); } function Req() { return Resolve(() => useRequest().rawRequest, "request"); } function Res(opts) { return Resolve(() => useResponse().rawResponse(opts), "response"); } function ReqId() { return Resolve(() => useRequest().reqId(), "reqId"); } function Ip(opts) { return Resolve(() => useRequest().getIp(opts), "ip"); } function IpList() { return Resolve(() => useRequest().getIpList(), "ipList"); } function Body() { return getMoostMate().apply(getMoostMate().decorate("paramSource", "BODY"), Resolve(() => useBody().parseBody(), "body")); } function RawBody() { return Resolve(() => useBody().rawBody(), "body"); } //#endregion //#region packages/event-http/src/decorators/set.decorator.ts const setHeaderInterceptor = (name, value, opts) => { const fn = (_before, after, onError) => { const h = useSetHeader(name); const status = useStatus(); const cb = () => { if ((!h.value || opts?.force) && (!opts?.status || opts.status === status.value)) h.value = value; }; if (opts?.when !== "error") after(cb); if (opts?.when === "always" || opts?.when === "error") onError(cb); }; fn.priority = TInterceptorPriority.AFTER_ALL; return fn; }; function SetHeader(...args) { return Intercept(setHeaderInterceptor(...args)); } const setCookieInterceptor = (name, value, attrs) => { const fn = (before, after) => { const { setCookie, getCookie } = useSetCookies(); after(() => { if (!getCookie(name)) setCookie(name, value, attrs); }); }; fn.priority = TInterceptorPriority.AFTER_ALL; return fn; }; function SetCookie(...args) { return Intercept(setCookieInterceptor(...args)); } const setStatusInterceptor = (code, opts) => defineInterceptorFn((before, after) => { const status = useStatus(); after(() => { if (!status.isDefined || opts?.force) status.value = code; }); }); function SetStatus(...args) { return Intercept(setStatusInterceptor(...args)); } //#endregion //#region packages/event-http/src/decorators/limits.decorator.ts const globalBodySizeLimit = (n) => defineInterceptorFn(() => { useRequest().setMaxInflated(n); }, TInterceptorPriority.BEFORE_ALL); const globalCompressedBodySizeLimit = (n) => defineInterceptorFn(() => { useRequest().setMaxCompressed(n); }, TInterceptorPriority.BEFORE_ALL); const globalBodyReadTimeoutMs = (n) => defineInterceptorFn(() => { useRequest().setReadTimeoutMs(n); }, TInterceptorPriority.BEFORE_ALL); const BodySizeLimit = (n) => Intercept(globalBodySizeLimit(n)); const CompressedBodySizeLimit = (n) => Intercept(globalCompressedBodySizeLimit(n)); const BodyReadTimeoutMs = (n) => Intercept(globalBodyReadTimeoutMs(n)); //#endregion //#region packages/event-http/src/event-http.ts function _define_property(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } const LOGGER_TITLE = "moost-http"; const CONTEXT_TYPE = "HTTP"; var MoostHttp = class { getHttpApp() { return this.httpApp; } getServerCb() { return this.httpApp.getServerCb(); } listen(port, hostname, backlog, listeningListener) { return this.httpApp.listen(port, hostname, backlog, listeningListener); } async onNotFound() { return defineMoostEventHandler({ loggerTitle: LOGGER_TITLE, getIterceptorHandler: () => this.moost?.getGlobalInterceptorHandler(), getControllerInstance: () => this.moost, callControllerMethod: () => new HttpError(404, "Resource Not Found"), targetPath: "", handlerType: "__SYSTEM__" })(); } onInit(moost) { this.moost = moost; } getProvideRegistry() { return createProvideRegistry([WooksHttp, () => this.getHttpApp()], ["WooksHttp", () => this.getHttpApp()], [Server, () => this.getHttpApp().getServer()], [Server$1, () => this.getHttpApp().getServer()]); } getLogger() { return this.getHttpApp().getLogger("[moost-http]"); } bindHandler(opts) { let fn; for (const handler of opts.handlers) { if (handler.type !== "HTTP") continue; const httpPath = handler.path; const path = typeof httpPath === "string" ? httpPath : typeof opts.method === "string" ? opts.method : ""; const targetPath = `${`${opts.prefix || ""}/${path}`.replace(/\/\/+/g, "/")}${path.endsWith("//") ? "/" : ""}`; fn = defineMoostEventHandler({ contextType: CONTEXT_TYPE, loggerTitle: LOGGER_TITLE, getIterceptorHandler: opts.getIterceptorHandler, getControllerInstance: opts.getInstance, controllerMethod: opts.method, resolveArgs: opts.resolveArgs, manualUnscope: true, hooks: { init: ({ unscope }) => { const { rawRequest } = useRequest(); rawRequest.on("end", unscope); } }, targetPath, handlerType: handler.type }); const routerBinding = this.httpApp.on(handler.method, targetPath, fn); const { getPath: pathBuilder } = routerBinding; const methodMeta = getMoostMate().read(opts.fakeInstance, opts.method) || {}; const id = methodMeta.id || opts.method; if (id) { const methods = this.pathBuilders[id] = this.pathBuilders[id] || {}; if (handler.method === "*") { methods.GET = pathBuilder; methods.PUT = pathBuilder; methods.PATCH = pathBuilder; methods.POST = pathBuilder; methods.DELETE = pathBuilder; } else methods[handler.method] = pathBuilder; } opts.logHandler(`${"\x1B[36m"}(${handler.method})${"\x1B[32m"}${targetPath}`); const args = routerBinding.getArgs(); const params = {}; args.forEach((a) => params[a] = `{${a}}`); opts.register(handler, routerBinding.getPath(params), args); } } constructor(httpApp) { _define_property(this, "name", "http"); _define_property(this, "httpApp", void 0); _define_property(this, "pathBuilders", {}); _define_property(this, "moost", void 0); if (httpApp && httpApp instanceof WooksHttp) this.httpApp = httpApp; else if (httpApp) this.httpApp = createHttpApp({ ...httpApp, onNotFound: this.onNotFound.bind(this) }); else this.httpApp = createHttpApp({ onNotFound: this.onNotFound.bind(this) }); } }; //#endregion export { All, Authorization, Body, BodyReadTimeoutMs, BodySizeLimit, CompressedBodySizeLimit, Cookie, CookieAttrsHook, CookieHook, Delete, Get, Header, HeaderHook, HttpError, HttpMethod, Ip, IpList, Method, MoostHttp, Patch, Post, Put, Query, RawBody, Req, ReqId, Res, SetCookie, SetHeader, SetStatus, StatusHook, Url, globalBodyReadTimeoutMs, globalBodySizeLimit, globalCompressedBodySizeLimit, useHttpContext };