@buildplease/apikit 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import"reflect-metadata";import{Console as e,LogFlag as t,coreNodeAssembly as n,createDirectoryAsync as r,ensureDirectory as i,ensureDirectoryAsync as a,removePathAsync as o,resolvePath as s}from"@buildplease/core/node";import{ByteUnit as c,CoreL10nResource as l,CoreSymbols as u,defineL10n as ee,filterObject as te,ignoreError as d,ignoreErrorAsync as ne,isDefinedAndNotNull as re,isEmptyObject as ie,isNonEmptyString as ae,isNullOrEmpty as oe,isObject as se,isPlainObject as ce}from"@buildplease/core";import f,{existsSync as le}from"node:fs";import p from"node:path";import{createJiti as ue}from"jiti";import{inject as m,injectable as h,multiInject as de,optional as fe}from"inversify";import pe from"@dotenvx/dotenvx";import me from"node:fs/promises";import he from"ejs";import ge from"nodemailer";import _e from"node:os";import{Readable as ve}from"node:stream";import{pipeline as ye}from"node:stream/promises";import be from"mime-types";import xe from"lodash.merge";import Se from"i18next";import Ce,{fastifyCookie as we,default as Te}from"@fastify/cookie";import{AsyncLocalStorage as Ee}from"node:async_hooks";import De,{createHash as Oe,createHmac as ke,randomInt as Ae,timingSafeEqual as je}from"node:crypto";import{v4 as Me,v7 as Ne}from"uuid";import{PassThrough as Pe,Readable as Fe}from"stream";import{pipeline as Ie}from"stream/promises";import g from"sharp";import{parsePhoneNumberFromString as Le,parsePhoneNumberWithError as Re}from"libphonenumber-js";import _ from"validator";import*as ze from"argon2";import Be,{default as Ve}from"@fastify/basic-auth";import He,{default as v}from"fastify-plugin";import Ue,{default as We}from"@fastify/cors";import Ge,{default as Ke}from"@fastify/under-pressure";import qe,{default as Je}from"fastify-ip";import Ye,{default as Xe}from"fastify-metrics";import Ze,{default as Qe}from"@fastify/multipart";import $e,{default as et}from"@fastify/static";import tt,{default as nt}from"@fastify/view";import rt,{LogController as it}from"fastify";import{ZodError as at,z as ot}from"zod";export*from"@buildplease/core/node";export*from"@buildplease/core";const st=Symbol(`apikit.configuration.field`),y={string(){return b((e,t)=>{if(typeof e!=`string`)throw Error(`${t} must be string.`);let n=e.trim();if(!n)throw Error(`${t} must not be empty.`);return n},{required:!0})},number(){return b((e,t)=>{let n=typeof e==`number`?e:Number(e);if(!Number.isFinite(n))throw Error(`${t} must be number.`);return n},{required:!0})},boolean(){return b((e,t)=>{if(typeof e==`boolean`)return e;if(typeof e==`string`){let t=e.trim().toLowerCase();if(t===`true`)return!0;if(t===`false`)return!1}throw Error(`${t} must be boolean.`)},{required:!0})},array(e){return b((t,n)=>{if(!Array.isArray(t))throw Error(`${n} must be array.`);return t.map((t,r)=>e.parse(t,`${n}[${r}]`))},{required:!0})},custom(){return b(e=>e,{required:!0})}};function ct(e){return!!(e&&typeof e==`object`&&e[st]===!0)}function b(e,t){let n={required:t.required,hasDefault:t.hasDefault??!1,defaultValue:t.defaultValue,parse:e,optional(){return b((t,n)=>{if(t!=null)return e(t,n)},{required:!1})},default(t){return b(e,{required:!1,hasDefault:!0,defaultValue:t})},map(n){let r=t.hasDefault&&t.defaultValue!==void 0?n(t.defaultValue):void 0;return b((t,r)=>n(e(t,r)),{required:t.required,hasDefault:t.hasDefault,defaultValue:r})}};return Object.defineProperty(n,st,{value:!0}),n}const lt=Symbol(`apikit.configuration.contract`),ut=Symbol(`apikit.configuration.binding`);function x(e,t){let n=e.trim();if(!n)throw Error(`Configuration key must not be empty.`);let r=(e=>{let t={contract:r,input:e};return Object.defineProperty(t,ut,{value:!0}),t});return Object.defineProperties(r,{[lt]:{value:!0},key:{value:n},schema:{value:t}}),r}function dt(e){return!!(e&&typeof e==`object`&&e[ut]===!0)}function ft(e){let t=Object.entries(e);if(!t.length)throw Error(`At least one environment must be defined.`);for(let[e,n]of t)mt(e,n);return e}function pt(e,t,n={}){let r=e[t];if(!r)throw Error(`Environment "${t}" is not defined.`);return{name:t,file:r.file.trim(),fileDir:r.fileDir?.trim()||n.fileDir?.trim()||process.cwd()}}function mt(e,t){if(!e.trim())throw Error(`Environment name must not be empty.`);if(typeof t.file!=`string`||!t.file.trim())throw Error(`Environment file must not be empty for "${e}".`)}const ht=Symbol(`apikit.configuration.source`);function gt(e){return{env(e){return S(`env`,{name:e})},byEnvironment(e){return S(`by-environment`,{cases:e})},compute(e){return S(`compute`,{compute:e})},static(e){return S(`static`,{value:e})}}}function _t(e){return!!(e&&typeof e==`object`&&e[ht]===!0)}function S(e,t,n=[]){let r={kind:e,options:t,transforms:n,map(r){return S(e,t,[...n,r])}};return Object.defineProperty(r,ht,{value:!0}),r}const C={build:{outDir:`.apikit`},logger:{enabled:!1},server:{debug:!1,trustProxy:!1},metrics:{enabled:!1,endpoint:`/metrics`,name:`metrics`,defaultMetrics:{enabled:!0},routeMetrics:{enabled:!0},clearRegisterOnInit:!1},health:{enabled:!0,url:`/health`,pressure:{maxEventLoopDelay:0,maxHeapUsedBytes:0,maxRssBytes:0,maxEventLoopUtilization:0}},notification:{enabled:!1},email:{enabled:!1,templatesPath:`./src/templates`,globals:{}},i18n:{resources:{},directories:[],files:[],defaultLanguage:`en`,fallbackLanguages:`en`,supportedLanguages:[`en`,`sk`,`cs`],load:`languageOnly`,preload:[`en`,`sk`,`cs`],nonExplicitSupportedLngs:!0,lowerCaseLng:!0,cleanCode:!0,defaultNamespace:`translation`,keySeparator:`.`,nsSeparator:`:`,pluralSeparator:`_`,contextSeparator:`_`},staticFiles:{enabled:!1,routePrefix:`/`,maxAge:3600,dotfiles:`ignore`,etag:!0,immutable:!0,decorateReply:!0,preCompressed:!1},basicAuth:{enabled:!1,authenticate:!1,proxyMode:!1,header:void 0,strictCredentials:void 0},cors:{enabled:!1,allowAllOrigins:!1,includeWwwSubdomain:!0,options:{methods:[`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`OPTIONS`],credentials:!0,optionsSuccessStatus:200}},multipart:{enabled:!1,options:{limits:{fileSize:20971520}}}};async function vt(e,t){let n=p.resolve(e,t,`build-metadata.ts`);if(!f.existsSync(n))throw Error(`ApiKit build metadata "${n}" does not exist. Run "apikit build:app" first.`);return yt(await ue(e,{interopDefault:!1}).import(n,{try:!0}),n)}function yt(e,t){if(!bt(e)||!bt(e.BuildMetadata))throw Error(`ApiKit build metadata is missing (${t}).`);let n=e.BuildMetadata,r=n.name;if(!bt(r)||typeof r.original!=`string`||typeof r.base!=`string`||typeof n.version!=`string`||typeof n.id!=`string`||typeof n.createdAt!=`string`)throw Error(`ApiKit build metadata is invalid (${t}).`);return{name:{original:r.original,base:r.base},version:n.version,id:n.id,createdAt:n.createdAt}}function bt(e){return typeof e==`object`&&!!e}const xt=[`.ts`,`.mts`,`.cts`,`.js`,`.mjs`,`.cjs`,`.json`];async function St(e,t={}){let n=Ct(t.dir),r=wt(n,t.config??e.defaultName);try{let t=await Tt(n,r);return{config:e.validate(t,r),configFilePath:r,rootDir:n}}catch(t){throw Error(`Failed to load ${e.name} config: ${t instanceof Error?t.message:String(t)}`)}}function Ct(e){let t=e?s(process.cwd(),e):process.cwd();return i(t),t}function wt(e,t){let n=s(e,t);for(let e of xt){let t=`${n}${e}`;if(f.existsSync(t))return t}return n}async function Tt(e,t){return ue(e,{interopDefault:!0,extensions:[...xt],tsconfigPaths:!0}).import(t,{try:!0,default:!0})}async function Et(e={}){return St({name:`ApiKit`,defaultName:`apikit.config`,validate:Dt},e)}function Dt(e,t){if(!e||typeof e!=`object`)throw Error(`ApiKit config is missing (${t})`);return e}async function w(e,t,n={}){let r={buildMetadata:n.buildMetadata,environment:n.environment};return kt(e.schema,t,r,e.key)}async function Ot(e,t){return w(e.contract,e.input,t)}async function kt(e,t,n,r){if(ct(e))return At(e,t,n,r);let i=await T(t,n,r)??{};if(!i||typeof i!=`object`||Array.isArray(i))throw Error(`${r} must be object.`);let a={};for(let[t,o]of Object.entries(e))a[t]=await kt(o,i[t],n,`${r}.${t}`);return a}async function At(e,t,n,r){let i=await T(t,n,r);if(i==null){if(e.hasDefault)return Mt(e.defaultValue);if(!e.required)return;throw Error(`Missing required configuration: ${r}`)}return e.parse(i,r)}async function T(e,t,n){if(_t(e))return jt(e,t,n);if(dt(e))return Ot(e,t);if(Array.isArray(e))return Promise.all(e.map((e,r)=>T(e,t,`${n}[${r}]`)));if(e&&typeof e==`object`){let r={};for(let[i,a]of Object.entries(e))r[i]=await T(a,t,`${n}.${i}`);return r}return e}async function jt(e,t,n){let r;switch(e.kind){case`env`:{let{name:t}=e.options,n=process.env[t];r=typeof n==`string`&&n.trim()?n.trim():void 0;break}case`by-environment`:{if(!t.environment)throw Error(`${n} requires runtime environment.`);let{cases:i}=e.options;r=await T(i[t.environment.name],t,n);break}case`compute`:{if(!t.environment)throw Error(`${n} requires runtime environment.`);if(!t.buildMetadata)throw Error(`${n} requires build metadata.`);let{compute:i}=e.options;r=await i(t);break}case`static`:{let{value:t}=e.options;r=t;break}}for(let i of e.transforms){if(!t.environment)throw Error(`${n} source transforms require runtime environment.`);if(!t.buildMetadata)throw Error(`${n} source transforms require build metadata.`);r=await i(r,t)}return r}function Mt(e){if(Array.isArray(e))return e.map(e=>Mt(e));if(Nt(e)){let t={};for(let[n,r]of Object.entries(e))t[n]=Mt(r);return t}return e}function Nt(e){return Object.prototype.toString.call(e)===`[object Object]`}const Pt=x(`apikit.basic-auth`,{enabled:y.boolean().default(C.basicAuth.enabled),authenticate:y.custom().default(C.basicAuth.authenticate),proxyMode:y.boolean().default(C.basicAuth.proxyMode),header:y.string().optional().default(C.basicAuth.header),strictCredentials:y.boolean().optional().default(C.basicAuth.strictCredentials),username:y.string().optional(),password:y.string().optional()}),Ft=x(`apikit.build`,{outDir:y.string().default(C.build.outDir)}),It=x(`apikit.cors`,{enabled:y.boolean().default(C.cors.enabled),allowAllOrigins:y.boolean().default(C.cors.allowAllOrigins),includeWwwSubdomain:y.boolean().default(C.cors.includeWwwSubdomain),options:y.custom().default({}).map(Lt)});function Lt(e){return{...C.cors.options,...e}}const Rt=x(`apikit.email`,{enabled:y.boolean().default(C.email.enabled),templatesPath:y.string().default(C.email.templatesPath),globals:y.custom().default(C.email.globals),smtp:{host:y.string().optional(),port:y.number().optional(),secure:y.boolean().optional(),user:y.string().optional(),password:y.string().optional()}}),zt=x(`apikit.health`,{enabled:y.boolean().default(C.health.enabled),url:y.string().default(C.health.url).map(Bt),pressure:{maxEventLoopDelay:y.number().default(C.health.pressure.maxEventLoopDelay),maxHeapUsedBytes:y.number().default(C.health.pressure.maxHeapUsedBytes),maxRssBytes:y.number().default(C.health.pressure.maxRssBytes),maxEventLoopUtilization:y.number().default(C.health.pressure.maxEventLoopUtilization)}});function Bt(e){if(!e.startsWith(`/`))throw Error(`apikit.health.url must start with slash.`);if(e===`/`)throw Error(`apikit.health.url must not be root path.`);if(e.includes(`?`)||e.includes(`#`))throw Error(`apikit.health.url must not contain query string or fragment.`);return e.length>1?e.replace(/\/+$/,``):e}const Vt=x(`apikit.i18n`,{resources:y.custom().default(C.i18n.resources),directories:y.array(y.custom()).default(C.i18n.directories),files:y.array(y.custom()).default(C.i18n.files),defaultLanguage:y.string().default(C.i18n.defaultLanguage),fallbackLanguages:y.custom().default(C.i18n.fallbackLanguages),supportedLanguages:y.array(y.string()).default(C.i18n.supportedLanguages),load:y.custom().default(C.i18n.load),preload:y.custom().default(C.i18n.preload),nonExplicitSupportedLngs:y.boolean().default(C.i18n.nonExplicitSupportedLngs),lowerCaseLng:y.boolean().default(C.i18n.lowerCaseLng),cleanCode:y.boolean().default(C.i18n.cleanCode),namespaces:y.array(y.string()).optional(),defaultNamespace:y.string().default(C.i18n.defaultNamespace),keySeparator:y.string().default(C.i18n.keySeparator),nsSeparator:y.string().default(C.i18n.nsSeparator),pluralSeparator:y.string().default(C.i18n.pluralSeparator),contextSeparator:y.string().default(C.i18n.contextSeparator)}),Ht=x(`apikit.logger`,y.custom().default({enabled:C.logger.enabled}).map(Ut));function Ut(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.logger must be object.`);if(typeof e.enabled!=`boolean`)throw Error(`apikit.logger.enabled must be boolean.`);if(!e.enabled){if(`transports`in e&&e.transports!==void 0)throw Error(`apikit.logger.transports cannot be configured when logger is disabled.`);if(`request`in e&&e.request!==void 0)throw Error(`apikit.logger.request cannot be configured when logger is disabled.`);return{enabled:!1}}if(!Array.isArray(e.transports)||e.transports.length===0)throw Error(`apikit.logger.transports must be a non-empty array when logger is enabled.`);let t=Wt(e.request);return{enabled:!0,transports:e.transports,...t?{request:t}:{}}}function Wt(e){if(e!==void 0){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.logger.request must be object.`);if(e.ignoredPaths===void 0)return{};if(!Array.isArray(e.ignoredPaths))throw Error(`apikit.logger.request.ignoredPaths must be array.`);return{ignoredPaths:e.ignoredPaths.map((e,t)=>Gt(e,t))}}}function Gt(e,t){if(typeof e!=`string`)throw Error(`apikit.logger.request.ignoredPaths[${t}] must be string.`);let n=e.trim();if(!n)throw Error(`apikit.logger.request.ignoredPaths[${t}] must not be empty.`);if(!n.startsWith(`/`))throw Error(`apikit.logger.request.ignoredPaths[${t}] must start with slash.`);if(n===`/`)throw Error(`apikit.logger.request.ignoredPaths[${t}] must not be root path.`);if(n.includes(`?`)||n.includes(`#`))throw Error(`apikit.logger.request.ignoredPaths[${t}] must not contain query string or fragment.`);return n.length>1?n.replace(/\/+$/,``):n}const Kt=x(`apikit.metrics`,{enabled:y.boolean().default(C.metrics.enabled),endpoint:y.custom().default(C.metrics.endpoint),name:y.string().default(C.metrics.name),defaultMetrics:y.custom().default(C.metrics.defaultMetrics),routeMetrics:y.custom().default(C.metrics.routeMetrics),clearRegisterOnInit:y.boolean().default(C.metrics.clearRegisterOnInit)}),qt=x(`apikit.multipart`,{enabled:y.boolean().default(C.multipart.enabled),options:y.custom().default(C.multipart.options)}),Jt=x(`apikit.notification`,y.custom().default({enabled:C.notification.enabled}).map(Yt));function Yt(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.notification must be object.`);if(typeof e.enabled!=`boolean`)throw Error(`apikit.notification.enabled must be boolean.`);if(!e.enabled){if(`channels`in e&&e.channels!==void 0)throw Error(`apikit.notification.channels cannot be configured when notification is disabled.`);return{enabled:!1}}if(!e.channels||typeof e.channels!=`object`||Array.isArray(e.channels))throw Error(`apikit.notification.channels must be object when notification is enabled.`);Zt(e.channels);let t=Xt(e.channels.telegram);if(!t)throw Error(`apikit.notification.channels must contain at least one configured channel.`);return{enabled:!0,channels:{telegram:t}}}function Xt(e){if(e!==void 0){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.notification.channels.telegram must be object.`);return{token:Qt(e.token,`apikit.notification.channels.telegram.token`),chatId:Qt(e.chatId,`apikit.notification.channels.telegram.chatId`)}}}function Zt(e){for(let t of Object.keys(e))if(t!==`telegram`)throw Error(`apikit.notification.channels.${t} is not supported.`)}function Qt(e,t){if(typeof e!=`string`)throw Error(`${t} must be string.`);let n=e.trim();if(!n)throw Error(`${t} must not be empty.`);return n}const $t=x(`apikit.server`,{identifier:y.string(),debug:y.boolean().default(C.server.debug),host:y.string(),port:y.number(),trustProxy:y.custom().default(C.server.trustProxy)}),en=x(`apikit.staticFiles`,{enabled:y.boolean().default(C.staticFiles.enabled),publicDirectory:y.string().optional(),routePrefix:y.string().default(C.staticFiles.routePrefix),maxAge:y.number().default(C.staticFiles.maxAge),dotfiles:y.custom().default(C.staticFiles.dotfiles),etag:y.boolean().default(C.staticFiles.etag),immutable:y.boolean().default(C.staticFiles.immutable),decorateReply:y.boolean().default(C.staticFiles.decorateReply),preCompressed:y.boolean().default(C.staticFiles.preCompressed)});function E(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let D=class{get build(){return global.apikit.build}get isDebug(){return global.apikit.serverConfig.debug}get environment(){return global.apikit.environmentConfig}get logger(){return global.apikit.loggerConfig}get server(){return global.apikit.serverConfig}get metrics(){return global.apikit.metricsConfig}get health(){return global.apikit.healthConfig}get email(){return global.apikit.emailConfig}get notification(){return global.apikit.notificationConfig}get i18n(){return global.apikit.i18nConfig}get staticFiles(){return global.apikit.staticFilesConfig}get basicAuth(){return global.apikit.basicAuthConfig}get cors(){return global.apikit.corsConfig}get multipart(){return global.apikit.multipartConfig}get(e){if(!global.apikit.configurations.has(e.key))throw Error(`Configuration "${e.key}" is missing.`);return global.apikit.configurations.get(e.key)}optional(e){return global.apikit.configurations.get(e.key)}};D=E([h()],D);function tn(e,t){return{...t,environments:e,configurations:t.configurations??[]}}const nn=new e;async function rn(e){let t=await Et({config:e.config}),n=await w(Ft,t.config.build),r=await vt(t.rootDir,n.outDir),i=pt(t.config.environments,e.environment,{fileDir:t.rootDir});sn(i);let a={buildMetadata:r,environment:i},o=await an(t.config,a);global.apikit={build:r,environmentConfig:i,...o},nn.success(`[ApiKit] Context created for ${i.name} environment`)}async function an(e,t){return{serverConfig:await w($t,e.server,t),loggerConfig:await w(Ht,e.logger,t),metricsConfig:await w(Kt,e.metrics,t),healthConfig:await w(zt,e.health,t),emailConfig:await w(Rt,e.email,t),notificationConfig:await w(Jt,e.notification,t),i18nConfig:await w(Vt,e.i18n,t),staticFilesConfig:await w(en,e.staticFiles,t),basicAuthConfig:await w(Pt,e.basicAuth,t),corsConfig:await w(It,e.cors,t),multipartConfig:await w(qt,e.multipart,t),configurations:await on(e.configurations,t)}}async function on(e,t){let n=new Map;for(let r of e){if(r.contract.key.startsWith(`apikit.`))throw Error(`Configuration key "${r.contract.key}" is reserved for ApiKit.`);if(n.has(r.contract.key))throw Error(`Configuration "${r.contract.key}" is registered more than once.`);n.set(r.contract.key,await Ot(r,t))}return n}function sn(e){let t=p.resolve(e.fileDir,e.file);if(!f.existsSync(t))throw Error(`Environment file "${t}" does not exist.`);pe.config({path:t}),process.env.NODE_ENV=e.name}const cn={name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`},O=`${cn.name}.ApiKit.DI`,k={DI:{Configuration:{Controller:Symbol.for(`${O}.Configuration.Controller`)},Database:{MongoDB:{QueryFormatter:Symbol.for(`${O}.Database.MongoDB.QueryFormatter`)}},Email:{Controller:Symbol.for(`${O}.Email.Controller`)},File:{TemporaryRepository:Symbol.for(`${O}.File.TemporaryRepository`)},Validation:{Controller:Symbol.for(`${O}.Validation.Controller`),DtoController:Symbol.for(`${O}.Validation.DtoController`)},OpenAPI:{SchemaController:Symbol.for(`${O}.OpenAPI.SchemaController`)},I18n:{Controller:Symbol.for(`${O}.I18n.Controller`)},Notification:{Controller:Symbol.for(`${O}.Notification.Controller`)},Normalization:{Controller:Symbol.for(`${O}.Normalization.Controller`)},Formatter:{Controller:Symbol.for(`${O}.Formatter.Controller`),MultipartController:Symbol.for(`${O}.Formatter.MultipartController`)},Generator:{RandomValueGenerator:Symbol.for(`${O}.Generator.RandomValueGenerator`)},Image:{NormalizationController:Symbol.for(`${O}.Image.NormalizationController`)},Server:{Controller:Symbol.for(`${O}.Server.Controller`),RequestController:Symbol.for(`${O}.Server.RequestController`),ResponseController:Symbol.for(`${O}.Server.ResponseController`)},Security:{CryptographyController:Symbol.for(`${O}.Security.CryptographyController`)}}};var ln=class{assemble(e){e.bind(k.DI.Configuration.Controller).to(D).inSingletonScope()}};let A=class{format(e){return this.flattenRecursive(e,``)}flattenRecursive(e,t){let n={};for(let r of Object.keys(e)){let i=e[r];if(i===void 0||this.isPlainObject(i)&&Object.keys(i).length===0)continue;if(this.isOperator(r)){n[r]=this.processOperator(r,i);continue}let a=t?`${t}.${r}`:r;this.isPlainObject(i)?this.containsOperator(i)?n[a]={...i}:Object.assign(n,this.flattenRecursive(i,a)):n[a]=i}return n}isOperator(e){return e.startsWith(`$`)}containsOperator(e){return Object.keys(e).some(e=>this.isOperator(e))}isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype}processOperator(e,t){return e===`$expr`?t:Array.isArray(t)?t.map(e=>this.flattenRecursive(e,``)):this.isPlainObject(t)?this.flattenRecursive(t,``):t}};A=E([h()],A);var un=class{assemble(e){e.bind(k.DI.Database.MongoDB.QueryFormatter).to(A)}};function j(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function M(e,t){return function(n,r){t(n,r,e)}}const N=`[Email]`;let P=class{configuration;logger;transporter;templatesPath;isEnabled;smtpConfig;constructor(e,t){this.configuration=e,this.logger=t,this.isEnabled=this.configuration.email.enabled,this.smtpConfig=dn(this.configuration.email),this.templatesPath=fn(this.configuration.email.templatesPath)}async sendEmail(e){try{if(!this.isEnabled){this.logger.debug(`${N} Sending skipped — disabled`);return}let t=this.getOrCreateTransporter(),n=await this.renderTemplate(e),r={to:e.recipient,from:e.sender,subject:e.subject,html:n,...e.replyTo===void 0?{}:{replyTo:e.replyTo}};await t.sendMail(r)}catch(e){throw this.logger.error(`${N} Send failed`,{error:e}),e}}getOrCreateTransporter(){return this.transporter||=ge.createTransport({host:this.smtpConfig.host,port:this.smtpConfig.port,secure:this.smtpConfig.secure,auth:{user:this.smtpConfig.user,pass:this.smtpConfig.pass}}),this.transporter}async renderTemplate(e){try{let t=this.makeFilePath(e.templatePath,e.fallbackPath),n=await me.readFile(t,`utf-8`),r={globals:this.makeGlobals(),...e.data};return he.render(n,r)}catch(e){throw this.logger.error(`${N} Render failed`,{error:e}),e}}makeFilePath(e,t){let n=p.join(this.templatesPath,this.sanitizeTemplatePath(e));if(le(n))return n;if(t){let e=p.join(this.templatesPath,this.sanitizeTemplatePath(t));if(le(e))return e}throw Error(`${N} Template not found: ${n}${t?` or ${t}`:``}`)}makeGlobals(){let e=this.configuration.email.globals;return{generatedDate:new Date().toISOString().replace(`T`,` `).substring(0,16)+` UTC`,...e}}sanitizeTemplatePath(e){if(e.includes(`..`))throw Error(`${N} Invalid template path: ${e}`);let t=e.replace(/^\/+/,``);return t.endsWith(`.ejs`)?t:`${t}.ejs`}};P=E([h(),M(0,m(k.DI.Configuration.Controller)),M(1,m(u.DI.Logger)),j(`design:paramtypes`,[Object,Object])],P);function dn(e){if(!e.enabled)return{host:``,port:0,secure:!1,user:``,pass:``};let t=e.smtp;if(!t.host)throw Error(`${N} email.smtp.host is required when email is enabled`);if(!t.port)throw Error(`${N} email.smtp.port is required when email is enabled`);if(t.secure===void 0)throw Error(`${N} email.smtp.secure is required when email is enabled`);if(!t.user)throw Error(`${N} email.smtp.user is required when email is enabled`);if(!t.password)throw Error(`${N} email.smtp.password is required when email is enabled`);if(!Number.isInteger(t.port)||t.port<=0)throw Error(`${N} email.smtp.port must be a positive integer`);return{host:t.host,port:t.port,secure:t.secure,user:t.user,pass:t.password}}function fn(e){let t=e.trim();return p.isAbsolute(t)?p.normalize(t):p.resolve(process.cwd(),t)}var pn=class{data;recipient;sender;subject;replyTo;constructor(e){this.data=e.data,this.recipient=e.recipient,this.sender=e.sender??this.defaultSender(),this.subject=e.subject??this.defaultSubject(),e.replyTo!==void 0&&(this.replyTo=e.replyTo)}get fallbackPath(){}},mn=class{assemble(e){e.bind(k.DI.Email.Controller).to(P).inSingletonScope()}};const F=`[ApiKit:TemporaryFile]`;let I=class{logger;rootDir;constructor(e){this.logger=e,this.rootDir=_e.tmpdir()}get rootDirectory(){return this.rootDir}async createDirectory(e){let t=this.safeJoin(e);try{return await r(t)}catch(e){throw this.logger.error(`${F} Create directory failed`,{error:e,details:{abs:t}}),e}}async deleteDirectory(e){let t=this.safeJoin(e);try{await o(t,{recursive:!0,force:!0})}catch(e){throw this.logger.error(`${F} Delete directory failed`,{error:e,details:{abs:t}}),e}}async save(e,t,n,i){let o=this.safeJoin(i),s=p.join(o,`${e}.${n.extension}`);try{if(await r(o),await a(o),Buffer.isBuffer(t))return await f.promises.writeFile(s,t),s;if(t instanceof ve){let e=f.createWriteStream(s);try{return await ye(t,e),s}finally{e.close()}}let e=Error(`Unsupported content type: expected Buffer or Readable.`);throw this.logger.error(`${F} Save unsupported content`,{error:e,details:{fileAbs:s,typeof:typeof t}}),e}catch(t){throw this.logger.error(`${F} Save failed`,{error:t,details:{fileAbs:s,relativeDirectory:i,filename:e,extension:n.extension}}),t}}async delete(e){let t=this.safeJoin(e);try{await o(t,{recursive:!1,force:!0})}catch(e){throw this.logger.error(`${F} Delete failed`,{error:e,details:{abs:t}}),e}}safeJoin(e){let t=p.resolve(this.rootDir,e),n=this.rootDir.endsWith(p.sep)?this.rootDir:this.rootDir+p.sep;if(!t.startsWith(n)&&t!==this.rootDir){let n=Error(`Path escapes repository root: "${e}"`);throw this.logger.error(`${F} Path traversal attempt`,{error:n,details:{root:this.rootDir,attempted:t}}),n}return t}};I=E([h(),M(0,m(u.DI.Logger)),j(`design:paramtypes`,[Object])],I);var hn=class{assemble(e){e.bind(k.DI.File.TemporaryRepository).to(I)}},L=class e extends Error{_code;_statusCode;_details;constructor({code:t,message:n,statusCode:r,details:i}){super(n),this._code=t,this._statusCode=r,this._details=i,Error.captureStackTrace&&Error.captureStackTrace(this,e),Object.setPrototypeOf(this,e.prototype)}get code(){return this._code}get statusCode(){return this._statusCode}get details(){return this._details}toJSON(){let e={code:this._code,message:this.message,details:this.formatDetails(this.details)};return te(e,{filterNull:!0,filterUndefined:!0,filterEmptyString:!0,filterEmptyObject:!0})}formatDetails(e){if(e!=null)return typeof e==`string`?{_error:[e]}:Array.isArray(e)&&e.every(e=>typeof e==`string`)?{_errors:e}:e}};function R(e){return typeof e==`object`&&!!e&&`message`in e&&typeof e.message==`string`&&`code`in e&&typeof e.code==`string`&&`statusCode`in e&&typeof e.statusCode==`number`}const z=l.extend({resources:{en:{apikit:{errors:{common:{not_found:`The requested resource was not found`,unable_to_process_request:`We’re unable to process your request.`,unknown_error:`An unknown error occurred. Please try again later.`,already_exists:`The resource already exists`},server:{internal:`An internal server error occurred`,unavailable:`The service is temporarily unavailable. Try again later`,dependency_failed:`An external service or dependency failed`,timeout:`The server did not respond in time`},limit:{too_many_requests:`Too many requests. Try again later`},auth:{unauthorized:`You are not authorized to perform this action`,forbidden:`You do not have access to this resource`},validation:{bad_request:`The request is malformed or invalid`,invalid_json_syntax:`Invalid JSON syntax`,invalid_properties:`Some of the provided values are invalid`,invalid_format:`Invalid format`,invalid_date_format:`The date format is incorrect`,invalid_password:`The password you entered is incorrect`,invalid_password_new_same_as_old:`The new password must be different from the current one`,invalid_phone_number_format:`Invalid phone number format`,invalid_phone_new_same_as_old:`TThe new phone number must be different from the old one`,invalid_email_format:`Invalid email format`,invalid_email_new_same_as_old:`The new email must be different from the current one`},format:{unsupported:`Unsupported format`,max_size_exceeded:`Payload is too large.`},image:{max_size_exceeded:`Image is too large. Maximum allowed size is {{specs.maxSize}} {{specs.unit}}.`}}}},sk:{apikit:{errors:{common:{not_found:`Požadovaný zdroj sa nenašiel`,unable_to_process_request:`Vašu požiadavku sa nepodarilo spracovať.`,unknown_error:`Vyskytla sa neznáma chyba. Skúste to prosím znova neskôr.`,already_exists:`Zdroj už existuje`},server:{internal:`Vyskytla sa interná chyba servera`,unavailable:`Služba je momentálne nedostupná. Skúste to neskôr`,dependency_failed:`Zlyhala externá služba alebo závislosť`,timeout:`Server neodpovedal v stanovenom čase`},limit:{too_many_requests:`Príliš veľa požiadaviek. Skúste to neskôr`},auth:{unauthorized:`Nemáte oprávnenie na vykonanie tejto akcie`,forbidden:`K tomuto zdroju nemáte prístup`},validation:{bad_request:`Požiadavka je neplatná alebo nesprávna`,invalid_json_syntax:`Neplatná syntax JSON`,invalid_properties:`Niektoré z poskytnutých hodnôt sú neplatné`,invalid_format:`Neplatný formát`,invalid_date_format:`Formát dátumu je nesprávny`,invalid_password:`Zadané heslo je nesprávne`,invalid_password_new_same_as_old:`Nové heslo sa musí líšiť od aktuálneho`,invalid_phone_number_format:`Neplatný formát telefónneho čísla`,invalid_phone_new_same_as_old:`Nové telefónne číslo sa musí líšiť od pôvodného`,invalid_email_format:`Neplatný formát e-mailu`,invalid_email_new_same_as_old:`Nový e-mail sa musí líšiť od aktuálneho`},format:{unsupported:`Nepodporovaný formát`,max_size_exceeded:`Súbor je príliš veľký.`},image:{max_size_exceeded:`Obrázok je príliš veľký. Maximálna povolená veľkosť je {{specs.maxSize}} {{specs.unit}}.`}}}},cs:{apikit:{errors:{common:{not_found:`Požadovaný zdroj nebyl nalezen`,unable_to_process_request:`Vaši žádost se nepodařilo zpracovat.`,unknown_error:`Došlo k neznámé chybě. Zkuste to prosím později.`,already_exists:`Zdroj již existuje`},server:{internal:`Došlo k interní chybě serveru`,unavailable:`Služba je momentálně nedostupná. Zkuste to později`,dependency_failed:`Selhala externí služba nebo závislost`,timeout:`Server neodpověděl včas`},limit:{too_many_requests:`Příliš mnoho požadavků. Zkuste to později`},auth:{unauthorized:`Nemáte oprávnění k provedení této akce`,forbidden:`K tomuto zdroji nemáte přístup`},validation:{bad_request:`Požadavek je neplatný nebo nesprávný`,invalid_json_syntax:`Neplatná syntaxe JSON`,invalid_properties:`Některé z poskytnutých hodnot jsou neplatné`,invalid_format:`Neplatný formát`,invalid_date_format:`Formát data je nesprávný`,invalid_password:`Zadané heslo je nesprávné`,invalid_password_new_same_as_old:`Nové heslo se musí lišit od aktuálního`,invalid_phone_number_format:`Neplatný formát telefonního čísla`,invalid_phone_new_same_as_old:`Nové telefonní číslo se musí lišit od původního`,invalid_email_format:`Neplatný formát e-mailu`,invalid_email_new_same_as_old:`Nový e-mail se musí lišit od aktuálního`},format:{unsupported:`Nepodporovaný formát`,max_size_exceeded:`Soubor je příliš velký.`},image:{max_size_exceeded:`Obrázek je příliš velký. Maximální povolená velikost je {{specs.maxSize}} {{specs.unit}}.`}}}}}}),B=ee(z);function gn(e){return(e??``).toLowerCase().replace(/_/g,`-`).trim()}function _n(e){let[t,n]=e.split(`-`);return{base:t||``,region:n}}let V=class{configurationController;constructor(e){this.configurationController=e}async prepare(){let e=this.makeOptions();await Se.init(e)}parseLocale(e,t={}){let{supportedLanguages:n,defaultLanguage:r}=this.makeConfig(),{ignoreRegion:i=!0}=t;if(!e||!e.trim())return r;let a=new Set(n.map(e=>e.toLowerCase())),o,s,c=0;for(let t of e.split(`,`)){let e=t.trim();if(!e){c++;continue}let n=e.split(`;`),r=gn(n[0]??``);if(!r||r===`*`){c++;continue}let l=Tn(n.find(e=>e.startsWith(`q=`)));if(l===0){c++;continue}let{base:u}=_n(r);if(!u){c++;continue}!i&&a.has(r)&&(!o||l>o.q||l===o.q&&c<o.idx)&&(o={code:r,q:l,idx:c}),a.has(u)&&(!s||l>s.q||l===s.q&&c<s.idx)&&(s={code:u,q:l,idx:c}),c++}return o?o.code:s?s.code:r}makeOptions(){let e=this.makeConfig(),t=vn(e);return{debug:!1,lng:e.defaultLanguage,fallbackLng:e.fallbackLanguages,supportedLngs:e.supportedLanguages,load:e.load,nonExplicitSupportedLngs:e.nonExplicitSupportedLngs,preload:e.preload,lowerCaseLng:e.lowerCaseLng,cleanCode:e.cleanCode,ns:e.namespaces,defaultNS:e.defaultNamespace,keySeparator:e.keySeparator,nsSeparator:e.nsSeparator,pluralSeparator:e.pluralSeparator,contextSeparator:e.contextSeparator,resources:t}}makeConfig(){let e=this.configurationController.i18n??{},t=e.defaultNamespace??`translation`,n=e.defaultLanguage??`en`,r=e.fallbackLanguages??n,i=(e.directories??[]).map(e=>({path:e.path,namespace:e.namespace??t})),a=(e.files??[]).map(e=>({locale:e.locale,path:e.path,namespace:e.namespace??t})),o=this.makeNamespaces(e.namespaces,t,i,a);return{resources:e.resources??{},directories:i,files:a,defaultLanguage:n,fallbackLanguages:r,supportedLanguages:e.supportedLanguages??[`en`,`sk`,`cs`],load:e.load??`languageOnly`,nonExplicitSupportedLngs:e.nonExplicitSupportedLngs??!0,preload:e.preload??!1,lowerCaseLng:e.lowerCaseLng??!0,cleanCode:e.cleanCode??!0,namespaces:o,defaultNamespace:t,keySeparator:e.keySeparator??`.`,nsSeparator:e.nsSeparator??`:`,pluralSeparator:e.pluralSeparator??`_`,contextSeparator:e.contextSeparator??`_`}}makeNamespaces(e,t,n,r){let i=Array.isArray(e)?e.filter(e=>typeof e==`string`):typeof e==`string`?[e]:[],a=new Set(i.length?i:[t]);for(let e of n)a.add(e.namespace);for(let e of r)a.add(e.namespace);return Array.from(a)}};V=E([h(),M(0,m(k.DI.Configuration.Controller)),j(`design:paramtypes`,[Object])],V);function vn(e){let t=bn(e);yn(t,e);let n=[...Sn(e),...Cn(e)];for(let{locale:e,ns:r,path:i}of n){let n=t[e]||={},a=JSON.parse(f.readFileSync(i,`utf-8`));n[r]=xe(n[r]||{},a)}return t}function yn(e,t){for(let n of Object.keys(t.resources).sort()){let r=t.resources[n];if(!r)continue;let i=e[n]||={};i[t.defaultNamespace]=xe(i[t.defaultNamespace]||{},r)}}function bn(e){let t={};for(let n of Object.keys(z.resources).sort()){let r=t[n]||={};r[e.defaultNamespace]=xn(z.resources[n])}return t}function xn(e){return JSON.parse(JSON.stringify(e))}function Sn(e){let t=[];for(let n of e.directories){let e=wn(s(process.cwd(),n.path));for(let r of e)t.push({locale:r.locale,ns:n.namespace,path:r.path})}return t}function Cn(e){return e.files.map(e=>({locale:e.locale,ns:e.namespace,path:s(process.cwd(),e.path)}))}function wn(e){let t=i(e),n=f.readdirSync(t).filter(e=>e.endsWith(`.json`)).sort();if(!n.length)throw Error(`[ApiKit:I18n] No .json files in ${t}`);return n.map(e=>({locale:e.replace(/\.json$/,``),path:s(t,e)}))}function Tn(e){if(!e)return 1;let t=parseFloat(e.slice(2).replace(`,`,`.`));return Number.isFinite(t)?Math.max(0,Math.min(1,t)):1}var En=class{_name;_value;_options;constructor(e,t,n={}){this._name=e,this._value=t,this._options={...n}}get name(){return this._name}get value(){return this._value}get options(){return{...this._options}}mutate(e){return e.name!==void 0&&(this._name=e.name),e.value!==void 0&&(this._value=e.value),e.options!==void 0&&(this._options={...this._options,...e.options}),this}serialize(){return we.serialize(this._name,this._value,this._options)}toString(){return this.serialize()}};const H={accept:`accept`,acceptLanguage:`accept-language`,authorization:`authorization`,cacheControl:`cache-control`,contentType:`content-type`,cookie:`cookie`,setCookie:`set-cookie`,userAgent:`user-agent`};let Dn=function(e){return e.POST=`POST`,e.PUT=`PUT`,e.PATCH=`PATCH`,e.GET=`GET`,e.DELETE=`DELETE`,e.OPTIONS=`OPTIONS`,e}({}),On=function(e){return e.JSON=`JSON`,e.File=`File`,e}({});var kn=class{statusCode;headers;constructor({statusCode:e,headers:t}){this.statusCode=e,this.headers=t}},An=class extends kn{data;responseType=`JSON`;constructor({statusCode:e,data:t,headers:n}){super({statusCode:e,headers:n}),this.data=t}},jn=class extends kn{filePath;shouldRender;data;responseType=`File`;constructor({statusCode:e,filePath:t,shouldRender:n,headers:r,data:i}){super({statusCode:e,headers:r}),this.filePath=t,this.shouldRender=n,this.data=i}},U=class{metadata;constructor(e){this.metadata=e}toJSON(){let e={[H.userAgent]:this.metadata.headers?.[H.userAgent],[H.contentType]:this.metadata.headers?.[H.contentType],[H.acceptLanguage]:this.metadata.headers?.[H.acceptLanguage],[H.accept]:this.metadata.headers?.[H.accept]},t=te({reqId:this.metadata.requestId,method:this.metadata.method,url:this.metadata.url,protocol:this.metadata.protocol,query:this.metadata.query,params:this.metadata.params,ip:this.metadata.ip,locale:this.metadata.locale,headers:e},{filterNull:!0,filterUndefined:!0,filterEmptyString:!0,filterEmptyArray:!0,filterEmptyObject:!0});return ie(t)?void 0:t}};const Mn=Symbol.for(`request-scope.storage`);function Nn(){let e=Reflect.get(globalThis,Mn);if(e)return e;let t=new Ee;return Reflect.defineProperty(globalThis,Mn,{value:t,configurable:!1,enumerable:!1,writable:!1}),t}const Pn=Nn(),W={run(e,t){return Pn.run(e,t)},get metadata(){let e=Pn.getStore();if(!e?.metadata)throw Error("[RequestScope] Attempted to access `metadata` outside of request lifecycle.");return e.metadata},get requestId(){return this.metadata.requestId},get locale(){return this.metadata.locale}};var Fn=class{static t(e,t={}){let n=W.locale;return Se.t(e,{...t,lng:n})}static get currentLocale(){return W.locale}static isSupportedLanguage(e,t={ignoreRegion:!0}){let n=gn(e);if(!n)return!1;let r=Se.options.supportedLngs;if(!r)return!1;let i=new Set(r.map(gn));if(i.has(n))return!0;if(t.ignoreRegion){let{base:e}=_n(n);if(e&&i.has(e))return!0}return!1}},In=class{static make(e,t={}){return this.translateKey(e,t)}static translateKey(e,t={}){let{overrideMessage:n,i18n:r}=t;return n??Fn.t(e,r)}};function G(e){return Gn(e),e}const Ln=G({NOT_FOUND:{message:B.Apikit.Errors.Common.NotFound,code:`RESOURCE_NOT_FOUND`,statusCode:404},UNKNOWN_ERROR:{message:B.Apikit.Errors.Common.UnknownError,code:`UNKNOWN_ERROR`,statusCode:500},UNABLE_TO_PROCESS_REQUEST:{message:B.Apikit.Errors.Common.UnableToProcessRequest,code:`UNABLE_TO_PROCESS_REQUEST`,statusCode:500},RESOURCE_ALREADY_EXISTS:{message:B.Apikit.Errors.Common.AlreadyExists,code:`RESOURCE_ALREADY_EXISTS`,statusCode:409}}),Rn=G({INTERNAL_SERVER_ERROR:{message:B.Apikit.Errors.Server.Internal,code:`INTERNAL_SERVER_ERROR`,statusCode:500},SERVICE_UNAVAILABLE:{message:B.Apikit.Errors.Server.Unavailable,code:`SERVICE_UNAVAILABLE`,statusCode:503},DEPENDENCY_FAILED:{message:B.Apikit.Errors.Server.DependencyFailed,code:`DEPENDENCY_FAILED`,statusCode:424},TIMEOUT:{message:B.Apikit.Errors.Server.Timeout,code:`TIMEOUT`,statusCode:504}}),zn=G({TOO_MANY_REQUESTS:{message:B.Apikit.Errors.Limit.TooManyRequests,code:`TOO_MANY_REQUESTS`,statusCode:429}}),Bn=G({UNAUTHORIZED:{message:B.Apikit.Errors.Auth.Unauthorized,code:`UNAUTHORIZED`,statusCode:401},FORBIDDEN:{message:B.Apikit.Errors.Auth.Forbidden,code:`FORBIDDEN`,statusCode:403}}),Vn=G({BAD_REQUEST:{message:B.Apikit.Errors.Validation.BadRequest,code:`BAD_REQUEST`,statusCode:400},INVALID_JSON_SYNTAX:{message:B.Apikit.Errors.Validation.InvalidJsonSyntax,code:`JSON_SYNTAX_ERROR`,statusCode:400},INVALID_PROPERTIES:{message:B.Apikit.Errors.Validation.InvalidProperties,code:`INVALID_PROPERTIES`,statusCode:400},INVALID_FORMAT:{message:B.Apikit.Errors.Validation.InvalidFormat,code:`INVALID_FORMAT`,statusCode:400},INVALID_DATE_FORMAT:{message:B.Apikit.Errors.Validation.InvalidDateFormat,code:`INVALID_DATE_FORMAT`,statusCode:400},INVALID_PASSWORD:{message:B.Apikit.Errors.Validation.InvalidPassword,code:`INVALID_PASSWORD`,statusCode:403},INVALID_PASSWORD_NEW_SAME_AS_OLD:{message:B.Apikit.Errors.Validation.InvalidPasswordNewSameAsOld,code:`INVALID_PASSWORD_NEW_SAME_AS_OLD`,statusCode:409},INVALID_PHONE_NUMBER_FORMAT:{message:B.Apikit.Errors.Validation.InvalidPhoneNumberFormat,code:`INVALID_PHONE_NUMBER_FORMAT`,statusCode:400},INVALID_PHONE_NEW_SAME_AS_OLD:{message:B.Apikit.Errors.Validation.InvalidPhoneNewSameAsOld,code:`INVALID_PHONE_NEW_SAME_AS_OLD`,statusCode:409},INVALID_EMAIL_FORMAT:{message:B.Apikit.Errors.Validation.InvalidEmailFormat,code:`INVALID_EMAIL_FORMAT`,statusCode:400},INVALID_EMAIL_NEW_SAME_AS_OLD:{message:B.Apikit.Errors.Validation.InvalidEmailNewSameAsOld,code:`INVALID_EMAIL_NEW_SAME_AS_OLD`,statusCode:409}}),Hn=G({UNSUPPORTED_FORMAT:{message:B.Apikit.Errors.Format.Unsupported,code:`UNSUPPORTED_FORMAT`,statusCode:400},MAX_SIZE_EXCEEDED:{message:B.Apikit.Errors.Format.MaxSizeExceeded,code:`MAX_SIZE_EXCEEDED`,statusCode:413}}),Un=G({MAX_SIZE_EXCEEDED:{message:B.Apikit.Errors.Image.MaxSizeExceeded,code:`IMAGE_MAX_SIZE_EXCEEDED`,statusCode:413}}),Wn=G({Common:Ln,Server:Rn,Limit:zn,Authorization:Bn,Validation:Vn,Format:Hn,Image:Un});function Gn(e){let t=new Set;Kn(e,e=>{if(t.has(e.message))throw Error(`Duplicate API error message key: ${e.message}`);t.add(e.message)})}function Kn(e,t){for(let n of Object.values(e)){if(R(n)){t(n);continue}Kn(n,t)}}const K=qn(Wn);function qn(e){return{codes:e,make(t,n={}){let r=Yn(e,t);if(!r)throw Error(`Invalid API error code path: ${t}`);return Jn(r,n)},extend(t){let n=xe({},e,t);return G(n),qn(n)}}}function Jn(e,t){let{overrideMessage:n,details:r,i18n:i}=t,a=In.translateKey(e.message,{overrideMessage:n,i18n:i});return new L({code:e.code,statusCode:e.statusCode,message:a,details:r})}function Yn(e,t){let n=t.split(`.`),r=e;for(let e of n){if(!r||R(r))return;r=r[e]}if(!(!r||!R(r)))return r}var Xn=class{mimeType;constructor(e){if(e.includes(`/`)){if(!be.extension(e))throw K.make(`Format.UNSUPPORTED_FORMAT`);this.mimeType=e;return}let t=be.lookup(e);if(!t)throw K.make(`Format.UNSUPPORTED_FORMAT`);this.mimeType=t}get value(){return this.mimeType}get extension(){let e=be.extension(this.mimeType);if(!e)throw K.make(`Format.UNSUPPORTED_FORMAT`);return e}equals(e){return this.mimeType===e.value}},Zn=class{value;constructor(e){this.value=e}apply(e){return typeof e==`function`?this.value=e(this.value):this.applyTransformations(e),this}filter(e=e=>e!==void 0){let t=n=>{if(Array.isArray(n)){let r=n.map(t).filter(e);return r.length>0?r:void 0}if(ce(n)){let r=Object.entries(n).map(([e,n])=>[e,t(n)]).filter(([t,n])=>e(n));return r.length>0?Object.fromEntries(r):void 0}return e(n)?n:void 0};return this.value=t(this.value),this}exec(){return this.value}applyTransformations(e){se(this.value)&&(this.value=Object.fromEntries(Object.entries(this.value).map(([t,n])=>[t,e[t]?.(n)??n])))}};let q=class{format(e){return new Zn(e)}};q=E([h()],q);let J=class{normalizeFields(e){let t={};for(let[n,r]of Object.entries(e))t[n]=this.normalizeValue(r,n);return t}normalizeValue(e,t){if(e===void 0)return;if(e===null)return null;if(!ae(e))return e;let n=e.trim();if(n===``)return e;if(n===`null`)return null;if(n===`true`)return!0;if(n===`false`)return!1;if(!Number.isNaN(Number(n)))return Number(n);try{return JSON.parse(n)}catch{return e}}};J=E([h()],J);var Qn=class{assemble(e){e.bind(k.DI.Formatter.Controller).to(q),e.bind(k.DI.Formatter.MultipartController).to(J)}};const Y={maxStringLength:4096,randomIntegerRangeLimit:2**48},$n={length:8,alphabet:`alphanumeric`},er={decimal:`0123456789`,lowercase:`abcdefghijklmnopqrstuvwxyz`,uppercase:`ABCDEFGHIJKLMNOPQRSTUVWXYZ`,letters:`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,alphanumeric:`0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,hex:`0123456789abcdef`,base64:`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,base64url:`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`};let tr=class{generateNumber(e){return this.assertGenerateNumberOptions(e),e.min===e.max?e.min:Ae(e.min,e.max+1)}generateString(e=$n){let t=e.length??$n.length,n=this.resolveAlphabet(e.alphabet??$n.alphabet);this.assertStringLength(t),this.assertAlphabet(n);let r=``;for(let e=0;e<t;e++)r+=n.charAt(Ae(0,n.length));return r}generateUuidV4(){return Me()}generateUuidV7(){return Ne()}resolveAlphabet(e){return typeof e==`string`?er[e]:e.characters}assertGenerateNumberOptions(e){if(!Number.isSafeInteger(e.min))throw Error(`GenerateNumberOptions.min must be a safe integer`);if(!Number.isSafeInteger(e.max))throw Error(`GenerateNumberOptions.max must be a safe integer`);if(e.max<e.min)throw Error(`GenerateNumberOptions.max must be greater than or equal to min`);if(e.max===2**53-1)throw Error(`GenerateNumberOptions.max must be lower than Number.MAX_SAFE_INTEGER`);if(e.max-e.min>=Y.randomIntegerRangeLimit)throw Error(`GenerateNumberOptions range must be lower than ${Y.randomIntegerRangeLimit}`)}assertStringLength(e){if(!Number.isSafeInteger(e))throw Error(`GenerateStringOptions.length must be a safe integer`);if(e<=0)throw Error(`GenerateStringOptions.length must be greater than 0`);if(e>Y.maxStringLength)throw Error(`GenerateStringOptions.length must be lower than or equal to ${Y.maxStringLength}`)}assertAlphabet(e){if(e.length<2)throw Error(`GenerateStringOptions.alphabet must contain at least 2 characters`);if(!/^[!-~]+$/.test(e))throw Error(`GenerateStringOptions.alphabet must contain printable ASCII characters without whitespace`);if(new Set(e).size!==e.length)throw Error(`GenerateStringOptions.alphabet must not contain duplicate characters`)}};tr=E([h()],tr);var nr=class{assemble(e){e.bind(k.DI.Generator.RandomValueGenerator).to(tr)}},rr=class{assemble(e){e.bind(k.DI.I18n.Controller).to(V)}};let ir=class{formatter;constructor(e){this.formatter=e}async processBufferToBuffer(e,t){let{processed:n,type:r}=await this.transform(g(e),t);return{buffer:await n.toBuffer(),type:r}}async processBufferToStream(e,t){let{processed:n,type:r}=await this.transform(g(e),t);return{stream:this.asReadable(n),type:r}}async processStreamToBuffer(e,t){let n=g();await Ie(e,n);let{processed:r,type:i}=await this.transform(n,t);return{buffer:await r.toBuffer(),type:i}}async processStreamToStream(e,t){let n=g();await Ie(e,n);let{processed:r,type:i}=await this.transform(n,t);return{stream:this.asReadable(r),type:i}}async transform(e,t){let n=t??this.makeDefaultOptions(),r;try{r=await e.metadata()}catch{throw K.make(`Format.UNSUPPORTED_FORMAT`,{details:`Invalid or unsupported image file`})}this.validateMaximumSize(r.size,n.maximumSize),this.validateInputFormat(r.format,n.allowedInputFormats);let i=await this.applyNormalization(e,r,n),a=this.toSharpFormat(n.outputFormat),{sharp:o}=n;i=o?.toFormat?i.toFormat(a,o.toFormat):i.toFormat(a),o?.configure&&(i=o.configure(i));let s=this.toFormatType(n.outputFormat);return{processed:i,type:s}}validateInputFormat(e,t){if(!e||!g.format[e]?.input)throw K.make(`Format.UNSUPPORTED_FORMAT`,{details:`Unsupported input format: ${e}`});if(t&&!t.includes(e))throw K.make(`Format.UNSUPPORTED_FORMAT`,{details:`Format not allowed: ${e}`})}validateMaximumSize(e,t){if(!(!t||!e)&&e>t){let n=this.formatter.formatBytes(t,{inputUnit:c.Byte,outputUnit:`auto`,decimals:1});throw K.make(`Image.MAX_SIZE_EXCEEDED`,{i18n:{specs:{maxSize:n.value,unit:n.unit}},details:`current=${e}B, max=${t}B, exceeded=${e-t}B`})}}toSharpFormat(e){return e}toFormatType(e){if(!this.getFormatInfo(e)?.output){let t=`Cannot encode output format: ${e}`;throw K.make(`Format.UNSUPPORTED_FORMAT`,{details:t})}return new Xn(e)}getFormatInfo(e){return g.format[e]}asReadable(e){let t=new Pe;return e.on(`error`,e=>t.destroy(e)),e.pipe(t),t}async applyNormalization(e,t,n){if(n.minWidth==null&&n.maxWidth==null&&n.minAspectRatio==null&&n.maxAspectRatio==null)return n.sharp?.resize&&(e=e.resize(n.sharp.resize)),e;this.validateConstraints(n);let r=t.width??0,i=t.height??0;if(!(r>0&&i>0))throw K.make(`Validation.INVALID_PROPERTIES`,{details:`Missing image dimensions.`});let a=n.aspectRatioTolerance??0,o=r/i,s=this.pickTargetAspectRatio(o,n.minAspectRatio,n.maxAspectRatio,a),c=r;if(s!==void 0){let t=o>s,n=t?Math.max(1,Math.round(i*s)):r,a=t?i:Math.max(1,Math.round(r/s)),l=Math.max(0,Math.floor((r-n)/2)),u=Math.max(0,Math.floor((i-a)/2));e=e.extract({left:l,top:u,width:n,height:a}),c=n}let{minWidth:l,maxWidth:u}=n,ee=typeof u==`number`&&c>u?u:typeof l==`number`&&c<l?l:c;return ee!==c&&(e=e.resize({width:ee})),e}validateConstraints(e){let t=[],n=e=>Number.isFinite(e)&&e>0;if(e.minWidth!=null&&!n(e.minWidth)&&t.push(`minWidth must be > 0`),e.maxWidth!=null&&!n(e.maxWidth)&&t.push(`maxWidth must be > 0`),e.minAspectRatio!=null&&!n(e.minAspectRatio)&&t.push(`minAspectRatio must be > 0`),e.maxAspectRatio!=null&&!n(e.maxAspectRatio)&&t.push(`maxAspectRatio must be > 0`),e.aspectRatioTolerance!=null&&!(e=>Number.isFinite(e)&&e>=0)(e.aspectRatioTolerance)&&t.push(`aspectRatioTolerance must be ≥ 0`),e.minWidth!=null&&e.maxWidth!=null&&e.minWidth>e.maxWidth&&t.push(`minWidth must be ≤ maxWidth`),e.minAspectRatio!=null&&e.maxAspectRatio!=null&&e.minAspectRatio>e.maxAspectRatio&&t.push(`minAspectRatio must be ≤ maxAspectRatio`),t.length)throw K.make(`Validation.INVALID_PROPERTIES`,{details:t.join(`; `)})}pickTargetAspectRatio(e,t,n,r=0){if(typeof t==`number`&&e<t-r)return t;if(typeof n==`number`&&e>n+r)return n}makeDefaultOptions(){return{outputFormat:`jpeg`,maximumSize:7864320,minWidth:320,maxWidth:1080,minAspectRatio:.8,maxAspectRatio:1.91,aspectRatioTolerance:.01,sharp:{toFormat:{quality:82,progressive:!0}}}}};ir=E([h(),M(0,m(u.DI.Formatter.UnitController)),j(`design:paramtypes`,[Object])],ir);var ar=class{assemble(e){e.bind(k.DI.Image.NormalizationController).to(ir)}};let or=class{normalizeEmail(e){let t=e.trim();if(!_.isEmail(t))throw K.make(`Validation.INVALID_EMAIL_FORMAT`);let n=_.normalizeEmail(t,{all_lowercase:!0,gmail_lowercase:!0,gmail_remove_dots:!0,gmail_remove_subaddress:!0,gmail_convert_googlemaildotcom:!0,outlookdotcom_lowercase:!0,outlookdotcom_remove_subaddress:!0,yahoo_lowercase:!0,yahoo_remove_subaddress:!0,icloud_lowercase:!0,icloud_remove_subaddress:!0});if(!n)throw K.make(`Validation.INVALID_EMAIL_FORMAT`);return n}normalizePhoneToE164(e){try{return Re(e).format(`E.164`)}catch{throw K.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}normalizePhoneToInternational(e){try{return Re(e).format(`INTERNATIONAL`)}catch{throw K.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}normalizePhoneToNational(e){try{return Re(e).format(`NATIONAL`).replace(/[^\d]/g,``)}catch{throw K.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}};or=E([h()],or);var sr=class{assemble(e){e.bind(k.DI.Normalization.Controller).to(or)}};const cr=`${cn.name}.ApiKit.Internal.DI`,lr={DI:{Notification:{ChannelController:Symbol.for(`${cr}.Notification.ChannelController`)}}},ur=`[Notification]`;let dr=function(e){return e.Telegram=`telegram`,e}({});const fr=`${ur}:Telegram`;var pr=class{configuration;channel=`telegram`;constructor(e){this.configuration=e}async send(e){if(e.type!==this.channel)throw Error(`${fr} Invalid channel request.`);let t;try{t=await fetch(`https://api.telegram.org/bot${this.configuration.token}/sendMessage`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({chat_id:this.configuration.chatId,text:mr(e.payload)})})}catch{throw Error(`${fr} Request failed.`)}if(!t.ok)throw Error(`${fr} Request failed with status ${t.status}.`)}};function mr(e){return e.title===void 0?e.message:`${e.title}\n\n${e.message}`}let hr=class{logger;channelControllers;constructor(e,t){this.logger=t,this.channelControllers=gr(e??[])}async send(e,t={}){let n=t.throwOnFailure===!0,r=[];for(let t of e.channels)r.push(await this.deliver(t,n));return{deliveries:r}}async deliver(e,t){let n={channel:e.type,status:`failed`};try{let t=this.channelControllers.get(e.type);if(!t)throw Error(`${ur} Channel "${e.type}" is unavailable.`);return await t.send(e),{channel:e.type,status:`sent`}}catch(r){if(this.logger.error(`${ur} Delivery failed.`,{error:r,details:{channel:e.type}}),t)throw r;return n}}};hr=E([h(),M(0,de(lr.DI.Notification.ChannelController)),M(0,fe()),M(1,m(u.DI.Logger)),j(`design:paramtypes`,[Object,Object])],hr);function gr(e){let t=new Map;for(let n of e){if(t.has(n.channel))throw Error(`${ur} Channel "${n.channel}" is registered more than once.`);t.set(n.channel,n)}return t}var _r=class{assemble(e){this.assembleChannelControllers(e),e.bind(k.DI.Notification.Controller).to(hr).inSingletonScope()}assembleChannelControllers(e){let t=global.apikit.notificationConfig;if(!t.enabled)return;let n=t.channels.telegram;n&&e.bind(lr.DI.Notification.ChannelController).toConstantValue(new pr(n))}};let vr=class{makeResponse(e,t,n){return{description:e,content:this.constructContent(t),headers:n?this.constructHeaders(n):void 0}}constructContent(e){return Object.entries(e).reduce((e,[t,{schema:n,examples:r}])=>(e[t]={schema:n,examples:r?this.constructExamples(r):void 0},e),{})}constructExamples(e){return Object.entries(e).reduce((e,[t,n])=>(e[t]={summary:n.summary,value:n.value},e),{})}constructHeaders(e){return e||{}}};vr=E([h()],vr);var yr=class{assemble(e){e.bind(k.DI.OpenAPI.SchemaController).to(vr)}};let br=class{digest(e,t){let n=Oe(this.resolveDigestAlgorithm(t.algorithm)).update(e,`utf8`).digest();return this.encode(n,t.outputEncoding)}mac(e,t){let n=ke(this.resolveMacAlgorithm(t.algorithm),t.secret).update(e,`utf8`).digest();return this.encode(n,t.outputEncoding)}verifyMac(e,t,n){let r=this.mac(e,n);return this.timingSafeEqual(r,t)}async hashPassword(e,t){if(t.algorithm===`argon2id`)return ze.hash(e,{type:ze.argon2id,memoryCost:t.memoryCost,timeCost:t.timeCost,parallelism:t.parallelism})}async verifyPassword(e,t){try{return await ze.verify(t,e)}catch{return!1}}timingSafeEqual(e,t){let n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&je(n,r)}encode(e,t){switch(t){case`hex`:return e.toString(`hex`);case`base64url`:return e.toString(`base64url`)}}resolveDigestAlgorithm(e){switch(e){case`sha256`:return`sha256`;case`sha384`:return`sha384`;case`sha512`:return`sha512`}}resolveMacAlgorithm(e){switch(e){case`hmac-sha256`:return`sha256`;case`hmac-sha384`:return`sha384`;case`hmac-sha512`:return`sha512`}}};br=E([h()],br);var xr=class{_value;_payload;constructor(e,t){this._value=e,this._payload=t}get value(){return this._value}get payload(){return this._payload}getField(e){return d(()=>this._payload[e]).orDefault(void 0)}},Sr=class{assemble(e){e.bind(k.DI.Security.CryptographyController).to(br)}},Cr=v(async(e,t)=>{let n=t.apikitController.basicAuth;if(!n.enabled)return;let r=n.username,i=n.password;if(!r||!i)throw Error(`[ApiKit:BasicAuth] username and password are required when basic auth is enabled.`);await e.register(Be,{validate:wr(r,i),authenticate:n.authenticate,proxyMode:n.proxyMode,header:n.header,strictCredentials:n.strictCredentials})},{name:`apikit-basic-auth`});function wr(e,t){return async(n,r)=>{Tr({inputUsername:n,inputPassword:r,expectedUsername:e,expectedPassword:t})}}function Tr(e){let t=Er(e.inputUsername,e.expectedUsername),n=Er(e.inputPassword,e.expectedPassword);if(!t||!n)throw Error(`Access denied`)}function Er(e,t){let n=Buffer.isBuffer(e)?e:Buffer.from(e,`utf-8`),r=Buffer.isBuffer(t)?t:Buffer.from(t,`utf-8`);return n.length===r.length?De.timingSafeEqual(n,r):(De.timingSafeEqual(n,n),!1)}var Dr=v(async e=>{await e.register(Te,{hook:`onRequest`,parseOptions:{}})},{name:`apikit-cookie`}),Or=v(async(e,t)=>{let n=t.apikitController.cors;n.enabled&&await e.register(We,kr(n))},{name:`apikit-cors`});function kr(e){let t=e.allowAllOrigins?!0:Ar(e.options.origin,{includeWwwSubdomain:e.includeWwwSubdomain});return{...e.options,origin:t}}function Ar(e,t){return e&&(typeof e==`string`?Nr(e,t):Array.isArray(e)?jr(e,t):e)}function jr(e,t){let n=[];for(let r of e)Mr(n,r,t);return Fr(n)}function Mr(e,t,n){if(typeof t==`string`){e.push(...Nr(t,n));return}if(t instanceof RegExp||typeof t==`boolean`){e.push(t);return}if(Array.isArray(t))for(let r of t)Mr(e,r,n)}function Nr(e,t){let n=Pr(e);if(!n)return[e];if(!t.includeWwwSubdomain)return[n];let{protocol:r,host:i}=new URL(n);return/^[a-zA-Z][a-zA-Z0-9.-]*$/.test(i)?[n,`${r}//${i.startsWith(`www.`)?i:`www.${i}`}`]:[n]}function Pr(e){try{let{protocol:t,host:n}=new URL(e);return`${t}//${n}`}catch{return null}}function Fr(e){let t=new Set,n=[];for(let r of e){if(typeof r!=`string`){n.push(r);continue}t.has(r)||(t.add(r),n.push(r))}return n}const Ir=`[ApiKit:Health]`;var Lr=v(async(e,t)=>{let n=t.apikitController.health;if(!n.enabled){e.log.info(`${Ir} Disabled — skipping`);return}await e.register(Ke,{exposeStatusRoute:n.url,maxEventLoopDelay:n.pressure.maxEventLoopDelay,maxHeapUsedBytes:n.pressure.maxHeapUsedBytes,maxRssBytes:n.pressure.maxRssBytes,maxEventLoopUtilization:n.pressure.maxEventLoopUtilization}),e.log.info(`${Ir} Enabled`)},{name:`apikit-health`}),Rr=v(async e=>{await e.register(Je,{strict:!1,isAWS:!1})},{name:`apikit-ip`});const zr=`[ApiKit:Metrics]`;var Br=v(async(e,t)=>{let n=t.apikitController.metrics;if(!n.enabled){e.log.info(`${zr} Disabled — skipping`);return}await e.register(Xe,{endpoint:n.endpoint,name:n.name,defaultMetrics:n.defaultMetrics,routeMetrics:n.routeMetrics,clearRegisterOnInit:n.clearRegisterOnInit}),e.log.info(`${zr} Enabled`)},{name:`apikit-metrics`}),Vr=v(async(e,t)=>{let n=t.apikitController.multipart;n.enabled&&await e.register(Qe,n.options)},{name:`apikit-multipart`});function Hr(e){let t=e.apikitController,n=t.logger;return n.enabled?qr([t.health.enabled?t.health.url:void 0,t.metrics.enabled?Wr(t.metrics.endpoint):void 0,...n.request?.ignoredPaths??[]]):[]}function Ur(e,t){let n=Kr(Gr(e));return t.some(e=>{let t=Kr(e);return n===t||n.startsWith(`${t}/`)})}function Wr(e){if(typeof e==`string`)return e;if(e&&typeof e==`object`&&`url`in e){let t=e.url;return typeof t==`string`?t:void 0}}function Gr(e){return e.split(/[?#]/,1)[0]||`/`}function Kr(e){let t=e.trim(),n=t.startsWith(`/`)?t:`/${t}`;return n.length>1?n.replace(/\/+$/,``):n}function qr(e){return[...new Set(e.filter(e=>!!e?.trim()).map(Kr).filter(e=>e!==`/`))]}const Jr=`[ApiKit:Request]`,Yr=`[ApiKit:Response]`;var Xr=v(async(e,t)=>{let n=t.logger,r=t.apikitController.logger,i=t.apikitController.isDebug,a=Hr(t);r.enabled&&(e.addHook(`onRequest`,async e=>{if(Ur(e.url,a))return;let t=new U(e.metadata);d(()=>{n.info(`${Jr} onRequest`,{metadata:t})})}),e.addHook(`preValidation`,async e=>{if(Ur(e.url,a)||!i)return;let t=new U({requestId:e.metadata.requestId});d(()=>{n.debug(`${Jr} preValidation`,{metadata:t,details:{body:Zr(e.body,e.headers)}})})}),e.addHook(`onSend`,async(e,t,r)=>(Ur(e.url,a)||d(()=>{let a=new U({requestId:e.metadata.requestId}),o={elapsedTime:t.elapsedTime,statusCode:t.statusCode};i?n.debug(`${Yr} onSend`,{metadata:a,details:{...o,body:Zr(r,t.getHeaders())}}):n.info(`${Yr} onSend`,{metadata:a,details:o})}),r)))},{name:`apikit-request-logger`,dependencies:[`apikit-request-metadata`]});function Zr(e,t){return String(t?.[H.contentType]??``).toLowerCase().includes(`multipart/form-data`)?`[Multipart]`:Qr(e)}function Qr(e,t=new WeakSet,n=0){if(!re(e))return`[Not provided]`;if(typeof e==`string`)try{return JSON.parse(e)}catch{return e}if(typeof e==`number`||typeof e==`boolean`)return e;if(typeof e==`bigint`||typeof e==`symbol`)return e.toString();if(typeof e==`function`)return`[Function: ${e.name||`anonymous`}]`;if(Buffer.isBuffer(e))return`[Buffer]`;if(e instanceof Fe)return`[Stream]`;if(typeof e==`object`&&e&&`file`in e&&`filename`in e)return`[File]`;if(typeof e==`object`){if(t.has(e))return`[Circular]`;if(t.add(e),Array.isArray(e))return e.map(e=>Qr(e,t,n+1));let r={};for(let[i,a]of Object.entries(e))r[i]=Qr(a,t,n+1);return r}return String(e)}var $r=v(async(e,t)=>{let n=t.i18nController;e.addHook(`onRequest`,async e=>{e.metadata={requestId:e.id,method:e.method,url:e.url,protocol:e.protocol,query:e.query,params:e.params,ip:oe(e.ip)?e.ips?.[0]??e.ip:e.ip,locale:n.parseLocale(e.headers[H.acceptLanguage]),headers:e.headers}})},{name:`apikit-request-metadata`}),ei=v(async e=>{e.addHook(`onRequest`,(e,t,n)=>{let r=e.metadata;W.run({metadata:r},()=>{n()})})},{name:`apikit-request-scope`,dependencies:[`apikit-request-metadata`]});const ti=`[ApiKit:Static]`,X={basicAuth:Cr,cookie:Dr,cors:Or,health:Lr,ip:Rr,metrics:Br,multipart:Vr,requestLogger:Xr,requestMetadata:$r,requestScope:ei,staticFiles:v(async(e,t)=>{let n=t.apikitController.staticFiles;if(!n.enabled){e.log.info(`${ti} Disabled — skipping`);return}if(!n.publicDirectory){let t=`${ti} publicDirectory is required when static files are enabled.`;throw e.log.error(t),Error(t)}await e.register(et,{root:n.publicDirectory,prefix:n.routePrefix,maxAge:n.maxAge,dotfiles:n.dotfiles,etag:n.etag,immutable:n.immutable,decorateReply:n.decorateReply,preCompressed:n.preCompressed}),e.log.info(`${ti} Enabled from ${n.publicDirectory}`)},{name:`apikit-static`}),view:v(async e=>{await e.register(nt,{engine:{ejs:he}})},{name:`apikit-view`})},Z=`[Server]`;let ni=class{i18n;logger;configuration;server;constructor(e,t,n){this.i18n=e,this.logger=t,this.configuration=n,this.server=rt({loggerInstance:this.logger.instance,logController:new it({disableRequestLogging:!0,requestIdLogLabel:`requestId`}),ajv:{customOptions:{strict:!0,keywords:[`example`]}},trustProxy:this.configuration.server.trustProxy})}get instance(){return this.server}async preparePlugins(e=async()=>{}){let t={i18nController:this.i18n,logger:this.logger,apikitController:this.configuration},n=[X.cookie,X.ip,X.requestMetadata,X.requestScope,X.requestLogger,X.cors,X.multipart,X.basicAuth,X.health,X.metrics],r=[X.staticFiles,X.view];for(let e of n)await this.server.register(e,t);await e(this.server,t);for(let e of r)await this.server.register(e,t)}async prepare(e){await this.configureErrorHandler(),await this.configureShutdownHandler(e)}async start(){let e=this.configuration.server.host,t=this.configuration.server.port;if(!Number.isInteger(t)||t<=0||t>65535)throw Error(`Invalid server port "${t}", must be an integer 1-65535.`);await this.server.ready(),await this.server.listen({host:e,port:t,listenTextResolver:e=>`${Z} Listening at ${e}`}),this.logger.info(`${Z} Debug mode ${this.configuration.isDebug?`ON`:`OFF`}`),this.logger.info(`${Z} Started on ${e}:${t}`)}async configureErrorHandler(){this.server.setErrorHandler(async(e,n,r)=>{let i=Array.isArray(e.validation),a=!e.statusCode||e.statusCode===500,o=K.make(`Server.INTERNAL_SERVER_ERROR`);switch(this.configuration.isDebug&&this.logger.debug(`${Z} Error Handler:`,{error:e}),!0){case e instanceof L:return r.status(e.statusCode).send(e.toJSON());case i:{let t=K.make(`Validation.BAD_REQUEST`),n=e.statusCode||t.statusCode,i=new L({statusCode:n,code:t.code,message:t.message});return r.status(n).send(i.toJSON())}case a:return this.logger.error(`${Z} Internal Server Error`,{flag:t.Important,metadata:new U({requestId:n.metadata.requestId}),error:e}),r.status(500).send(o.toJSON());default:{let t=e.statusCode||500,n=new L({statusCode:t,code:e.code||e.name||o.code,message:e.message||o.message});return r.status(t).send(n.toJSON())}}})}async configureShutdownHandler(e){let t=async(t,n)=>{if(this.logger.warn(`${Z} ⛔ Shutdown: ${t}`),e)try{await e()}catch(e){this.logger.error(`${Z} ⚠️ Shutdown hook failed`,{error:e})}try{await this.server.close(),this.logger.info(`${Z} ✅ Closed`)}catch(e){this.logger.error(`${Z} ❌ Close failed`,{error:e})}n&&this.logger.error(`${Z} 🚨 Fatal error during shutdown`,{error:n}),process.exit(+!!n)},n=[[`SIGINT`,()=>t(`SIGINT`)],[`SIGTERM`,()=>t(`SIGTERM`)],[`uncaughtException`,e=>t(`uncaughtException`,e)],[`unhandledRejection`,e=>t(`unhandledRejection`,e)]];for(let[e,t]of n)process.on(e,t)}};ni=E([h(),M(0,m(k.DI.I18n.Controller)),M(1,m(u.DI.Logger)),M(2,m(k.DI.Configuration.Controller)),j(`design:paramtypes`,[Object,Object,Object])],ni);const ri=`[ApiKit:Request]`;let ii=class{logger;responseController;constructor(e,t){this.logger=e,this.responseController=t}handler(e,t={}){return async(n,r)=>{try{let i=await e(n,t);return await this.responseController.sendResponse(n,r,i)}catch(e){throw await this.logError(n,e),e}}}preHandler(e,t={}){return async(n,r)=>{try{let i=await e(n,t);if(i)return await this.responseController.sendResponse(n,r,i)}catch(e){throw await this.logError(n,e),e}}}async logError(e,n){await ne(()=>{let r=e.metadata.requestId;n instanceof L?this.logger.info(`${ri} Api error response`,{error:n,metadata:new U({requestId:r})}):this.logger.error(`${ri} Unexpected error`,{flag:t.Important,error:n,metadata:new U({requestId:r})})})}};ii=E([h(),M(0,m(u.DI.Logger)),M(1,m(k.DI.Server.ResponseController)),j(`design:paramtypes`,[Object,Object])],ii);const ai=`[ApiKit:Response]`;let oi=class{logger;constructor(e){this.logger=e}async sendResponse(e,t,n){switch(n.responseType){case`JSON`:return await this.sendJSONResponse(e,t,n);case`File`:return await this.sendFileResponse(e,t,n);default:throw Error(`${ai} Unsupported response type`)}}async sendJSONResponse(e,t,n){let r=this.createResponseHeaders(n.headers);return t.headers(r).type(`application/json`).status(n.statusCode).send(n.data)}async sendFileResponse(e,t,n){let r=this.createResponseHeaders(n.headers);t.headers(r).type(`text/html`).status(n.statusCode);try{if(n.shouldRender){let e=await t.viewAsync(n.filePath,n.data);return t.send(e)}return t.sendFile(n.filePath)}catch(t){let n=e.metadata.requestId;throw this.logger.error(`${ai} File response failed`,{error:t,metadata:new U({requestId:n})}),t}}createResponseHeaders(e){return{[H.cacheControl]:`no-store`,...e||{}}}};oi=E([h(),M(0,m(u.DI.Logger)),j(`design:paramtypes`,[Object])],oi);var si=class{assemble(e){e.bind(k.DI.Server.Controller).to(ni).inSingletonScope(),e.bind(k.DI.Server.RequestController).to(ii).inSingletonScope(),e.bind(k.DI.Server.ResponseController).to(oi).inSingletonScope()}};let Q=class{configuration;logger;constructor(e,t){this.configuration=e,this.logger=t}validate(e,t){try{return e.parse(t)}catch(e){this.handleError(e)}}async validateAsync(e,t){try{return await e.parseAsync(t)}catch(e){this.handleError(e)}}handleError(e){if(e instanceof at){this.configuration.isDebug&&this.logger.debug(`[ApiKit:Validation] Dto validation failed`,{details:{tree:ot.treeifyError(e)}});let t=this.buildValidationDetails(e),n=this.buildValidationMessage(e);throw K.make(`Validation.INVALID_PROPERTIES`,{details:t,overrideMessage:n})}throw e}buildValidationDetails(e){return{issues:e.issues.map(e=>({code:e.code,path:e.path.map(e=>typeof e==`number`?e:String(e)),message:e.message}))}}buildValidationMessage(e){for(let t of e.issues){if(t.code!==`custom`||!t.params)continue;let e=t.params;if(!e?.i18n?.key)continue;let{key:n,values:r}=e.i18n;return r?Fn.t(n,r):Fn.t(n)}return null}};Q=E([h(),M(0,m(k.DI.Configuration.Controller)),M(1,m(u.DI.Logger)),j(`design:paramtypes`,[Object,Object])],Q);let $=class{isValidEmail(e){return!!e&&_.isEmail(e)}isValidEmailThrowing(e){if(!this.isValidEmail(e))throw K.make(`Validation.INVALID_EMAIL_FORMAT`)}isValidPhoneNumber(e,t){if(!e)return!1;let n;return n=t?Le(e,t):Le(e),!!n?.isValid()}isValidPhoneNumberThrowing(e,t){if(!this.isValidPhoneNumber(e,t))throw K.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}isValidCode(e){return!!e&&/^\d{6}$/.test(e)}isValidCodeThrowing(e){if(!this.isValidCode(e))throw K.make(`Validation.INVALID_FORMAT`,{details:`Input is not a valid code`})}isEmail(e){return!!e&&_.isEmail(e)}isEmailThrowing(e){if(!this.isEmail(e))throw K.make(`Validation.INVALID_EMAIL_FORMAT`)}isPhoneNumber(e){return!!e&&_.isMobilePhone(e)}isPhoneNumberThrowing(e){if(!this.isPhoneNumber(e))throw K.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}isNumber(e){return typeof e==`number`&&!isNaN(e)}isNumberThrowing(e){if(!this.isNumber(e))throw K.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not a valid number`})}isString(e){return typeof e==`string`}isStringThrowing(e){if(!this.isString(e))throw K.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not a valid string`})}isEmptyString(e){return e==null||e.trim()===``}isEmptyStringThrowing(e){if(!this.isEmptyString(e))throw K.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not an empty string`})}isNonEmptyString(e){return this.isString(e)&&!this.isEmptyString(e)}isNonEmptyStringThrowing(e){let t=e;if(typeof t!=`string`||t.trim()===``)throw K.make(`Validation.INVALID_PROPERTIES`,{details:`Input is empty or not a string`});return t}isValidDate(e){if(!e)return!1;let t=new Date(e);return!isNaN(t.getTime())}isValidDateThrowing(e){if(!this.isValidDate(e))throw K.make(`Validation.INVALID_DATE_FORMAT`);return new Date(e)}};$=E([h()],$);var ci=class{assemble(e){e.bind(k.DI.Validation.Controller).to($),e.bind(k.DI.Validation.DtoController).to(Q)}};function li(){return[new ln,new un,new mn,new hn,new Qn,new nr,new rr,new ar,new sr,new _r,new yr,new Sr,new si,new ci]}function ui(){let e=global.apikit.loggerConfig,t=e.enabled?{enabled:!0,debug:global.apikit.serverConfig.debug,transports:e.transports}:{enabled:!1,debug:global.apikit.serverConfig.debug};return[...n({logger:t}),...li()]}export{L as ApiError,Wn as ApiErrorCodes,K as ApiErrorFactory,D as ApiKitControllerImpl,B as ApiKitL10n,z as ApiKitL10nResource,k as ApiKitSymbols,Bn as AuthorizationErrors,pn as BaseEmailTemplate,Pt as BasicAuthConfiguration,Ft as BuildConfiguration,Ln as CommonErrors,En as Cookie,It as CorsConfiguration,br as CryptographyControllerImpl,$n as DEFAULT_GENERATE_STRING_OPTIONS,Q as DtoValidationControllerImpl,Rt as EmailConfiguration,P as EmailControllerImpl,X as FastifyPlugins,jn as FileHttpResponse,Hn as FormatErrors,Xn as FormatType,Zn as Formatter,q as FormatterControllerImpl,zt as HealthConfiguration,H as HttpHeaders,Dn as HttpMethod,kn as HttpResponse,Vt as I18nConfiguration,V as I18nControllerImpl,In as I18nFactory,Fn as I18nProvider,Un as ImageErrors,ir as ImageNormalizationControllerImpl,An as JSONHttpResponse,zn as LimitErrors,Ht as LoggerConfiguration,Kt as MetricsConfiguration,A as MongoDbQueryFormatterImpl,qt as MultipartConfiguration,J as MultipartFormatterControllerImpl,or as NormalizationControllerImpl,dr as NotificationChannel,Jt as NotificationConfiguration,vr as OpenAPISchemaControllerImpl,Y as RANDOM_VALUE_GENERATOR_LIMITS,tr as RandomValueGeneratorImpl,ii as RequestControllerImpl,U as RequestLogMetadata,W as RequestScope,oi as ResponseControllerImpl,On as ResponseType,$t as ServerConfiguration,ni as ServerControllerImpl,Rn as ServerErrors,en as StaticFilesConfiguration,I as TemporaryFileRepositoryImpl,xr as Token,$ as ValidationControllerImpl,Vn as ValidationErrors,ui as apikitAssembly,tn as defineApiKit,x as defineConfiguration,ft as defineEnvironments,G as defineErrors,gt as defineSource,Ve as fastifyBasicAuth,Ce as fastifyCookie,Ue as fastifyCors,qe as fastifyIp,Ye as fastifyMetrics,Ze as fastifyMultipart,$e as fastifyStatic,Ge as fastifyUnderPressure,tt as fastifyView,y as field,He as fp,R as isApiErrorDefinition,rn as loadApiKitContext};
1
+ import"reflect-metadata";import{Console as e,LogFlag as t,coreNodeAssembly as n,createDirectoryAsync as r,defineConfig as i,defineConfiguration as a,ensureDirectory as o,ensureDirectoryAsync as s,field as c,loadConfig as l,removePathAsync as u,resolveConfiguration as d,resolveConfigurationBinding as ee,resolvePath as te}from"@buildplease/core/node";import{ByteUnit as ne,CoreL10nResource as re,CoreSymbols as f,defineL10n as ie,filterObject as ae,ignoreError as p,ignoreErrorAsync as oe,isDefinedAndNotNull as se,isEmptyObject as ce,isNonEmptyString as le,isNullOrEmpty as ue,isObject as de,isPlainObject as fe}from"@buildplease/core";import m,{existsSync as pe}from"node:fs";import h from"node:path";import{createJiti as me}from"jiti";import{inject as g,injectable as _,multiInject as he,optional as ge}from"inversify";import _e from"node:fs/promises";import ve from"ejs";import ye from"nodemailer";import be from"node:os";import{Readable as xe}from"node:stream";import{pipeline as Se}from"node:stream/promises";import Ce from"mime-types";import we from"lodash.merge";import Te from"i18next";import Ee,{fastifyCookie as De,default as Oe}from"@fastify/cookie";import{AsyncLocalStorage as ke}from"node:async_hooks";import Ae,{createHash as je,createHmac as Me,randomInt as Ne,timingSafeEqual as Pe}from"node:crypto";import{v4 as Fe,v7 as Ie}from"uuid";import{PassThrough as Le,Readable as Re}from"stream";import{pipeline as ze}from"stream/promises";import v from"sharp";import{parsePhoneNumberFromString as Be,parsePhoneNumberWithError as Ve}from"libphonenumber-js";import y from"validator";import*as He from"argon2";import Ue,{default as We}from"@fastify/basic-auth";import Ge,{default as b}from"fastify-plugin";import Ke,{default as qe}from"@fastify/cors";import Je,{default as Ye}from"@fastify/under-pressure";import Xe,{default as Ze}from"fastify-ip";import Qe,{default as $e}from"fastify-metrics";import et,{default as tt}from"@fastify/multipart";import nt,{default as rt}from"@fastify/static";import it,{default as at}from"@fastify/view";import ot,{LogController as st}from"fastify";import{ZodError as ct,z as lt}from"zod";export*from"@buildplease/core/node";export*from"@buildplease/core";const x={build:{outDir:`.apikit`},logger:{enabled:!1},server:{debug:!1,trustProxy:!1},metrics:{enabled:!1,endpoint:`/metrics`,name:`metrics`,defaultMetrics:{enabled:!0},routeMetrics:{enabled:!0},clearRegisterOnInit:!1},health:{enabled:!0,url:`/health`,pressure:{maxEventLoopDelay:0,maxHeapUsedBytes:0,maxRssBytes:0,maxEventLoopUtilization:0}},notification:{enabled:!1},email:{enabled:!1,templatesPath:`./src/templates`,globals:{}},i18n:{resources:{},directories:[],files:[],defaultLanguage:`en`,fallbackLanguages:`en`,supportedLanguages:[`en`,`sk`,`cs`],load:`languageOnly`,preload:[`en`,`sk`,`cs`],nonExplicitSupportedLngs:!0,lowerCaseLng:!0,cleanCode:!0,defaultNamespace:`translation`,keySeparator:`.`,nsSeparator:`:`,pluralSeparator:`_`,contextSeparator:`_`},staticFiles:{enabled:!1,routePrefix:`/`,maxAge:3600,dotfiles:`ignore`,etag:!0,immutable:!0,decorateReply:!0,preCompressed:!1},basicAuth:{enabled:!1,authenticate:!1,proxyMode:!1,header:void 0,strictCredentials:void 0},cors:{enabled:!1,allowAllOrigins:!1,includeWwwSubdomain:!0,options:{methods:[`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`OPTIONS`],credentials:!0,optionsSuccessStatus:200}},multipart:{enabled:!1,options:{limits:{fileSize:20971520}}}};async function ut(e,t){let n=h.resolve(e,t,`build-metadata.ts`);if(!m.existsSync(n))throw Error(`ApiKit build metadata "${n}" does not exist. Run "apikit build:app" first.`);return dt(await me(e,{interopDefault:!1}).import(n,{try:!0}),n)}function dt(e,t){if(!ft(e)||!ft(e.BuildMetadata))throw Error(`ApiKit build metadata is missing (${t}).`);let n=e.BuildMetadata,r=n.name;if(!ft(r)||typeof r.original!=`string`||typeof r.base!=`string`||typeof n.version!=`string`||typeof n.id!=`string`||typeof n.createdAt!=`string`)throw Error(`ApiKit build metadata is invalid (${t}).`);return{name:{original:r.original,base:r.base},version:n.version,id:n.id,createdAt:n.createdAt}}function ft(e){return typeof e==`object`&&!!e}const pt=a(`apikit.basic-auth`,{enabled:c.boolean().default(x.basicAuth.enabled),authenticate:c.custom().default(x.basicAuth.authenticate),proxyMode:c.boolean().default(x.basicAuth.proxyMode),header:c.string().optional().default(x.basicAuth.header),strictCredentials:c.boolean().optional().default(x.basicAuth.strictCredentials),username:c.string().optional(),password:c.string().optional()}),mt=a(`apikit.build`,{outDir:c.string().default(x.build.outDir)}),ht=a(`apikit.cors`,{enabled:c.boolean().default(x.cors.enabled),allowAllOrigins:c.boolean().default(x.cors.allowAllOrigins),includeWwwSubdomain:c.boolean().default(x.cors.includeWwwSubdomain),options:c.custom().default({}).map(gt)});function gt(e){return{...x.cors.options,...e}}const _t=a(`apikit.email`,{enabled:c.boolean().default(x.email.enabled),templatesPath:c.string().default(x.email.templatesPath),globals:c.custom().default(x.email.globals),smtp:{host:c.string().optional(),port:c.number().optional(),secure:c.boolean().optional(),user:c.string().optional(),password:c.string().optional()}}),vt=a(`apikit.health`,{enabled:c.boolean().default(x.health.enabled),url:c.string().default(x.health.url).map(yt),pressure:{maxEventLoopDelay:c.number().default(x.health.pressure.maxEventLoopDelay),maxHeapUsedBytes:c.number().default(x.health.pressure.maxHeapUsedBytes),maxRssBytes:c.number().default(x.health.pressure.maxRssBytes),maxEventLoopUtilization:c.number().default(x.health.pressure.maxEventLoopUtilization)}});function yt(e){if(!e.startsWith(`/`))throw Error(`apikit.health.url must start with slash.`);if(e===`/`)throw Error(`apikit.health.url must not be root path.`);if(e.includes(`?`)||e.includes(`#`))throw Error(`apikit.health.url must not contain query string or fragment.`);return e.length>1?e.replace(/\/+$/,``):e}const bt=a(`apikit.i18n`,{resources:c.custom().default(x.i18n.resources),directories:c.array(c.custom()).default(x.i18n.directories),files:c.array(c.custom()).default(x.i18n.files),defaultLanguage:c.string().default(x.i18n.defaultLanguage),fallbackLanguages:c.custom().default(x.i18n.fallbackLanguages),supportedLanguages:c.array(c.string()).default(x.i18n.supportedLanguages),load:c.custom().default(x.i18n.load),preload:c.custom().default(x.i18n.preload),nonExplicitSupportedLngs:c.boolean().default(x.i18n.nonExplicitSupportedLngs),lowerCaseLng:c.boolean().default(x.i18n.lowerCaseLng),cleanCode:c.boolean().default(x.i18n.cleanCode),namespaces:c.array(c.string()).optional(),defaultNamespace:c.string().default(x.i18n.defaultNamespace),keySeparator:c.string().default(x.i18n.keySeparator),nsSeparator:c.string().default(x.i18n.nsSeparator),pluralSeparator:c.string().default(x.i18n.pluralSeparator),contextSeparator:c.string().default(x.i18n.contextSeparator)}),xt=a(`apikit.logger`,c.custom().default({enabled:x.logger.enabled}).map(St));function St(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.logger must be object.`);if(typeof e.enabled!=`boolean`)throw Error(`apikit.logger.enabled must be boolean.`);if(!e.enabled){if(`transports`in e&&e.transports!==void 0)throw Error(`apikit.logger.transports cannot be configured when logger is disabled.`);if(`request`in e&&e.request!==void 0)throw Error(`apikit.logger.request cannot be configured when logger is disabled.`);return{enabled:!1}}if(!Array.isArray(e.transports)||e.transports.length===0)throw Error(`apikit.logger.transports must be a non-empty array when logger is enabled.`);let t=Ct(e.request);return{enabled:!0,transports:e.transports,...t?{request:t}:{}}}function Ct(e){if(e!==void 0){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.logger.request must be object.`);if(e.ignoredPaths===void 0)return{};if(!Array.isArray(e.ignoredPaths))throw Error(`apikit.logger.request.ignoredPaths must be array.`);return{ignoredPaths:e.ignoredPaths.map((e,t)=>wt(e,t))}}}function wt(e,t){if(typeof e!=`string`)throw Error(`apikit.logger.request.ignoredPaths[${t}] must be string.`);let n=e.trim();if(!n)throw Error(`apikit.logger.request.ignoredPaths[${t}] must not be empty.`);if(!n.startsWith(`/`))throw Error(`apikit.logger.request.ignoredPaths[${t}] must start with slash.`);if(n===`/`)throw Error(`apikit.logger.request.ignoredPaths[${t}] must not be root path.`);if(n.includes(`?`)||n.includes(`#`))throw Error(`apikit.logger.request.ignoredPaths[${t}] must not contain query string or fragment.`);return n.length>1?n.replace(/\/+$/,``):n}const Tt=a(`apikit.metrics`,{enabled:c.boolean().default(x.metrics.enabled),endpoint:c.custom().default(x.metrics.endpoint),name:c.string().default(x.metrics.name),defaultMetrics:c.custom().default(x.metrics.defaultMetrics),routeMetrics:c.custom().default(x.metrics.routeMetrics),clearRegisterOnInit:c.boolean().default(x.metrics.clearRegisterOnInit)}),Et=a(`apikit.multipart`,{enabled:c.boolean().default(x.multipart.enabled),options:c.custom().default(x.multipart.options)}),Dt=a(`apikit.notification`,c.custom().default({enabled:x.notification.enabled}).map(Ot));function Ot(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.notification must be object.`);if(typeof e.enabled!=`boolean`)throw Error(`apikit.notification.enabled must be boolean.`);if(!e.enabled){if(`channels`in e&&e.channels!==void 0)throw Error(`apikit.notification.channels cannot be configured when notification is disabled.`);return{enabled:!1}}if(!e.channels||typeof e.channels!=`object`||Array.isArray(e.channels))throw Error(`apikit.notification.channels must be object when notification is enabled.`);At(e.channels);let t=kt(e.channels.telegram);if(!t)throw Error(`apikit.notification.channels must contain at least one configured channel.`);return{enabled:!0,channels:{telegram:t}}}function kt(e){if(e!==void 0){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.notification.channels.telegram must be object.`);return{token:jt(e.token,`apikit.notification.channels.telegram.token`),chatId:jt(e.chatId,`apikit.notification.channels.telegram.chatId`)}}}function At(e){for(let t of Object.keys(e))if(t!==`telegram`)throw Error(`apikit.notification.channels.${t} is not supported.`)}function jt(e,t){if(typeof e!=`string`)throw Error(`${t} must be string.`);let n=e.trim();if(!n)throw Error(`${t} must not be empty.`);return n}const Mt=a(`apikit.server`,{identifier:c.string(),debug:c.boolean().default(x.server.debug),host:c.string(),port:c.number(),trustProxy:c.custom().default(x.server.trustProxy)}),Nt=a(`apikit.staticFiles`,{enabled:c.boolean().default(x.staticFiles.enabled),publicDirectory:c.string().optional(),routePrefix:c.string().default(x.staticFiles.routePrefix),maxAge:c.number().default(x.staticFiles.maxAge),dotfiles:c.custom().default(x.staticFiles.dotfiles),etag:c.boolean().default(x.staticFiles.etag),immutable:c.boolean().default(x.staticFiles.immutable),decorateReply:c.boolean().default(x.staticFiles.decorateReply),preCompressed:c.boolean().default(x.staticFiles.preCompressed)});function S(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let C=class{get build(){return global.apikit.build}get isDebug(){return global.apikit.serverConfig.debug}get environment(){return global.apikit.environmentConfig}get logger(){return global.apikit.loggerConfig}get server(){return global.apikit.serverConfig}get metrics(){return global.apikit.metricsConfig}get health(){return global.apikit.healthConfig}get email(){return global.apikit.emailConfig}get notification(){return global.apikit.notificationConfig}get i18n(){return global.apikit.i18nConfig}get staticFiles(){return global.apikit.staticFilesConfig}get basicAuth(){return global.apikit.basicAuthConfig}get cors(){return global.apikit.corsConfig}get multipart(){return global.apikit.multipartConfig}get(e){if(!global.apikit.configurations.has(e.key))throw Error(`Configuration "${e.key}" is missing.`);return global.apikit.configurations.get(e.key)}optional(e){return global.apikit.configurations.get(e.key)}};C=S([_()],C);const Pt=new e;async function Ft(e){let t=await l({config:e.config,environment:e.environment}),n=t.config.input,r=t.environment,i=await d(mt,n.build,{environment:r}),a=await ut(t.rootDir,i.outDir),o=await It(n,{buildMetadata:a,environment:r});global.apikit={build:a,environmentConfig:r,...o},Pt.success(`[ApiKit] Context created for ${r.name} environment`)}async function It(e,t){return{serverConfig:await d(Mt,e.server,t),loggerConfig:await d(xt,e.logger,t),metricsConfig:await d(Tt,e.metrics,t),healthConfig:await d(vt,e.health,t),emailConfig:await d(_t,e.email,t),notificationConfig:await d(Dt,e.notification,t),i18nConfig:await d(bt,e.i18n,t),staticFilesConfig:await d(Nt,e.staticFiles,t),basicAuthConfig:await d(pt,e.basicAuth,t),corsConfig:await d(ht,e.cors,t),multipartConfig:await d(Et,e.multipart,t),configurations:await Lt(e.configurations,t)}}async function Lt(e,t){let n=new Map;for(let r of e){if(r.contract.key.startsWith(`apikit.`))throw Error(`Configuration key "${r.contract.key}" is reserved for ApiKit.`);if(n.has(r.contract.key))throw Error(`Configuration "${r.contract.key}" is registered more than once.`);n.set(r.contract.key,await ee(r,t))}return n}function Rt(e,t){return i(e,{...t,configurations:t.configurations??[]})}const zt={name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`},w=`${zt.name}.ApiKit.DI`,T={DI:{Configuration:{Controller:Symbol.for(`${w}.Configuration.Controller`)},Database:{MongoDB:{QueryFormatter:Symbol.for(`${w}.Database.MongoDB.QueryFormatter`)}},Email:{Controller:Symbol.for(`${w}.Email.Controller`)},File:{TemporaryRepository:Symbol.for(`${w}.File.TemporaryRepository`)},Validation:{Controller:Symbol.for(`${w}.Validation.Controller`),DtoController:Symbol.for(`${w}.Validation.DtoController`)},OpenAPI:{SchemaController:Symbol.for(`${w}.OpenAPI.SchemaController`)},I18n:{Controller:Symbol.for(`${w}.I18n.Controller`)},Notification:{Controller:Symbol.for(`${w}.Notification.Controller`)},Normalization:{Controller:Symbol.for(`${w}.Normalization.Controller`)},Formatter:{Controller:Symbol.for(`${w}.Formatter.Controller`),MultipartController:Symbol.for(`${w}.Formatter.MultipartController`)},Generator:{RandomValueGenerator:Symbol.for(`${w}.Generator.RandomValueGenerator`)},Image:{NormalizationController:Symbol.for(`${w}.Image.NormalizationController`)},Server:{Controller:Symbol.for(`${w}.Server.Controller`),RequestController:Symbol.for(`${w}.Server.RequestController`),ResponseController:Symbol.for(`${w}.Server.ResponseController`)},Security:{CryptographyController:Symbol.for(`${w}.Security.CryptographyController`)}}};var Bt=class{assemble(e){e.bind(T.DI.Configuration.Controller).to(C).inSingletonScope()}};let E=class{format(e){return this.flattenRecursive(e,``)}flattenRecursive(e,t){let n={};for(let r of Object.keys(e)){let i=e[r];if(i===void 0||this.isPlainObject(i)&&Object.keys(i).length===0)continue;if(this.isOperator(r)){n[r]=this.processOperator(r,i);continue}let a=t?`${t}.${r}`:r;this.isPlainObject(i)?this.containsOperator(i)?n[a]={...i}:Object.assign(n,this.flattenRecursive(i,a)):n[a]=i}return n}isOperator(e){return e.startsWith(`$`)}containsOperator(e){return Object.keys(e).some(e=>this.isOperator(e))}isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype}processOperator(e,t){return e===`$expr`?t:Array.isArray(t)?t.map(e=>this.flattenRecursive(e,``)):this.isPlainObject(t)?this.flattenRecursive(t,``):t}};E=S([_()],E);var Vt=class{assemble(e){e.bind(T.DI.Database.MongoDB.QueryFormatter).to(E)}};function D(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function O(e,t){return function(n,r){t(n,r,e)}}const k=`[Email]`;let A=class{configuration;logger;transporter;templatesPath;isEnabled;smtpConfig;constructor(e,t){this.configuration=e,this.logger=t,this.isEnabled=this.configuration.email.enabled,this.smtpConfig=Ht(this.configuration.email),this.templatesPath=Ut(this.configuration.email.templatesPath)}async sendEmail(e){try{if(!this.isEnabled){this.logger.debug(`${k} Sending skipped — disabled`);return}let t=this.getOrCreateTransporter(),n=await this.renderTemplate(e),r={to:e.recipient,from:e.sender,subject:e.subject,html:n,...e.replyTo===void 0?{}:{replyTo:e.replyTo}};await t.sendMail(r)}catch(e){throw this.logger.error(`${k} Send failed`,{error:e}),e}}getOrCreateTransporter(){return this.transporter||=ye.createTransport({host:this.smtpConfig.host,port:this.smtpConfig.port,secure:this.smtpConfig.secure,auth:{user:this.smtpConfig.user,pass:this.smtpConfig.pass}}),this.transporter}async renderTemplate(e){try{let t=this.makeFilePath(e.templatePath,e.fallbackPath),n=await _e.readFile(t,`utf-8`),r={globals:this.makeGlobals(),...e.data};return ve.render(n,r)}catch(e){throw this.logger.error(`${k} Render failed`,{error:e}),e}}makeFilePath(e,t){let n=h.join(this.templatesPath,this.sanitizeTemplatePath(e));if(pe(n))return n;if(t){let e=h.join(this.templatesPath,this.sanitizeTemplatePath(t));if(pe(e))return e}throw Error(`${k} Template not found: ${n}${t?` or ${t}`:``}`)}makeGlobals(){let e=this.configuration.email.globals;return{generatedDate:new Date().toISOString().replace(`T`,` `).substring(0,16)+` UTC`,...e}}sanitizeTemplatePath(e){if(e.includes(`..`))throw Error(`${k} Invalid template path: ${e}`);let t=e.replace(/^\/+/,``);return t.endsWith(`.ejs`)?t:`${t}.ejs`}};A=S([_(),O(0,g(T.DI.Configuration.Controller)),O(1,g(f.DI.Logger)),D(`design:paramtypes`,[Object,Object])],A);function Ht(e){if(!e.enabled)return{host:``,port:0,secure:!1,user:``,pass:``};let t=e.smtp;if(!t.host)throw Error(`${k} email.smtp.host is required when email is enabled`);if(!t.port)throw Error(`${k} email.smtp.port is required when email is enabled`);if(t.secure===void 0)throw Error(`${k} email.smtp.secure is required when email is enabled`);if(!t.user)throw Error(`${k} email.smtp.user is required when email is enabled`);if(!t.password)throw Error(`${k} email.smtp.password is required when email is enabled`);if(!Number.isInteger(t.port)||t.port<=0)throw Error(`${k} email.smtp.port must be a positive integer`);return{host:t.host,port:t.port,secure:t.secure,user:t.user,pass:t.password}}function Ut(e){let t=e.trim();return h.isAbsolute(t)?h.normalize(t):h.resolve(process.cwd(),t)}var Wt=class{data;recipient;sender;subject;replyTo;constructor(e){this.data=e.data,this.recipient=e.recipient,this.sender=e.sender??this.defaultSender(),this.subject=e.subject??this.defaultSubject(),e.replyTo!==void 0&&(this.replyTo=e.replyTo)}get fallbackPath(){}},Gt=class{assemble(e){e.bind(T.DI.Email.Controller).to(A).inSingletonScope()}};const j=`[ApiKit:TemporaryFile]`;let M=class{logger;rootDir;constructor(e){this.logger=e,this.rootDir=be.tmpdir()}get rootDirectory(){return this.rootDir}async createDirectory(e){let t=this.safeJoin(e);try{return await r(t)}catch(e){throw this.logger.error(`${j} Create directory failed`,{error:e,details:{abs:t}}),e}}async deleteDirectory(e){let t=this.safeJoin(e);try{await u(t,{recursive:!0,force:!0})}catch(e){throw this.logger.error(`${j} Delete directory failed`,{error:e,details:{abs:t}}),e}}async save(e,t,n,i){let a=this.safeJoin(i),o=h.join(a,`${e}.${n.extension}`);try{if(await r(a),await s(a),Buffer.isBuffer(t))return await m.promises.writeFile(o,t),o;if(t instanceof xe){let e=m.createWriteStream(o);try{return await Se(t,e),o}finally{e.close()}}let e=Error(`Unsupported content type: expected Buffer or Readable.`);throw this.logger.error(`${j} Save unsupported content`,{error:e,details:{fileAbs:o,typeof:typeof t}}),e}catch(t){throw this.logger.error(`${j} Save failed`,{error:t,details:{fileAbs:o,relativeDirectory:i,filename:e,extension:n.extension}}),t}}async delete(e){let t=this.safeJoin(e);try{await u(t,{recursive:!1,force:!0})}catch(e){throw this.logger.error(`${j} Delete failed`,{error:e,details:{abs:t}}),e}}safeJoin(e){let t=h.resolve(this.rootDir,e),n=this.rootDir.endsWith(h.sep)?this.rootDir:this.rootDir+h.sep;if(!t.startsWith(n)&&t!==this.rootDir){let n=Error(`Path escapes repository root: "${e}"`);throw this.logger.error(`${j} Path traversal attempt`,{error:n,details:{root:this.rootDir,attempted:t}}),n}return t}};M=S([_(),O(0,g(f.DI.Logger)),D(`design:paramtypes`,[Object])],M);var Kt=class{assemble(e){e.bind(T.DI.File.TemporaryRepository).to(M)}},N=class e extends Error{_code;_statusCode;_details;constructor({code:t,message:n,statusCode:r,details:i}){super(n),this._code=t,this._statusCode=r,this._details=i,Error.captureStackTrace&&Error.captureStackTrace(this,e),Object.setPrototypeOf(this,e.prototype)}get code(){return this._code}get statusCode(){return this._statusCode}get details(){return this._details}toJSON(){let e={code:this._code,message:this.message,details:this.formatDetails(this.details)};return ae(e,{filterNull:!0,filterUndefined:!0,filterEmptyString:!0,filterEmptyObject:!0})}formatDetails(e){if(e!=null)return typeof e==`string`?{_error:[e]}:Array.isArray(e)&&e.every(e=>typeof e==`string`)?{_errors:e}:e}};function P(e){return typeof e==`object`&&!!e&&`message`in e&&typeof e.message==`string`&&`code`in e&&typeof e.code==`string`&&`statusCode`in e&&typeof e.statusCode==`number`}const F=re.extend({resources:{en:{apikit:{errors:{common:{not_found:`The requested resource was not found`,unable_to_process_request:`We’re unable to process your request.`,unknown_error:`An unknown error occurred. Please try again later.`,already_exists:`The resource already exists`},server:{internal:`An internal server error occurred`,unavailable:`The service is temporarily unavailable. Try again later`,dependency_failed:`An external service or dependency failed`,timeout:`The server did not respond in time`},limit:{too_many_requests:`Too many requests. Try again later`},auth:{unauthorized:`You are not authorized to perform this action`,forbidden:`You do not have access to this resource`},validation:{bad_request:`The request is malformed or invalid`,invalid_json_syntax:`Invalid JSON syntax`,invalid_properties:`Some of the provided values are invalid`,invalid_format:`Invalid format`,invalid_date_format:`The date format is incorrect`,invalid_password:`The password you entered is incorrect`,invalid_password_new_same_as_old:`The new password must be different from the current one`,invalid_phone_number_format:`Invalid phone number format`,invalid_phone_new_same_as_old:`TThe new phone number must be different from the old one`,invalid_email_format:`Invalid email format`,invalid_email_new_same_as_old:`The new email must be different from the current one`},format:{unsupported:`Unsupported format`,max_size_exceeded:`Payload is too large.`},image:{max_size_exceeded:`Image is too large. Maximum allowed size is {{specs.maxSize}} {{specs.unit}}.`}}}},sk:{apikit:{errors:{common:{not_found:`Požadovaný zdroj sa nenašiel`,unable_to_process_request:`Vašu požiadavku sa nepodarilo spracovať.`,unknown_error:`Vyskytla sa neznáma chyba. Skúste to prosím znova neskôr.`,already_exists:`Zdroj už existuje`},server:{internal:`Vyskytla sa interná chyba servera`,unavailable:`Služba je momentálne nedostupná. Skúste to neskôr`,dependency_failed:`Zlyhala externá služba alebo závislosť`,timeout:`Server neodpovedal v stanovenom čase`},limit:{too_many_requests:`Príliš veľa požiadaviek. Skúste to neskôr`},auth:{unauthorized:`Nemáte oprávnenie na vykonanie tejto akcie`,forbidden:`K tomuto zdroju nemáte prístup`},validation:{bad_request:`Požiadavka je neplatná alebo nesprávna`,invalid_json_syntax:`Neplatná syntax JSON`,invalid_properties:`Niektoré z poskytnutých hodnôt sú neplatné`,invalid_format:`Neplatný formát`,invalid_date_format:`Formát dátumu je nesprávny`,invalid_password:`Zadané heslo je nesprávne`,invalid_password_new_same_as_old:`Nové heslo sa musí líšiť od aktuálneho`,invalid_phone_number_format:`Neplatný formát telefónneho čísla`,invalid_phone_new_same_as_old:`Nové telefónne číslo sa musí líšiť od pôvodného`,invalid_email_format:`Neplatný formát e-mailu`,invalid_email_new_same_as_old:`Nový e-mail sa musí líšiť od aktuálneho`},format:{unsupported:`Nepodporovaný formát`,max_size_exceeded:`Súbor je príliš veľký.`},image:{max_size_exceeded:`Obrázok je príliš veľký. Maximálna povolená veľkosť je {{specs.maxSize}} {{specs.unit}}.`}}}},cs:{apikit:{errors:{common:{not_found:`Požadovaný zdroj nebyl nalezen`,unable_to_process_request:`Vaši žádost se nepodařilo zpracovat.`,unknown_error:`Došlo k neznámé chybě. Zkuste to prosím později.`,already_exists:`Zdroj již existuje`},server:{internal:`Došlo k interní chybě serveru`,unavailable:`Služba je momentálně nedostupná. Zkuste to později`,dependency_failed:`Selhala externí služba nebo závislost`,timeout:`Server neodpověděl včas`},limit:{too_many_requests:`Příliš mnoho požadavků. Zkuste to později`},auth:{unauthorized:`Nemáte oprávnění k provedení této akce`,forbidden:`K tomuto zdroji nemáte přístup`},validation:{bad_request:`Požadavek je neplatný nebo nesprávný`,invalid_json_syntax:`Neplatná syntaxe JSON`,invalid_properties:`Některé z poskytnutých hodnot jsou neplatné`,invalid_format:`Neplatný formát`,invalid_date_format:`Formát data je nesprávný`,invalid_password:`Zadané heslo je nesprávné`,invalid_password_new_same_as_old:`Nové heslo se musí lišit od aktuálního`,invalid_phone_number_format:`Neplatný formát telefonního čísla`,invalid_phone_new_same_as_old:`Nové telefonní číslo se musí lišit od původního`,invalid_email_format:`Neplatný formát e-mailu`,invalid_email_new_same_as_old:`Nový e-mail se musí lišit od aktuálního`},format:{unsupported:`Nepodporovaný formát`,max_size_exceeded:`Soubor je příliš velký.`},image:{max_size_exceeded:`Obrázek je příliš velký. Maximální povolená velikost je {{specs.maxSize}} {{specs.unit}}.`}}}}}}),I=ie(F);function qt(e){return(e??``).toLowerCase().replace(/_/g,`-`).trim()}function Jt(e){let[t,n]=e.split(`-`);return{base:t||``,region:n}}let L=class{configurationController;constructor(e){this.configurationController=e}async prepare(){let e=this.makeOptions();await Te.init(e)}parseLocale(e,t={}){let{supportedLanguages:n,defaultLanguage:r}=this.makeConfig(),{ignoreRegion:i=!0}=t;if(!e||!e.trim())return r;let a=new Set(n.map(e=>e.toLowerCase())),o,s,c=0;for(let t of e.split(`,`)){let e=t.trim();if(!e){c++;continue}let n=e.split(`;`),r=qt(n[0]??``);if(!r||r===`*`){c++;continue}let l=nn(n.find(e=>e.startsWith(`q=`)));if(l===0){c++;continue}let{base:u}=Jt(r);if(!u){c++;continue}!i&&a.has(r)&&(!o||l>o.q||l===o.q&&c<o.idx)&&(o={code:r,q:l,idx:c}),a.has(u)&&(!s||l>s.q||l===s.q&&c<s.idx)&&(s={code:u,q:l,idx:c}),c++}return o?o.code:s?s.code:r}makeOptions(){let e=this.makeConfig(),t=Yt(e);return{debug:!1,lng:e.defaultLanguage,fallbackLng:e.fallbackLanguages,supportedLngs:e.supportedLanguages,load:e.load,nonExplicitSupportedLngs:e.nonExplicitSupportedLngs,preload:e.preload,lowerCaseLng:e.lowerCaseLng,cleanCode:e.cleanCode,ns:e.namespaces,defaultNS:e.defaultNamespace,keySeparator:e.keySeparator,nsSeparator:e.nsSeparator,pluralSeparator:e.pluralSeparator,contextSeparator:e.contextSeparator,resources:t}}makeConfig(){let e=this.configurationController.i18n??{},t=e.defaultNamespace??`translation`,n=e.defaultLanguage??`en`,r=e.fallbackLanguages??n,i=(e.directories??[]).map(e=>({path:e.path,namespace:e.namespace??t})),a=(e.files??[]).map(e=>({locale:e.locale,path:e.path,namespace:e.namespace??t})),o=this.makeNamespaces(e.namespaces,t,i,a);return{resources:e.resources??{},directories:i,files:a,defaultLanguage:n,fallbackLanguages:r,supportedLanguages:e.supportedLanguages??[`en`,`sk`,`cs`],load:e.load??`languageOnly`,nonExplicitSupportedLngs:e.nonExplicitSupportedLngs??!0,preload:e.preload??!1,lowerCaseLng:e.lowerCaseLng??!0,cleanCode:e.cleanCode??!0,namespaces:o,defaultNamespace:t,keySeparator:e.keySeparator??`.`,nsSeparator:e.nsSeparator??`:`,pluralSeparator:e.pluralSeparator??`_`,contextSeparator:e.contextSeparator??`_`}}makeNamespaces(e,t,n,r){let i=Array.isArray(e)?e.filter(e=>typeof e==`string`):typeof e==`string`?[e]:[],a=new Set(i.length?i:[t]);for(let e of n)a.add(e.namespace);for(let e of r)a.add(e.namespace);return Array.from(a)}};L=S([_(),O(0,g(T.DI.Configuration.Controller)),D(`design:paramtypes`,[Object])],L);function Yt(e){let t=Zt(e);Xt(t,e);let n=[...$t(e),...en(e)];for(let{locale:e,ns:r,path:i}of n){let n=t[e]||={},a=JSON.parse(m.readFileSync(i,`utf-8`));n[r]=we(n[r]||{},a)}return t}function Xt(e,t){for(let n of Object.keys(t.resources).sort()){let r=t.resources[n];if(!r)continue;let i=e[n]||={};i[t.defaultNamespace]=we(i[t.defaultNamespace]||{},r)}}function Zt(e){let t={};for(let n of Object.keys(F.resources).sort()){let r=t[n]||={};r[e.defaultNamespace]=Qt(F.resources[n])}return t}function Qt(e){return JSON.parse(JSON.stringify(e))}function $t(e){let t=[];for(let n of e.directories){let e=tn(te(process.cwd(),n.path));for(let r of e)t.push({locale:r.locale,ns:n.namespace,path:r.path})}return t}function en(e){return e.files.map(e=>({locale:e.locale,ns:e.namespace,path:te(process.cwd(),e.path)}))}function tn(e){let t=o(e),n=m.readdirSync(t).filter(e=>e.endsWith(`.json`)).sort();if(!n.length)throw Error(`[ApiKit:I18n] No .json files in ${t}`);return n.map(e=>({locale:e.replace(/\.json$/,``),path:te(t,e)}))}function nn(e){if(!e)return 1;let t=parseFloat(e.slice(2).replace(`,`,`.`));return Number.isFinite(t)?Math.max(0,Math.min(1,t)):1}var rn=class{_name;_value;_options;constructor(e,t,n={}){this._name=e,this._value=t,this._options={...n}}get name(){return this._name}get value(){return this._value}get options(){return{...this._options}}mutate(e){return e.name!==void 0&&(this._name=e.name),e.value!==void 0&&(this._value=e.value),e.options!==void 0&&(this._options={...this._options,...e.options}),this}serialize(){return De.serialize(this._name,this._value,this._options)}toString(){return this.serialize()}};const R={accept:`accept`,acceptLanguage:`accept-language`,authorization:`authorization`,cacheControl:`cache-control`,contentType:`content-type`,cookie:`cookie`,setCookie:`set-cookie`,userAgent:`user-agent`};let an=function(e){return e.POST=`POST`,e.PUT=`PUT`,e.PATCH=`PATCH`,e.GET=`GET`,e.DELETE=`DELETE`,e.OPTIONS=`OPTIONS`,e}({}),on=function(e){return e.JSON=`JSON`,e.File=`File`,e}({});var sn=class{statusCode;headers;constructor({statusCode:e,headers:t}){this.statusCode=e,this.headers=t}},cn=class extends sn{data;responseType=`JSON`;constructor({statusCode:e,data:t,headers:n}){super({statusCode:e,headers:n}),this.data=t}},ln=class extends sn{filePath;shouldRender;data;responseType=`File`;constructor({statusCode:e,filePath:t,shouldRender:n,headers:r,data:i}){super({statusCode:e,headers:r}),this.filePath=t,this.shouldRender=n,this.data=i}},z=class{metadata;constructor(e){this.metadata=e}toJSON(){let e={[R.userAgent]:this.metadata.headers?.[R.userAgent],[R.contentType]:this.metadata.headers?.[R.contentType],[R.acceptLanguage]:this.metadata.headers?.[R.acceptLanguage],[R.accept]:this.metadata.headers?.[R.accept]},t=ae({reqId:this.metadata.requestId,method:this.metadata.method,url:this.metadata.url,protocol:this.metadata.protocol,query:this.metadata.query,params:this.metadata.params,ip:this.metadata.ip,locale:this.metadata.locale,headers:e},{filterNull:!0,filterUndefined:!0,filterEmptyString:!0,filterEmptyArray:!0,filterEmptyObject:!0});return ce(t)?void 0:t}};const un=Symbol.for(`request-scope.storage`);function dn(){let e=Reflect.get(globalThis,un);if(e)return e;let t=new ke;return Reflect.defineProperty(globalThis,un,{value:t,configurable:!1,enumerable:!1,writable:!1}),t}const fn=dn(),B={run(e,t){return fn.run(e,t)},get metadata(){let e=fn.getStore();if(!e?.metadata)throw Error("[RequestScope] Attempted to access `metadata` outside of request lifecycle.");return e.metadata},get requestId(){return this.metadata.requestId},get locale(){return this.metadata.locale}};var V=class{static t(e,t={}){let n=B.locale;return Te.t(e,{...t,lng:n})}static get currentLocale(){return B.locale}static isSupportedLanguage(e,t={ignoreRegion:!0}){let n=qt(e);if(!n)return!1;let r=Te.options.supportedLngs;if(!r)return!1;let i=new Set(r.map(qt));if(i.has(n))return!0;if(t.ignoreRegion){let{base:e}=Jt(n);if(e&&i.has(e))return!0}return!1}},pn=class{static make(e,t={}){return this.translateKey(e,t)}static translateKey(e,t={}){let{overrideMessage:n,i18n:r}=t;return n??V.t(e,r)}};function H(e){return Sn(e),e}const mn=H({NOT_FOUND:{message:I.Apikit.Errors.Common.NotFound,code:`RESOURCE_NOT_FOUND`,statusCode:404},UNKNOWN_ERROR:{message:I.Apikit.Errors.Common.UnknownError,code:`UNKNOWN_ERROR`,statusCode:500},UNABLE_TO_PROCESS_REQUEST:{message:I.Apikit.Errors.Common.UnableToProcessRequest,code:`UNABLE_TO_PROCESS_REQUEST`,statusCode:500},RESOURCE_ALREADY_EXISTS:{message:I.Apikit.Errors.Common.AlreadyExists,code:`RESOURCE_ALREADY_EXISTS`,statusCode:409}}),hn=H({INTERNAL_SERVER_ERROR:{message:I.Apikit.Errors.Server.Internal,code:`INTERNAL_SERVER_ERROR`,statusCode:500},SERVICE_UNAVAILABLE:{message:I.Apikit.Errors.Server.Unavailable,code:`SERVICE_UNAVAILABLE`,statusCode:503},DEPENDENCY_FAILED:{message:I.Apikit.Errors.Server.DependencyFailed,code:`DEPENDENCY_FAILED`,statusCode:424},TIMEOUT:{message:I.Apikit.Errors.Server.Timeout,code:`TIMEOUT`,statusCode:504}}),gn=H({TOO_MANY_REQUESTS:{message:I.Apikit.Errors.Limit.TooManyRequests,code:`TOO_MANY_REQUESTS`,statusCode:429}}),_n=H({UNAUTHORIZED:{message:I.Apikit.Errors.Auth.Unauthorized,code:`UNAUTHORIZED`,statusCode:401},FORBIDDEN:{message:I.Apikit.Errors.Auth.Forbidden,code:`FORBIDDEN`,statusCode:403}}),vn=H({BAD_REQUEST:{message:I.Apikit.Errors.Validation.BadRequest,code:`BAD_REQUEST`,statusCode:400},INVALID_JSON_SYNTAX:{message:I.Apikit.Errors.Validation.InvalidJsonSyntax,code:`JSON_SYNTAX_ERROR`,statusCode:400},INVALID_PROPERTIES:{message:I.Apikit.Errors.Validation.InvalidProperties,code:`INVALID_PROPERTIES`,statusCode:400},INVALID_FORMAT:{message:I.Apikit.Errors.Validation.InvalidFormat,code:`INVALID_FORMAT`,statusCode:400},INVALID_DATE_FORMAT:{message:I.Apikit.Errors.Validation.InvalidDateFormat,code:`INVALID_DATE_FORMAT`,statusCode:400},INVALID_PASSWORD:{message:I.Apikit.Errors.Validation.InvalidPassword,code:`INVALID_PASSWORD`,statusCode:403},INVALID_PASSWORD_NEW_SAME_AS_OLD:{message:I.Apikit.Errors.Validation.InvalidPasswordNewSameAsOld,code:`INVALID_PASSWORD_NEW_SAME_AS_OLD`,statusCode:409},INVALID_PHONE_NUMBER_FORMAT:{message:I.Apikit.Errors.Validation.InvalidPhoneNumberFormat,code:`INVALID_PHONE_NUMBER_FORMAT`,statusCode:400},INVALID_PHONE_NEW_SAME_AS_OLD:{message:I.Apikit.Errors.Validation.InvalidPhoneNewSameAsOld,code:`INVALID_PHONE_NEW_SAME_AS_OLD`,statusCode:409},INVALID_EMAIL_FORMAT:{message:I.Apikit.Errors.Validation.InvalidEmailFormat,code:`INVALID_EMAIL_FORMAT`,statusCode:400},INVALID_EMAIL_NEW_SAME_AS_OLD:{message:I.Apikit.Errors.Validation.InvalidEmailNewSameAsOld,code:`INVALID_EMAIL_NEW_SAME_AS_OLD`,statusCode:409}}),yn=H({UNSUPPORTED_FORMAT:{message:I.Apikit.Errors.Format.Unsupported,code:`UNSUPPORTED_FORMAT`,statusCode:400},MAX_SIZE_EXCEEDED:{message:I.Apikit.Errors.Format.MaxSizeExceeded,code:`MAX_SIZE_EXCEEDED`,statusCode:413}}),bn=H({MAX_SIZE_EXCEEDED:{message:I.Apikit.Errors.Image.MaxSizeExceeded,code:`IMAGE_MAX_SIZE_EXCEEDED`,statusCode:413}}),xn=H({Common:mn,Server:hn,Limit:gn,Authorization:_n,Validation:vn,Format:yn,Image:bn});function Sn(e){let t=new Set;Cn(e,e=>{if(t.has(e.message))throw Error(`Duplicate API error message key: ${e.message}`);t.add(e.message)})}function Cn(e,t){for(let n of Object.values(e)){if(P(n)){t(n);continue}Cn(n,t)}}const U=wn(xn);function wn(e){return{codes:e,make(t,n={}){let r=En(e,t);if(!r)throw Error(`Invalid API error code path: ${t}`);return Tn(r,n)},extend(t){let n=we({},e,t);return H(n),wn(n)}}}function Tn(e,t){let{overrideMessage:n,details:r,i18n:i}=t,a=pn.translateKey(e.message,{overrideMessage:n,i18n:i});return new N({code:e.code,statusCode:e.statusCode,message:a,details:r})}function En(e,t){let n=t.split(`.`),r=e;for(let e of n){if(!r||P(r))return;r=r[e]}if(!(!r||!P(r)))return r}var Dn=class{mimeType;constructor(e){if(e.includes(`/`)){if(!Ce.extension(e))throw U.make(`Format.UNSUPPORTED_FORMAT`);this.mimeType=e;return}let t=Ce.lookup(e);if(!t)throw U.make(`Format.UNSUPPORTED_FORMAT`);this.mimeType=t}get value(){return this.mimeType}get extension(){let e=Ce.extension(this.mimeType);if(!e)throw U.make(`Format.UNSUPPORTED_FORMAT`);return e}equals(e){return this.mimeType===e.value}},On=class{value;constructor(e){this.value=e}apply(e){return typeof e==`function`?this.value=e(this.value):this.applyTransformations(e),this}filter(e=e=>e!==void 0){let t=n=>{if(Array.isArray(n)){let r=n.map(t).filter(e);return r.length>0?r:void 0}if(fe(n)){let r=Object.entries(n).map(([e,n])=>[e,t(n)]).filter(([t,n])=>e(n));return r.length>0?Object.fromEntries(r):void 0}return e(n)?n:void 0};return this.value=t(this.value),this}exec(){return this.value}applyTransformations(e){de(this.value)&&(this.value=Object.fromEntries(Object.entries(this.value).map(([t,n])=>[t,e[t]?.(n)??n])))}};let W=class{format(e){return new On(e)}};W=S([_()],W);let G=class{normalizeFields(e){let t={};for(let[n,r]of Object.entries(e))t[n]=this.normalizeValue(r,n);return t}normalizeValue(e,t){if(e===void 0)return;if(e===null)return null;if(!le(e))return e;let n=e.trim();if(n===``)return e;if(n===`null`)return null;if(n===`true`)return!0;if(n===`false`)return!1;if(!Number.isNaN(Number(n)))return Number(n);try{return JSON.parse(n)}catch{return e}}};G=S([_()],G);var kn=class{assemble(e){e.bind(T.DI.Formatter.Controller).to(W),e.bind(T.DI.Formatter.MultipartController).to(G)}};const K={maxStringLength:4096,randomIntegerRangeLimit:2**48},q={length:8,alphabet:`alphanumeric`},An={decimal:`0123456789`,lowercase:`abcdefghijklmnopqrstuvwxyz`,uppercase:`ABCDEFGHIJKLMNOPQRSTUVWXYZ`,letters:`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,alphanumeric:`0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,hex:`0123456789abcdef`,base64:`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,base64url:`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`};let J=class{generateNumber(e){return this.assertGenerateNumberOptions(e),e.min===e.max?e.min:Ne(e.min,e.max+1)}generateString(e=q){let t=e.length??q.length,n=this.resolveAlphabet(e.alphabet??q.alphabet);this.assertStringLength(t),this.assertAlphabet(n);let r=``;for(let e=0;e<t;e++)r+=n.charAt(Ne(0,n.length));return r}generateUuidV4(){return Fe()}generateUuidV7(){return Ie()}resolveAlphabet(e){return typeof e==`string`?An[e]:e.characters}assertGenerateNumberOptions(e){if(!Number.isSafeInteger(e.min))throw Error(`GenerateNumberOptions.min must be a safe integer`);if(!Number.isSafeInteger(e.max))throw Error(`GenerateNumberOptions.max must be a safe integer`);if(e.max<e.min)throw Error(`GenerateNumberOptions.max must be greater than or equal to min`);if(e.max===2**53-1)throw Error(`GenerateNumberOptions.max must be lower than Number.MAX_SAFE_INTEGER`);if(e.max-e.min>=K.randomIntegerRangeLimit)throw Error(`GenerateNumberOptions range must be lower than ${K.randomIntegerRangeLimit}`)}assertStringLength(e){if(!Number.isSafeInteger(e))throw Error(`GenerateStringOptions.length must be a safe integer`);if(e<=0)throw Error(`GenerateStringOptions.length must be greater than 0`);if(e>K.maxStringLength)throw Error(`GenerateStringOptions.length must be lower than or equal to ${K.maxStringLength}`)}assertAlphabet(e){if(e.length<2)throw Error(`GenerateStringOptions.alphabet must contain at least 2 characters`);if(!/^[!-~]+$/.test(e))throw Error(`GenerateStringOptions.alphabet must contain printable ASCII characters without whitespace`);if(new Set(e).size!==e.length)throw Error(`GenerateStringOptions.alphabet must not contain duplicate characters`)}};J=S([_()],J);var jn=class{assemble(e){e.bind(T.DI.Generator.RandomValueGenerator).to(J)}},Mn=class{assemble(e){e.bind(T.DI.I18n.Controller).to(L)}};let Y=class{formatter;constructor(e){this.formatter=e}async processBufferToBuffer(e,t){let{processed:n,type:r}=await this.transform(v(e),t);return{buffer:await n.toBuffer(),type:r}}async processBufferToStream(e,t){let{processed:n,type:r}=await this.transform(v(e),t);return{stream:this.asReadable(n),type:r}}async processStreamToBuffer(e,t){let n=v();await ze(e,n);let{processed:r,type:i}=await this.transform(n,t);return{buffer:await r.toBuffer(),type:i}}async processStreamToStream(e,t){let n=v();await ze(e,n);let{processed:r,type:i}=await this.transform(n,t);return{stream:this.asReadable(r),type:i}}async transform(e,t){let n=t??this.makeDefaultOptions(),r;try{r=await e.metadata()}catch{throw U.make(`Format.UNSUPPORTED_FORMAT`,{details:`Invalid or unsupported image file`})}this.validateMaximumSize(r.size,n.maximumSize),this.validateInputFormat(r.format,n.allowedInputFormats);let i=await this.applyNormalization(e,r,n),a=this.toSharpFormat(n.outputFormat),{sharp:o}=n;i=o?.toFormat?i.toFormat(a,o.toFormat):i.toFormat(a),o?.configure&&(i=o.configure(i));let s=this.toFormatType(n.outputFormat);return{processed:i,type:s}}validateInputFormat(e,t){if(!e||!v.format[e]?.input)throw U.make(`Format.UNSUPPORTED_FORMAT`,{details:`Unsupported input format: ${e}`});if(t&&!t.includes(e))throw U.make(`Format.UNSUPPORTED_FORMAT`,{details:`Format not allowed: ${e}`})}validateMaximumSize(e,t){if(!(!t||!e)&&e>t){let n=this.formatter.formatBytes(t,{inputUnit:ne.Byte,outputUnit:`auto`,decimals:1});throw U.make(`Image.MAX_SIZE_EXCEEDED`,{i18n:{specs:{maxSize:n.value,unit:n.unit}},details:`current=${e}B, max=${t}B, exceeded=${e-t}B`})}}toSharpFormat(e){return e}toFormatType(e){if(!this.getFormatInfo(e)?.output){let t=`Cannot encode output format: ${e}`;throw U.make(`Format.UNSUPPORTED_FORMAT`,{details:t})}return new Dn(e)}getFormatInfo(e){return v.format[e]}asReadable(e){let t=new Le;return e.on(`error`,e=>t.destroy(e)),e.pipe(t),t}async applyNormalization(e,t,n){if(n.minWidth==null&&n.maxWidth==null&&n.minAspectRatio==null&&n.maxAspectRatio==null)return n.sharp?.resize&&(e=e.resize(n.sharp.resize)),e;this.validateConstraints(n);let r=t.width??0,i=t.height??0;if(!(r>0&&i>0))throw U.make(`Validation.INVALID_PROPERTIES`,{details:`Missing image dimensions.`});let a=n.aspectRatioTolerance??0,o=r/i,s=this.pickTargetAspectRatio(o,n.minAspectRatio,n.maxAspectRatio,a),c=r;if(s!==void 0){let t=o>s,n=t?Math.max(1,Math.round(i*s)):r,a=t?i:Math.max(1,Math.round(r/s)),l=Math.max(0,Math.floor((r-n)/2)),u=Math.max(0,Math.floor((i-a)/2));e=e.extract({left:l,top:u,width:n,height:a}),c=n}let{minWidth:l,maxWidth:u}=n,d=typeof u==`number`&&c>u?u:typeof l==`number`&&c<l?l:c;return d!==c&&(e=e.resize({width:d})),e}validateConstraints(e){let t=[],n=e=>Number.isFinite(e)&&e>0;if(e.minWidth!=null&&!n(e.minWidth)&&t.push(`minWidth must be > 0`),e.maxWidth!=null&&!n(e.maxWidth)&&t.push(`maxWidth must be > 0`),e.minAspectRatio!=null&&!n(e.minAspectRatio)&&t.push(`minAspectRatio must be > 0`),e.maxAspectRatio!=null&&!n(e.maxAspectRatio)&&t.push(`maxAspectRatio must be > 0`),e.aspectRatioTolerance!=null&&!(e=>Number.isFinite(e)&&e>=0)(e.aspectRatioTolerance)&&t.push(`aspectRatioTolerance must be ≥ 0`),e.minWidth!=null&&e.maxWidth!=null&&e.minWidth>e.maxWidth&&t.push(`minWidth must be ≤ maxWidth`),e.minAspectRatio!=null&&e.maxAspectRatio!=null&&e.minAspectRatio>e.maxAspectRatio&&t.push(`minAspectRatio must be ≤ maxAspectRatio`),t.length)throw U.make(`Validation.INVALID_PROPERTIES`,{details:t.join(`; `)})}pickTargetAspectRatio(e,t,n,r=0){if(typeof t==`number`&&e<t-r)return t;if(typeof n==`number`&&e>n+r)return n}makeDefaultOptions(){return{outputFormat:`jpeg`,maximumSize:7864320,minWidth:320,maxWidth:1080,minAspectRatio:.8,maxAspectRatio:1.91,aspectRatioTolerance:.01,sharp:{toFormat:{quality:82,progressive:!0}}}}};Y=S([_(),O(0,g(f.DI.Formatter.UnitController)),D(`design:paramtypes`,[Object])],Y);var Nn=class{assemble(e){e.bind(T.DI.Image.NormalizationController).to(Y)}};let Pn=class{normalizeEmail(e){let t=e.trim();if(!y.isEmail(t))throw U.make(`Validation.INVALID_EMAIL_FORMAT`);let n=y.normalizeEmail(t,{all_lowercase:!0,gmail_lowercase:!0,gmail_remove_dots:!0,gmail_remove_subaddress:!0,gmail_convert_googlemaildotcom:!0,outlookdotcom_lowercase:!0,outlookdotcom_remove_subaddress:!0,yahoo_lowercase:!0,yahoo_remove_subaddress:!0,icloud_lowercase:!0,icloud_remove_subaddress:!0});if(!n)throw U.make(`Validation.INVALID_EMAIL_FORMAT`);return n}normalizePhoneToE164(e){try{return Ve(e).format(`E.164`)}catch{throw U.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}normalizePhoneToInternational(e){try{return Ve(e).format(`INTERNATIONAL`)}catch{throw U.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}normalizePhoneToNational(e){try{return Ve(e).format(`NATIONAL`).replace(/[^\d]/g,``)}catch{throw U.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}};Pn=S([_()],Pn);var Fn=class{assemble(e){e.bind(T.DI.Normalization.Controller).to(Pn)}};const In=`${zt.name}.ApiKit.Internal.DI`,Ln={DI:{Notification:{ChannelController:Symbol.for(`${In}.Notification.ChannelController`)}}},Rn=`[Notification]`;let zn=function(e){return e.Telegram=`telegram`,e}({});const Bn=`${Rn}:Telegram`;var Vn=class{configuration;channel=`telegram`;constructor(e){this.configuration=e}async send(e){if(e.type!==this.channel)throw Error(`${Bn} Invalid channel request.`);let t;try{t=await fetch(`https://api.telegram.org/bot${this.configuration.token}/sendMessage`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({chat_id:this.configuration.chatId,text:Hn(e.payload)})})}catch{throw Error(`${Bn} Request failed.`)}if(!t.ok)throw Error(`${Bn} Request failed with status ${t.status}.`)}};function Hn(e){return e.title===void 0?e.message:`${e.title}\n\n${e.message}`}let Un=class{logger;channelControllers;constructor(e,t){this.logger=t,this.channelControllers=Wn(e??[])}async send(e,t={}){let n=t.throwOnFailure===!0,r=[];for(let t of e.channels)r.push(await this.deliver(t,n));return{deliveries:r}}async deliver(e,t){let n={channel:e.type,status:`failed`};try{let t=this.channelControllers.get(e.type);if(!t)throw Error(`${Rn} Channel "${e.type}" is unavailable.`);return await t.send(e),{channel:e.type,status:`sent`}}catch(r){if(this.logger.error(`${Rn} Delivery failed.`,{error:r,details:{channel:e.type}}),t)throw r;return n}}};Un=S([_(),O(0,he(Ln.DI.Notification.ChannelController)),O(0,ge()),O(1,g(f.DI.Logger)),D(`design:paramtypes`,[Object,Object])],Un);function Wn(e){let t=new Map;for(let n of e){if(t.has(n.channel))throw Error(`${Rn} Channel "${n.channel}" is registered more than once.`);t.set(n.channel,n)}return t}var Gn=class{assemble(e){this.assembleChannelControllers(e),e.bind(T.DI.Notification.Controller).to(Un).inSingletonScope()}assembleChannelControllers(e){let t=global.apikit.notificationConfig;if(!t.enabled)return;let n=t.channels.telegram;n&&e.bind(Ln.DI.Notification.ChannelController).toConstantValue(new Vn(n))}};let Kn=class{makeResponse(e,t,n){return{description:e,content:this.constructContent(t),headers:n?this.constructHeaders(n):void 0}}constructContent(e){return Object.entries(e).reduce((e,[t,{schema:n,examples:r}])=>(e[t]={schema:n,examples:r?this.constructExamples(r):void 0},e),{})}constructExamples(e){return Object.entries(e).reduce((e,[t,n])=>(e[t]={summary:n.summary,value:n.value},e),{})}constructHeaders(e){return e||{}}};Kn=S([_()],Kn);var qn=class{assemble(e){e.bind(T.DI.OpenAPI.SchemaController).to(Kn)}};let Jn=class{digest(e,t){let n=je(this.resolveDigestAlgorithm(t.algorithm)).update(e,`utf8`).digest();return this.encode(n,t.outputEncoding)}mac(e,t){let n=Me(this.resolveMacAlgorithm(t.algorithm),t.secret).update(e,`utf8`).digest();return this.encode(n,t.outputEncoding)}verifyMac(e,t,n){let r=this.mac(e,n);return this.timingSafeEqual(r,t)}async hashPassword(e,t){if(t.algorithm===`argon2id`)return He.hash(e,{type:He.argon2id,memoryCost:t.memoryCost,timeCost:t.timeCost,parallelism:t.parallelism})}async verifyPassword(e,t){try{return await He.verify(t,e)}catch{return!1}}timingSafeEqual(e,t){let n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&Pe(n,r)}encode(e,t){switch(t){case`hex`:return e.toString(`hex`);case`base64url`:return e.toString(`base64url`)}}resolveDigestAlgorithm(e){switch(e){case`sha256`:return`sha256`;case`sha384`:return`sha384`;case`sha512`:return`sha512`}}resolveMacAlgorithm(e){switch(e){case`hmac-sha256`:return`sha256`;case`hmac-sha384`:return`sha384`;case`hmac-sha512`:return`sha512`}}};Jn=S([_()],Jn);var Yn=class{_value;_payload;constructor(e,t){this._value=e,this._payload=t}get value(){return this._value}get payload(){return this._payload}getField(e){return p(()=>this._payload[e]).orDefault(void 0)}},Xn=class{assemble(e){e.bind(T.DI.Security.CryptographyController).to(Jn)}},Zn=b(async(e,t)=>{let n=t.apikitController.basicAuth;if(!n.enabled)return;let r=n.username,i=n.password;if(!r||!i)throw Error(`[ApiKit:BasicAuth] username and password are required when basic auth is enabled.`);await e.register(Ue,{validate:Qn(r,i),authenticate:n.authenticate,proxyMode:n.proxyMode,header:n.header,strictCredentials:n.strictCredentials})},{name:`apikit-basic-auth`});function Qn(e,t){return async(n,r)=>{$n({inputUsername:n,inputPassword:r,expectedUsername:e,expectedPassword:t})}}function $n(e){let t=er(e.inputUsername,e.expectedUsername),n=er(e.inputPassword,e.expectedPassword);if(!t||!n)throw Error(`Access denied`)}function er(e,t){let n=Buffer.isBuffer(e)?e:Buffer.from(e,`utf-8`),r=Buffer.isBuffer(t)?t:Buffer.from(t,`utf-8`);return n.length===r.length?Ae.timingSafeEqual(n,r):(Ae.timingSafeEqual(n,n),!1)}var tr=b(async e=>{await e.register(Oe,{hook:`onRequest`,parseOptions:{}})},{name:`apikit-cookie`}),nr=b(async(e,t)=>{let n=t.apikitController.cors;n.enabled&&await e.register(qe,rr(n))},{name:`apikit-cors`});function rr(e){let t=e.allowAllOrigins?!0:ir(e.options.origin,{includeWwwSubdomain:e.includeWwwSubdomain});return{...e.options,origin:t}}function ir(e,t){return e&&(typeof e==`string`?sr(e,t):Array.isArray(e)?ar(e,t):e)}function ar(e,t){let n=[];for(let r of e)or(n,r,t);return lr(n)}function or(e,t,n){if(typeof t==`string`){e.push(...sr(t,n));return}if(t instanceof RegExp||typeof t==`boolean`){e.push(t);return}if(Array.isArray(t))for(let r of t)or(e,r,n)}function sr(e,t){let n=cr(e);if(!n)return[e];if(!t.includeWwwSubdomain)return[n];let{protocol:r,host:i}=new URL(n);return/^[a-zA-Z][a-zA-Z0-9.-]*$/.test(i)?[n,`${r}//${i.startsWith(`www.`)?i:`www.${i}`}`]:[n]}function cr(e){try{let{protocol:t,host:n}=new URL(e);return`${t}//${n}`}catch{return null}}function lr(e){let t=new Set,n=[];for(let r of e){if(typeof r!=`string`){n.push(r);continue}t.has(r)||(t.add(r),n.push(r))}return n}const ur=`[ApiKit:Health]`;var dr=b(async(e,t)=>{let n=t.apikitController.health;if(!n.enabled){e.log.info(`${ur} Disabled — skipping`);return}await e.register(Ye,{exposeStatusRoute:n.url,maxEventLoopDelay:n.pressure.maxEventLoopDelay,maxHeapUsedBytes:n.pressure.maxHeapUsedBytes,maxRssBytes:n.pressure.maxRssBytes,maxEventLoopUtilization:n.pressure.maxEventLoopUtilization}),e.log.info(`${ur} Enabled`)},{name:`apikit-health`}),fr=b(async e=>{await e.register(Ze,{strict:!1,isAWS:!1})},{name:`apikit-ip`});const pr=`[ApiKit:Metrics]`;var mr=b(async(e,t)=>{let n=t.apikitController.metrics;if(!n.enabled){e.log.info(`${pr} Disabled — skipping`);return}await e.register($e,{endpoint:n.endpoint,name:n.name,defaultMetrics:n.defaultMetrics,routeMetrics:n.routeMetrics,clearRegisterOnInit:n.clearRegisterOnInit}),e.log.info(`${pr} Enabled`)},{name:`apikit-metrics`}),hr=b(async(e,t)=>{let n=t.apikitController.multipart;n.enabled&&await e.register(tt,n.options)},{name:`apikit-multipart`});function gr(e){let t=e.apikitController,n=t.logger;return n.enabled?xr([t.health.enabled?t.health.url:void 0,t.metrics.enabled?vr(t.metrics.endpoint):void 0,...n.request?.ignoredPaths??[]]):[]}function _r(e,t){let n=br(yr(e));return t.some(e=>{let t=br(e);return n===t||n.startsWith(`${t}/`)})}function vr(e){if(typeof e==`string`)return e;if(e&&typeof e==`object`&&`url`in e){let t=e.url;return typeof t==`string`?t:void 0}}function yr(e){return e.split(/[?#]/,1)[0]||`/`}function br(e){let t=e.trim(),n=t.startsWith(`/`)?t:`/${t}`;return n.length>1?n.replace(/\/+$/,``):n}function xr(e){return[...new Set(e.filter(e=>!!e?.trim()).map(br).filter(e=>e!==`/`))]}const Sr=`[ApiKit:Request]`,Cr=`[ApiKit:Response]`;var wr=b(async(e,t)=>{let n=t.logger,r=t.apikitController.logger,i=t.apikitController.isDebug,a=gr(t);r.enabled&&(e.addHook(`onRequest`,async e=>{if(_r(e.url,a))return;let t=new z(e.metadata);p(()=>{n.info(`${Sr} onRequest`,{metadata:t})})}),e.addHook(`preValidation`,async e=>{if(_r(e.url,a)||!i)return;let t=new z({requestId:e.metadata.requestId});p(()=>{n.debug(`${Sr} preValidation`,{metadata:t,details:{body:Tr(e.body,e.headers)}})})}),e.addHook(`onSend`,async(e,t,r)=>(_r(e.url,a)||p(()=>{let a=new z({requestId:e.metadata.requestId}),o={elapsedTime:t.elapsedTime,statusCode:t.statusCode};i?n.debug(`${Cr} onSend`,{metadata:a,details:{...o,body:Tr(r,t.getHeaders())}}):n.info(`${Cr} onSend`,{metadata:a,details:o})}),r)))},{name:`apikit-request-logger`,dependencies:[`apikit-request-metadata`]});function Tr(e,t){return String(t?.[R.contentType]??``).toLowerCase().includes(`multipart/form-data`)?`[Multipart]`:Er(e)}function Er(e,t=new WeakSet,n=0){if(!se(e))return`[Not provided]`;if(typeof e==`string`)try{return JSON.parse(e)}catch{return e}if(typeof e==`number`||typeof e==`boolean`)return e;if(typeof e==`bigint`||typeof e==`symbol`)return e.toString();if(typeof e==`function`)return`[Function: ${e.name||`anonymous`}]`;if(Buffer.isBuffer(e))return`[Buffer]`;if(e instanceof Re)return`[Stream]`;if(typeof e==`object`&&e&&`file`in e&&`filename`in e)return`[File]`;if(typeof e==`object`){if(t.has(e))return`[Circular]`;if(t.add(e),Array.isArray(e))return e.map(e=>Er(e,t,n+1));let r={};for(let[i,a]of Object.entries(e))r[i]=Er(a,t,n+1);return r}return String(e)}var Dr=b(async(e,t)=>{let n=t.i18nController;e.addHook(`onRequest`,async e=>{e.metadata={requestId:e.id,method:e.method,url:e.url,protocol:e.protocol,query:e.query,params:e.params,ip:ue(e.ip)?e.ips?.[0]??e.ip:e.ip,locale:n.parseLocale(e.headers[R.acceptLanguage]),headers:e.headers}})},{name:`apikit-request-metadata`}),Or=b(async e=>{e.addHook(`onRequest`,(e,t,n)=>{let r=e.metadata;B.run({metadata:r},()=>{n()})})},{name:`apikit-request-scope`,dependencies:[`apikit-request-metadata`]});const kr=`[ApiKit:Static]`,X={basicAuth:Zn,cookie:tr,cors:nr,health:dr,ip:fr,metrics:mr,multipart:hr,requestLogger:wr,requestMetadata:Dr,requestScope:Or,staticFiles:b(async(e,t)=>{let n=t.apikitController.staticFiles;if(!n.enabled){e.log.info(`${kr} Disabled — skipping`);return}if(!n.publicDirectory){let t=`${kr} publicDirectory is required when static files are enabled.`;throw e.log.error(t),Error(t)}await e.register(rt,{root:n.publicDirectory,prefix:n.routePrefix,maxAge:n.maxAge,dotfiles:n.dotfiles,etag:n.etag,immutable:n.immutable,decorateReply:n.decorateReply,preCompressed:n.preCompressed}),e.log.info(`${kr} Enabled from ${n.publicDirectory}`)},{name:`apikit-static`}),view:b(async e=>{await e.register(at,{engine:{ejs:ve}})},{name:`apikit-view`})},Z=`[Server]`;let Ar=class{i18n;logger;configuration;server;constructor(e,t,n){this.i18n=e,this.logger=t,this.configuration=n,this.server=ot({loggerInstance:this.logger.instance,logController:new st({disableRequestLogging:!0,requestIdLogLabel:`requestId`}),ajv:{customOptions:{strict:!0,keywords:[`example`]}},trustProxy:this.configuration.server.trustProxy})}get instance(){return this.server}async preparePlugins(e=async()=>{}){let t={i18nController:this.i18n,logger:this.logger,apikitController:this.configuration},n=[X.cookie,X.ip,X.requestMetadata,X.requestScope,X.requestLogger,X.cors,X.multipart,X.basicAuth,X.health,X.metrics],r=[X.staticFiles,X.view];for(let e of n)await this.server.register(e,t);await e(this.server,t);for(let e of r)await this.server.register(e,t)}async prepare(e){await this.configureErrorHandler(),await this.configureShutdownHandler(e)}async start(){let e=this.configuration.server.host,t=this.configuration.server.port;if(!Number.isInteger(t)||t<=0||t>65535)throw Error(`Invalid server port "${t}", must be an integer 1-65535.`);await this.server.ready(),await this.server.listen({host:e,port:t,listenTextResolver:e=>`${Z} Listening at ${e}`}),this.logger.info(`${Z} Debug mode ${this.configuration.isDebug?`ON`:`OFF`}`),this.logger.info(`${Z} Started on ${e}:${t}`)}async configureErrorHandler(){this.server.setErrorHandler(async(e,n,r)=>{let i=Array.isArray(e.validation),a=!e.statusCode||e.statusCode===500,o=U.make(`Server.INTERNAL_SERVER_ERROR`);switch(this.configuration.isDebug&&this.logger.debug(`${Z} Error Handler:`,{error:e}),!0){case e instanceof N:return r.status(e.statusCode).send(e.toJSON());case i:{let t=U.make(`Validation.BAD_REQUEST`),n=e.statusCode||t.statusCode,i=new N({statusCode:n,code:t.code,message:t.message});return r.status(n).send(i.toJSON())}case a:return this.logger.error(`${Z} Internal Server Error`,{flag:t.Important,metadata:new z({requestId:n.metadata.requestId}),error:e}),r.status(500).send(o.toJSON());default:{let t=e.statusCode||500,n=new N({statusCode:t,code:e.code||e.name||o.code,message:e.message||o.message});return r.status(t).send(n.toJSON())}}})}async configureShutdownHandler(e){let t=async(t,n)=>{if(this.logger.warn(`${Z} ⛔ Shutdown: ${t}`),e)try{await e()}catch(e){this.logger.error(`${Z} ⚠️ Shutdown hook failed`,{error:e})}try{await this.server.close(),this.logger.info(`${Z} ✅ Closed`)}catch(e){this.logger.error(`${Z} ❌ Close failed`,{error:e})}n&&this.logger.error(`${Z} 🚨 Fatal error during shutdown`,{error:n}),process.exit(+!!n)},n=[[`SIGINT`,()=>t(`SIGINT`)],[`SIGTERM`,()=>t(`SIGTERM`)],[`uncaughtException`,e=>t(`uncaughtException`,e)],[`unhandledRejection`,e=>t(`unhandledRejection`,e)]];for(let[e,t]of n)process.on(e,t)}};Ar=S([_(),O(0,g(T.DI.I18n.Controller)),O(1,g(f.DI.Logger)),O(2,g(T.DI.Configuration.Controller)),D(`design:paramtypes`,[Object,Object,Object])],Ar);const jr=`[ApiKit:Request]`;let Mr=class{logger;responseController;constructor(e,t){this.logger=e,this.responseController=t}handler(e,t={}){return async(n,r)=>{try{let i=await e(n,t);return await this.responseController.sendResponse(n,r,i)}catch(e){throw await this.logError(n,e),e}}}preHandler(e,t={}){return async(n,r)=>{try{let i=await e(n,t);if(i)return await this.responseController.sendResponse(n,r,i)}catch(e){throw await this.logError(n,e),e}}}async logError(e,n){await oe(()=>{let r=e.metadata.requestId;n instanceof N?this.logger.info(`${jr} Api error response`,{error:n,metadata:new z({requestId:r})}):this.logger.error(`${jr} Unexpected error`,{flag:t.Important,error:n,metadata:new z({requestId:r})})})}};Mr=S([_(),O(0,g(f.DI.Logger)),O(1,g(T.DI.Server.ResponseController)),D(`design:paramtypes`,[Object,Object])],Mr);const Nr=`[ApiKit:Response]`;let Pr=class{logger;constructor(e){this.logger=e}async sendResponse(e,t,n){switch(n.responseType){case`JSON`:return await this.sendJSONResponse(e,t,n);case`File`:return await this.sendFileResponse(e,t,n);default:throw Error(`${Nr} Unsupported response type`)}}async sendJSONResponse(e,t,n){let r=this.createResponseHeaders(n.headers);return t.headers(r).type(`application/json`).status(n.statusCode).send(n.data)}async sendFileResponse(e,t,n){let r=this.createResponseHeaders(n.headers);t.headers(r).type(`text/html`).status(n.statusCode);try{if(n.shouldRender){let e=await t.viewAsync(n.filePath,n.data);return t.send(e)}return t.sendFile(n.filePath)}catch(t){let n=e.metadata.requestId;throw this.logger.error(`${Nr} File response failed`,{error:t,metadata:new z({requestId:n})}),t}}createResponseHeaders(e){return{[R.cacheControl]:`no-store`,...e||{}}}};Pr=S([_(),O(0,g(f.DI.Logger)),D(`design:paramtypes`,[Object])],Pr);var Fr=class{assemble(e){e.bind(T.DI.Server.Controller).to(Ar).inSingletonScope(),e.bind(T.DI.Server.RequestController).to(Mr).inSingletonScope(),e.bind(T.DI.Server.ResponseController).to(Pr).inSingletonScope()}};let Q=class{configuration;logger;constructor(e,t){this.configuration=e,this.logger=t}validate(e,t){try{return e.parse(t)}catch(e){this.handleError(e)}}async validateAsync(e,t){try{return await e.parseAsync(t)}catch(e){this.handleError(e)}}handleError(e){if(e instanceof ct){this.configuration.isDebug&&this.logger.debug(`[ApiKit:Validation] Dto validation failed`,{details:{tree:lt.treeifyError(e)}});let t=this.buildValidationDetails(e),n=this.buildValidationMessage(e);throw U.make(`Validation.INVALID_PROPERTIES`,{details:t,overrideMessage:n})}throw e}buildValidationDetails(e){return{issues:e.issues.map(e=>({code:e.code,path:e.path.map(e=>typeof e==`number`?e:String(e)),message:e.message}))}}buildValidationMessage(e){for(let t of e.issues){if(t.code!==`custom`||!t.params)continue;let e=t.params;if(!e?.i18n?.key)continue;let{key:n,values:r}=e.i18n;return r?V.t(n,r):V.t(n)}return null}};Q=S([_(),O(0,g(T.DI.Configuration.Controller)),O(1,g(f.DI.Logger)),D(`design:paramtypes`,[Object,Object])],Q);let $=class{isValidEmail(e){return!!e&&y.isEmail(e)}isValidEmailThrowing(e){if(!this.isValidEmail(e))throw U.make(`Validation.INVALID_EMAIL_FORMAT`)}isValidPhoneNumber(e,t){if(!e)return!1;let n;return n=t?Be(e,t):Be(e),!!n?.isValid()}isValidPhoneNumberThrowing(e,t){if(!this.isValidPhoneNumber(e,t))throw U.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}isValidCode(e){return!!e&&/^\d{6}$/.test(e)}isValidCodeThrowing(e){if(!this.isValidCode(e))throw U.make(`Validation.INVALID_FORMAT`,{details:`Input is not a valid code`})}isEmail(e){return!!e&&y.isEmail(e)}isEmailThrowing(e){if(!this.isEmail(e))throw U.make(`Validation.INVALID_EMAIL_FORMAT`)}isPhoneNumber(e){return!!e&&y.isMobilePhone(e)}isPhoneNumberThrowing(e){if(!this.isPhoneNumber(e))throw U.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}isNumber(e){return typeof e==`number`&&!isNaN(e)}isNumberThrowing(e){if(!this.isNumber(e))throw U.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not a valid number`})}isString(e){return typeof e==`string`}isStringThrowing(e){if(!this.isString(e))throw U.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not a valid string`})}isEmptyString(e){return e==null||e.trim()===``}isEmptyStringThrowing(e){if(!this.isEmptyString(e))throw U.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not an empty string`})}isNonEmptyString(e){return this.isString(e)&&!this.isEmptyString(e)}isNonEmptyStringThrowing(e){let t=e;if(typeof t!=`string`||t.trim()===``)throw U.make(`Validation.INVALID_PROPERTIES`,{details:`Input is empty or not a string`});return t}isValidDate(e){if(!e)return!1;let t=new Date(e);return!isNaN(t.getTime())}isValidDateThrowing(e){if(!this.isValidDate(e))throw U.make(`Validation.INVALID_DATE_FORMAT`);return new Date(e)}};$=S([_()],$);var Ir=class{assemble(e){e.bind(T.DI.Validation.Controller).to($),e.bind(T.DI.Validation.DtoController).to(Q)}};function Lr(){return[new Bt,new Vt,new Gt,new Kt,new kn,new jn,new Mn,new Nn,new Fn,new Gn,new qn,new Xn,new Fr,new Ir]}function Rr(){let e=global.apikit.loggerConfig,t=e.enabled?{enabled:!0,debug:global.apikit.serverConfig.debug,transports:e.transports}:{enabled:!1,debug:global.apikit.serverConfig.debug};return[...n({logger:t}),...Lr()]}export{N as ApiError,xn as ApiErrorCodes,U as ApiErrorFactory,C as ApiKitControllerImpl,I as ApiKitL10n,F as ApiKitL10nResource,T as ApiKitSymbols,_n as AuthorizationErrors,Wt as BaseEmailTemplate,pt as BasicAuthConfiguration,mt as BuildConfiguration,mn as CommonErrors,rn as Cookie,ht as CorsConfiguration,Jn as CryptographyControllerImpl,q as DEFAULT_GENERATE_STRING_OPTIONS,Q as DtoValidationControllerImpl,_t as EmailConfiguration,A as EmailControllerImpl,X as FastifyPlugins,ln as FileHttpResponse,yn as FormatErrors,Dn as FormatType,On as Formatter,W as FormatterControllerImpl,vt as HealthConfiguration,R as HttpHeaders,an as HttpMethod,sn as HttpResponse,bt as I18nConfiguration,L as I18nControllerImpl,pn as I18nFactory,V as I18nProvider,bn as ImageErrors,Y as ImageNormalizationControllerImpl,cn as JSONHttpResponse,gn as LimitErrors,xt as LoggerConfiguration,Tt as MetricsConfiguration,E as MongoDbQueryFormatterImpl,Et as MultipartConfiguration,G as MultipartFormatterControllerImpl,Pn as NormalizationControllerImpl,zn as NotificationChannel,Dt as NotificationConfiguration,Kn as OpenAPISchemaControllerImpl,K as RANDOM_VALUE_GENERATOR_LIMITS,J as RandomValueGeneratorImpl,Mr as RequestControllerImpl,z as RequestLogMetadata,B as RequestScope,Pr as ResponseControllerImpl,on as ResponseType,Mt as ServerConfiguration,Ar as ServerControllerImpl,hn as ServerErrors,Nt as StaticFilesConfiguration,M as TemporaryFileRepositoryImpl,Yn as Token,$ as ValidationControllerImpl,vn as ValidationErrors,Rr as apikitAssembly,Rt as defineConfig,H as defineErrors,We as fastifyBasicAuth,Ee as fastifyCookie,Ke as fastifyCors,Xe as fastifyIp,Qe as fastifyMetrics,et as fastifyMultipart,nt as fastifyStatic,Je as fastifyUnderPressure,it as fastifyView,Ge as fp,P as isApiErrorDefinition,Ft as loadApiKitContext};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildplease/apikit",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "keywords": [],
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,8 +41,7 @@
41
41
  "resources"
42
42
  ],
43
43
  "dependencies": {
44
- "@buildplease/core": "1.0.2",
45
- "@dotenvx/dotenvx": "2.21.0",
44
+ "@buildplease/core": "1.1.0",
46
45
  "@fastify/basic-auth": "6.3.0",
47
46
  "@fastify/cookie": "11.1.2",
48
47
  "@fastify/cors": "11.3.0",