UNPKG

@trifrost/core

Version:

Blazingly fast, runtime-agnostic server framework for modern edge and node environments

130 lines (129 loc) 5.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Sym_TriFrostMiddlewareCors = void 0; exports.Cors = Cors; const array_1 = require("@valkyriestudios/utils/array"); const boolean_1 = require("@valkyriestudios/utils/boolean"); const number_1 = require("@valkyriestudios/utils/number"); const object_1 = require("@valkyriestudios/utils/object"); const string_1 = require("@valkyriestudios/utils/string"); const constants_1 = require("../types/constants"); /* Specific symbol attached to cors mware to identify them by */ exports.Sym_TriFrostMiddlewareCors = Symbol('TriFrost.Middleware.Cors'); const METHODS = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'CONNECT', 'TRACE']; const METHODSSet = new Set(METHODS); /** * Cors defaults */ const CorsDefaults = { origin: '*', methods: ['GET', 'HEAD', 'POST'], headers: [], expose: [], credentials: false, }; /** * CORS - Cross Origin Resource Sharing * * @param {TriFrostCorsOptions} options - Options to apply * @param {TriFrostCorsConfig} config - Additional behavioral config * * @see origin - https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Origin * @see methods - https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Methods * @see headers - https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Headers * @see expose - https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Expose-Headers * @see credentials - https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Credentials * @see maxage - https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Max-Age */ function Cors(options = {}, config) { const use_defaults = !(0, boolean_1.isBoolean)(config?.use_defaults) ? true : config.use_defaults; const { origin, methods, headers, expose, credentials, maxage } = use_defaults === true ? { ...CorsDefaults, ...((0, object_1.isObject)(options) && options) } : (0, object_1.isObject)(options) ? options : {}; let originWhiteList = null; let originFn = null; const computed = { vary: 'Origin' }; /* Access-Control-Allow-Origin */ if ((0, string_1.isNeString)(origin)) { computed['access-control-allow-origin'] = origin; } else if ((0, array_1.isNeArray)(origin)) { originWhiteList = new Set(); for (let i = 0; i < origin.length; i++) { const val = origin[i]; if ((0, string_1.isNeString)(val)) originWhiteList.add(val.trim()); } if (!originWhiteList.size) throw new Error('TriFrostMiddleware@Cors: Invalid origin'); originFn = reqOrigin => { if (typeof reqOrigin === 'string' && originWhiteList.has(reqOrigin)) return reqOrigin; return null; }; } else if (typeof origin === 'function') { originFn = origin; } /* Access-Control-Allow-Methods */ if ((0, array_1.isNeArray)(methods)) { const normalized = new Set(); for (let i = 0; i < methods.length; i++) { const method = methods[i]; if (!METHODSSet.has(method)) throw new Error('TriFrostMiddleware@Cors: Invalid method "' + method + '"'); normalized.add(method); } computed['access-control-allow-methods'] = [...normalized].join(', '); } else if (methods === '*') { computed['access-control-allow-methods'] = '*'; } /* Access-Control-Allow-Headers */ if ((0, array_1.isNeArray)(headers)) { const normalized = new Set(); for (let i = 0; i < headers.length; i++) { const el = headers[i]; if (!(0, string_1.isNeString)(el)) throw new Error('TriFrostMiddleware@Cors: Invalid header "' + el + '"'); normalized.add(el.trim()); } computed['access-control-allow-headers'] = [...normalized.values()].join(', '); } /* Access-Control-Expose-Headers */ if ((0, array_1.isNeArray)(expose)) { const normalized = new Set(); for (let i = 0; i < expose.length; i++) { const el = expose[i]; if (!(0, string_1.isNeString)(el)) throw new Error('TriFrostMiddleware@Cors: Invalid expose "' + el + '"'); normalized.add(el.trim()); } computed['access-control-expose-headers'] = [...normalized.values()].join(', '); } /* Access-Control-Allow-Credentials */ if (credentials === true) { computed['access-control-allow-credentials'] = 'true'; } /* Access-Control-Max-Age */ if ((0, number_1.isIntGte)(maxage, 0)) { computed['access-control-max-age'] = `${maxage}`; } /* Baseline Middleware function */ const mware = function TriFrostCorsMiddleware(ctx) { /* Add computed headers */ ctx.setHeaders(computed); /* If origin is function we should check to see if we need to add it */ if (originFn) { const value = originFn(ctx.headers.origin ?? ctx.headers.Origin ?? null); if (value !== null) ctx.setHeader('access-control-allow-origin', value); } /* If it's an options call simply return a 204 status */ if (ctx.method === constants_1.HttpMethods.OPTIONS) return ctx.status(204); }; /* Add symbols for introspection/use further down the line */ Reflect.set(mware, constants_1.Sym_TriFrostName, 'TriFrostCors'); Reflect.set(mware, constants_1.Sym_TriFrostDescription, 'Middleware for Cross Origin Resource Sharing'); Reflect.set(mware, constants_1.Sym_TriFrostFingerPrint, exports.Sym_TriFrostMiddlewareCors); return mware; }