@buildplease/apikit 1.0.2 → 1.1.1
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.
- package/README.md +21 -4
- package/dist/cli/index.mjs +6 -6
- package/dist/src/index.cjs +1 -1
- package/dist/src/index.d.cts +185 -263
- package/dist/src/index.d.mts +185 -263
- package/dist/src/index.mjs +1 -1
- package/dist/{src-node-test → src-test}/index.d.cts +2 -2
- package/dist/{src-node-test → src-test}/index.d.mts +2 -2
- package/package.json +7 -8
- /package/dist/{src-node-test → src-test}/index.cjs +0 -0
- /package/dist/{src-node-test → src-test}/index.mjs +0 -0
package/dist/src/index.mjs
CHANGED
|
@@ -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{ByteUnit as e,CoreL10nResource as t,CoreSymbols as n,ScopeController as r,coreAssembly as i,defineL10n as a,filterObject as o,ignoreError as s,ignoreErrorAsync as c,isDefinedAndNotNull as l,isEmptyObject as u,isNonEmptyString as ee,isNullOrEmpty as te,isObject as ne,isPlainObject as re}from"@buildplease/core";import{LogFlag as ie,LoggerImpl as ae,createDirectoryAsync as oe,defineConfig as se,defineConfiguration as d,ensureDirectory as ce,ensureDirectoryAsync as le,field as f,loadSelectedEnvironmentConfig as ue,removePathAsync as de,resolveConfiguration as p,resolveConfigurationBinding as fe,resolvePath as pe}from"@buildplease/core/node";import m,{existsSync as me}from"node:fs";import h from"node:path";import{createJiti as he}from"jiti";import{inject as g,injectable as _,multiInject as ge,optional as _e}from"inversify";import ve from"node:fs/promises";import ye from"ejs";import be from"nodemailer";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 from"node:os";import{Readable as Oe}from"node:stream";import{pipeline as ke}from"node:stream/promises";import Ae from"mime-types";import je,{createHash as Me,createHmac as Ne,randomInt as Pe,timingSafeEqual as Fe}from"node:crypto";import{v4 as Ie,v7 as Le}from"uuid";import{PassThrough as Re,Readable as ze}from"stream";import{pipeline as Be}from"stream/promises";import v from"sharp";import{parsePhoneNumberFromString as Ve,parsePhoneNumberWithError as He}from"libphonenumber-js";import y from"validator";import*as Ue from"argon2";import We,{default as Ge}from"@fastify/basic-auth";import Ke,{default as b}from"fastify-plugin";import qe,{default as Je}from"@fastify/cors";import Ye,{default as Xe}from"@fastify/under-pressure";import Ze,{default as Qe}from"fastify-ip";import $e,{default as et}from"fastify-metrics";import tt,{default as nt}from"@fastify/multipart";import rt,{default as it}from"@fastify/static";import at,{default as ot}from"@fastify/view";import st,{LogController as ct}from"fastify";import{ZodError as lt,z as ut}from"zod";export*from"@buildplease/core";export*from"@buildplease/core/node";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 dt(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 ft(await he(e,{interopDefault:!1}).import(n,{try:!0}),n)}function ft(e,t){if(!pt(e)||!pt(e.BuildMetadata))throw Error(`ApiKit build metadata is missing (${t}).`);let n=e.BuildMetadata,r=n.name;if(!pt(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 pt(e){return typeof e==`object`&&!!e}const mt=d(`apikit.basic-auth`,{enabled:f.boolean().default(x.basicAuth.enabled),authenticate:f.custom().default(x.basicAuth.authenticate),proxyMode:f.boolean().default(x.basicAuth.proxyMode),header:f.string().optional().default(x.basicAuth.header),strictCredentials:f.boolean().optional().default(x.basicAuth.strictCredentials),username:f.string().optional(),password:f.string().optional()}),ht=d(`apikit.build`,{outDir:f.string().default(x.build.outDir)}),gt=d(`apikit.cors`,{enabled:f.boolean().default(x.cors.enabled),allowAllOrigins:f.boolean().default(x.cors.allowAllOrigins),includeWwwSubdomain:f.boolean().default(x.cors.includeWwwSubdomain),options:f.custom().default({}).map(_t)});function _t(e){return{...x.cors.options,...e}}const vt=d(`apikit.email`,{enabled:f.boolean().default(x.email.enabled),templatesPath:f.string().default(x.email.templatesPath),globals:f.custom().default(x.email.globals),smtp:{host:f.string().optional(),port:f.number().optional(),secure:f.boolean().optional(),user:f.string().optional(),password:f.string().optional()}}),yt=d(`apikit.health`,{enabled:f.boolean().default(x.health.enabled),url:f.string().default(x.health.url).map(bt),pressure:{maxEventLoopDelay:f.number().default(x.health.pressure.maxEventLoopDelay),maxHeapUsedBytes:f.number().default(x.health.pressure.maxHeapUsedBytes),maxRssBytes:f.number().default(x.health.pressure.maxRssBytes),maxEventLoopUtilization:f.number().default(x.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 xt=d(`apikit.i18n`,{resources:f.custom().default(x.i18n.resources),directories:f.array(f.custom()).default(x.i18n.directories),files:f.array(f.custom()).default(x.i18n.files),defaultLanguage:f.string().default(x.i18n.defaultLanguage),fallbackLanguages:f.custom().default(x.i18n.fallbackLanguages),supportedLanguages:f.array(f.string()).default(x.i18n.supportedLanguages),load:f.custom().default(x.i18n.load),preload:f.custom().default(x.i18n.preload),nonExplicitSupportedLngs:f.boolean().default(x.i18n.nonExplicitSupportedLngs),lowerCaseLng:f.boolean().default(x.i18n.lowerCaseLng),cleanCode:f.boolean().default(x.i18n.cleanCode),namespaces:f.array(f.string()).optional(),defaultNamespace:f.string().default(x.i18n.defaultNamespace),keySeparator:f.string().default(x.i18n.keySeparator),nsSeparator:f.string().default(x.i18n.nsSeparator),pluralSeparator:f.string().default(x.i18n.pluralSeparator),contextSeparator:f.string().default(x.i18n.contextSeparator)}),St=d(`apikit.logger`,f.custom().default({enabled:x.logger.enabled}).map(Ct));function Ct(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)=>Tt(e,t))}}}function Tt(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 Et=d(`apikit.metrics`,{enabled:f.boolean().default(x.metrics.enabled),endpoint:f.custom().default(x.metrics.endpoint),name:f.string().default(x.metrics.name),defaultMetrics:f.custom().default(x.metrics.defaultMetrics),routeMetrics:f.custom().default(x.metrics.routeMetrics),clearRegisterOnInit:f.boolean().default(x.metrics.clearRegisterOnInit)}),Dt=d(`apikit.multipart`,{enabled:f.boolean().default(x.multipart.enabled),options:f.custom().default(x.multipart.options)}),Ot=d(`apikit.notification`,f.custom().default({enabled:x.notification.enabled}).map(kt));function kt(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.`);jt(e.channels);let t=At(e.channels.telegram);if(!t)throw Error(`apikit.notification.channels must contain at least one configured channel.`);return{enabled:!0,channels:{telegram:t}}}function At(e){if(e!==void 0){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`apikit.notification.channels.telegram must be object.`);return{token:Mt(e.token,`apikit.notification.channels.telegram.token`),chatId:Mt(e.chatId,`apikit.notification.channels.telegram.chatId`)}}}function jt(e){for(let t of Object.keys(e))if(t!==`telegram`)throw Error(`apikit.notification.channels.${t} is not supported.`)}function Mt(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 Nt=d(`apikit.server`,{identifier:f.string(),debug:f.boolean().default(x.server.debug),host:f.string(),port:f.number(),trustProxy:f.custom().default(x.server.trustProxy)}),Pt=d(`apikit.staticFiles`,{enabled:f.boolean().default(x.staticFiles.enabled),publicDirectory:f.string().optional(),routePrefix:f.string().default(x.staticFiles.routePrefix),maxAge:f.number().default(x.staticFiles.maxAge),dotfiles:f.custom().default(x.staticFiles.dotfiles),etag:f.boolean().default(x.staticFiles.etag),immutable:f.boolean().default(x.staticFiles.immutable),decorateReply:f.boolean().default(x.staticFiles.decorateReply),preCompressed:f.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 Ft=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)}};Ft=S([_()],Ft);function It(e,t){return se(e,{...t,configurations:t.configurations??[]})}let C=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}};C=S([_()],C);const Lt={name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`},w=`${Lt.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`)}}};function E(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function D(e,t){return function(n,r){t(n,r,e)}}const O=`[Email]`;let k=class{configuration;logger;transporter;templatesPath;isEnabled;smtpConfig;constructor(e,t){this.configuration=e,this.logger=t,this.isEnabled=this.configuration.email.enabled,this.smtpConfig=Rt(this.configuration.email),this.templatesPath=zt(this.configuration.email.templatesPath)}async sendEmail(e){try{if(!this.isEnabled){this.logger.debug(`${O} 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(`${O} Send failed`,{error:e}),e}}getOrCreateTransporter(){return this.transporter||=be.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 ve.readFile(t,`utf-8`),r={globals:this.makeGlobals(),...e.data};return ye.render(n,r)}catch(e){throw this.logger.error(`${O} Render failed`,{error:e}),e}}makeFilePath(e,t){let n=h.join(this.templatesPath,this.sanitizeTemplatePath(e));if(me(n))return n;if(t){let e=h.join(this.templatesPath,this.sanitizeTemplatePath(t));if(me(e))return e}throw Error(`${O} 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(`${O} Invalid template path: ${e}`);let t=e.replace(/^\/+/,``);return t.endsWith(`.ejs`)?t:`${t}.ejs`}};k=S([_(),D(0,g(T.DI.Configuration.Controller)),D(1,g(n.DI.Logger)),E(`design:paramtypes`,[Object,Object])],k);function Rt(e){if(!e.enabled)return{host:``,port:0,secure:!1,user:``,pass:``};let t=e.smtp;if(!t.host)throw Error(`${O} email.smtp.host is required when email is enabled`);if(!t.port)throw Error(`${O} email.smtp.port is required when email is enabled`);if(t.secure===void 0)throw Error(`${O} email.smtp.secure is required when email is enabled`);if(!t.user)throw Error(`${O} email.smtp.user is required when email is enabled`);if(!t.password)throw Error(`${O} email.smtp.password is required when email is enabled`);if(!Number.isInteger(t.port)||t.port<=0)throw Error(`${O} 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 zt(e){let t=e.trim();return h.isAbsolute(t)?h.normalize(t):h.resolve(process.cwd(),t)}var Bt=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(){}},A=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 o(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 j(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 M=t.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}}.`}}}}}}),N=a(M);function Vt(e){return(e??``).toLowerCase().replace(/_/g,`-`).trim()}function Ht(e){let[t,n]=e.split(`-`);return{base:t||``,region:n}}let Ut=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=Vt(n[0]??``);if(!r||r===`*`){c++;continue}let l=Zt(n.find(e=>e.startsWith(`q=`)));if(l===0){c++;continue}let{base:u}=Ht(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=Wt(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)}};Ut=S([_(),D(0,g(T.DI.Configuration.Controller)),E(`design:paramtypes`,[Object])],Ut);function Wt(e){let t=Kt(e);Gt(t,e);let n=[...Jt(e),...Yt(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]=xe(n[r]||{},a)}return t}function Gt(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 Kt(e){let t={};for(let n of Object.keys(M.resources).sort()){let r=t[n]||={};r[e.defaultNamespace]=qt(M.resources[n])}return t}function qt(e){return JSON.parse(JSON.stringify(e))}function Jt(e){let t=[];for(let n of e.directories){let e=Xt(pe(process.cwd(),n.path));for(let r of e)t.push({locale:r.locale,ns:n.namespace,path:r.path})}return t}function Yt(e){return e.files.map(e=>({locale:e.locale,ns:e.namespace,path:pe(process.cwd(),e.path)}))}function Xt(e){let t=ce(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:pe(t,e)}))}function Zt(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 Qt=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 P={accept:`accept`,acceptLanguage:`accept-language`,authorization:`authorization`,cacheControl:`cache-control`,contentType:`content-type`,cookie:`cookie`,setCookie:`set-cookie`,userAgent:`user-agent`};let $t=function(e){return e.POST=`POST`,e.PUT=`PUT`,e.PATCH=`PATCH`,e.GET=`GET`,e.DELETE=`DELETE`,e.OPTIONS=`OPTIONS`,e}({}),en=function(e){return e.JSON=`JSON`,e.File=`File`,e}({});var tn=class{statusCode;headers;constructor({statusCode:e,headers:t}){this.statusCode=e,this.headers=t}},nn=class extends tn{data;responseType=`JSON`;constructor({statusCode:e,data:t,headers:n}){super({statusCode:e,headers:n}),this.data=t}},rn=class extends tn{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}},F=class{metadata;constructor(e){this.metadata=e}toJSON(){let e={[P.userAgent]:this.metadata.headers?.[P.userAgent],[P.contentType]:this.metadata.headers?.[P.contentType],[P.acceptLanguage]:this.metadata.headers?.[P.acceptLanguage],[P.accept]:this.metadata.headers?.[P.accept]},t=o({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 u(t)?void 0:t}};const an=Symbol.for(`request-scope.storage`);function on(){let e=Reflect.get(globalThis,an);if(e)return e;let t=new Ee;return Reflect.defineProperty(globalThis,an,{value:t,configurable:!1,enumerable:!1,writable:!1}),t}const sn=on(),I={run(e,t){return sn.run(e,t)},get metadata(){let e=sn.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 L=class{static t(e,t={}){let n=I.locale;return Se.t(e,{...t,lng:n})}static get currentLocale(){return I.locale}static isSupportedLanguage(e,t={ignoreRegion:!0}){let n=Vt(e);if(!n)return!1;let r=Se.options.supportedLngs;if(!r)return!1;let i=new Set(r.map(Vt));if(i.has(n))return!0;if(t.ignoreRegion){let{base:e}=Ht(n);if(e&&i.has(e))return!0}return!1}},cn=class{static make(e,t={}){return this.translateKey(e,t)}static translateKey(e,t={}){let{overrideMessage:n,i18n:r}=t;return n??L.t(e,r)}};function R(e){return _n(e),e}const ln=R({NOT_FOUND:{message:N.Apikit.Errors.Common.NotFound,code:`RESOURCE_NOT_FOUND`,statusCode:404},UNKNOWN_ERROR:{message:N.Apikit.Errors.Common.UnknownError,code:`UNKNOWN_ERROR`,statusCode:500},UNABLE_TO_PROCESS_REQUEST:{message:N.Apikit.Errors.Common.UnableToProcessRequest,code:`UNABLE_TO_PROCESS_REQUEST`,statusCode:500},RESOURCE_ALREADY_EXISTS:{message:N.Apikit.Errors.Common.AlreadyExists,code:`RESOURCE_ALREADY_EXISTS`,statusCode:409}}),un=R({INTERNAL_SERVER_ERROR:{message:N.Apikit.Errors.Server.Internal,code:`INTERNAL_SERVER_ERROR`,statusCode:500},SERVICE_UNAVAILABLE:{message:N.Apikit.Errors.Server.Unavailable,code:`SERVICE_UNAVAILABLE`,statusCode:503},DEPENDENCY_FAILED:{message:N.Apikit.Errors.Server.DependencyFailed,code:`DEPENDENCY_FAILED`,statusCode:424},TIMEOUT:{message:N.Apikit.Errors.Server.Timeout,code:`TIMEOUT`,statusCode:504}}),dn=R({TOO_MANY_REQUESTS:{message:N.Apikit.Errors.Limit.TooManyRequests,code:`TOO_MANY_REQUESTS`,statusCode:429}}),fn=R({UNAUTHORIZED:{message:N.Apikit.Errors.Auth.Unauthorized,code:`UNAUTHORIZED`,statusCode:401},FORBIDDEN:{message:N.Apikit.Errors.Auth.Forbidden,code:`FORBIDDEN`,statusCode:403}}),pn=R({BAD_REQUEST:{message:N.Apikit.Errors.Validation.BadRequest,code:`BAD_REQUEST`,statusCode:400},INVALID_JSON_SYNTAX:{message:N.Apikit.Errors.Validation.InvalidJsonSyntax,code:`JSON_SYNTAX_ERROR`,statusCode:400},INVALID_PROPERTIES:{message:N.Apikit.Errors.Validation.InvalidProperties,code:`INVALID_PROPERTIES`,statusCode:400},INVALID_FORMAT:{message:N.Apikit.Errors.Validation.InvalidFormat,code:`INVALID_FORMAT`,statusCode:400},INVALID_DATE_FORMAT:{message:N.Apikit.Errors.Validation.InvalidDateFormat,code:`INVALID_DATE_FORMAT`,statusCode:400},INVALID_PASSWORD:{message:N.Apikit.Errors.Validation.InvalidPassword,code:`INVALID_PASSWORD`,statusCode:403},INVALID_PASSWORD_NEW_SAME_AS_OLD:{message:N.Apikit.Errors.Validation.InvalidPasswordNewSameAsOld,code:`INVALID_PASSWORD_NEW_SAME_AS_OLD`,statusCode:409},INVALID_PHONE_NUMBER_FORMAT:{message:N.Apikit.Errors.Validation.InvalidPhoneNumberFormat,code:`INVALID_PHONE_NUMBER_FORMAT`,statusCode:400},INVALID_PHONE_NEW_SAME_AS_OLD:{message:N.Apikit.Errors.Validation.InvalidPhoneNewSameAsOld,code:`INVALID_PHONE_NEW_SAME_AS_OLD`,statusCode:409},INVALID_EMAIL_FORMAT:{message:N.Apikit.Errors.Validation.InvalidEmailFormat,code:`INVALID_EMAIL_FORMAT`,statusCode:400},INVALID_EMAIL_NEW_SAME_AS_OLD:{message:N.Apikit.Errors.Validation.InvalidEmailNewSameAsOld,code:`INVALID_EMAIL_NEW_SAME_AS_OLD`,statusCode:409}}),mn=R({UNSUPPORTED_FORMAT:{message:N.Apikit.Errors.Format.Unsupported,code:`UNSUPPORTED_FORMAT`,statusCode:400},MAX_SIZE_EXCEEDED:{message:N.Apikit.Errors.Format.MaxSizeExceeded,code:`MAX_SIZE_EXCEEDED`,statusCode:413}}),hn=R({MAX_SIZE_EXCEEDED:{message:N.Apikit.Errors.Image.MaxSizeExceeded,code:`IMAGE_MAX_SIZE_EXCEEDED`,statusCode:413}}),gn=R({Common:ln,Server:un,Limit:dn,Authorization:fn,Validation:pn,Format:mn,Image:hn});function _n(e){let t=new Set;vn(e,e=>{if(t.has(e.message))throw Error(`Duplicate API error message key: ${e.message}`);t.add(e.message)})}function vn(e,t){for(let n of Object.values(e)){if(j(n)){t(n);continue}vn(n,t)}}const z=yn(gn);function yn(e){return{codes:e,make(t,n={}){let r=xn(e,t);if(!r)throw Error(`Invalid API error code path: ${t}`);return bn(r,n)},extend(t){let n=xe({},e,t);return R(n),yn(n)}}}function bn(e,t){let{overrideMessage:n,details:r,i18n:i}=t,a=cn.translateKey(e.message,{overrideMessage:n,i18n:i});return new A({code:e.code,statusCode:e.statusCode,message:a,details:r})}function xn(e,t){let n=t.split(`.`),r=e;for(let e of n){if(!r||j(r))return;r=r[e]}if(!(!r||!j(r)))return r}const B=`[ApiKit:TemporaryFile]`;let V=class{logger;rootDir;constructor(e){this.logger=e,this.rootDir=De.tmpdir()}get rootDirectory(){return this.rootDir}async createDirectory(e){let t=this.safeJoin(e);try{return await oe(t)}catch(e){throw this.logger.error(`${B} Create directory failed`,{error:e,details:{abs:t}}),e}}async deleteDirectory(e){let t=this.safeJoin(e);try{await de(t,{recursive:!0,force:!0})}catch(e){throw this.logger.error(`${B} Delete directory failed`,{error:e,details:{abs:t}}),e}}async save(e,t,n,r){let i=this.safeJoin(r),a=h.join(i,`${e}.${n.extension}`);try{if(await oe(i),await le(i),Buffer.isBuffer(t))return await m.promises.writeFile(a,t),a;if(t instanceof Oe){let e=m.createWriteStream(a);try{return await ke(t,e),a}finally{e.close()}}let e=Error(`Unsupported content type: expected Buffer or Readable.`);throw this.logger.error(`${B} Save unsupported content`,{error:e,details:{fileAbs:a,typeof:typeof t}}),e}catch(t){throw this.logger.error(`${B} Save failed`,{error:t,details:{fileAbs:a,relativeDirectory:r,filename:e,extension:n.extension}}),t}}async delete(e){let t=this.safeJoin(e);try{await de(t,{recursive:!1,force:!0})}catch(e){throw this.logger.error(`${B} 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(`${B} Path traversal attempt`,{error:n,details:{root:this.rootDir,attempted:t}}),n}return t}};V=S([_(),D(0,g(n.DI.Logger)),E(`design:paramtypes`,[Object])],V);var Sn=class{mimeType;constructor(e){if(e.includes(`/`)){if(!Ae.extension(e))throw z.make(`Format.UNSUPPORTED_FORMAT`);this.mimeType=e;return}let t=Ae.lookup(e);if(!t)throw z.make(`Format.UNSUPPORTED_FORMAT`);this.mimeType=t}get value(){return this.mimeType}get extension(){let e=Ae.extension(this.mimeType);if(!e)throw z.make(`Format.UNSUPPORTED_FORMAT`);return e}equals(e){return this.mimeType===e.value}},Cn=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(re(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){ne(this.value)&&(this.value=Object.fromEntries(Object.entries(this.value).map(([t,n])=>[t,e[t]?.(n)??n])))}};let H=class{format(e){return new Cn(e)}};H=S([_()],H);let U=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(!ee(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}}};U=S([_()],U);const W={maxStringLength:4096,randomIntegerRangeLimit:2**48},G={length:8,alphabet:`alphanumeric`},wn={decimal:`0123456789`,lowercase:`abcdefghijklmnopqrstuvwxyz`,uppercase:`ABCDEFGHIJKLMNOPQRSTUVWXYZ`,letters:`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,alphanumeric:`0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,hex:`0123456789abcdef`,base64:`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,base64url:`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`};let K=class{generateNumber(e){return this.assertGenerateNumberOptions(e),e.min===e.max?e.min:Pe(e.min,e.max+1)}generateString(e=G){let t=e.length??G.length,n=this.resolveAlphabet(e.alphabet??G.alphabet);this.assertStringLength(t),this.assertAlphabet(n);let r=``;for(let e=0;e<t;e++)r+=n.charAt(Pe(0,n.length));return r}generateUuidV4(){return Ie()}generateUuidV7(){return Le()}resolveAlphabet(e){return typeof e==`string`?wn[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>=W.randomIntegerRangeLimit)throw Error(`GenerateNumberOptions range must be lower than ${W.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>W.maxStringLength)throw Error(`GenerateStringOptions.length must be lower than or equal to ${W.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`)}};K=S([_()],K);let q=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 Be(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 Be(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 z.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 z.make(`Format.UNSUPPORTED_FORMAT`,{details:`Unsupported input format: ${e}`});if(t&&!t.includes(e))throw z.make(`Format.UNSUPPORTED_FORMAT`,{details:`Format not allowed: ${e}`})}validateMaximumSize(t,n){if(!(!n||!t)&&t>n){let r=this.formatter.formatBytes(n,{inputUnit:e.Byte,outputUnit:`auto`,decimals:1});throw z.make(`Image.MAX_SIZE_EXCEEDED`,{i18n:{specs:{maxSize:r.value,unit:r.unit}},details:`current=${t}B, max=${n}B, exceeded=${t-n}B`})}}toSharpFormat(e){return e}toFormatType(e){if(!this.getFormatInfo(e)?.output){let t=`Cannot encode output format: ${e}`;throw z.make(`Format.UNSUPPORTED_FORMAT`,{details:t})}return new Sn(e)}getFormatInfo(e){return v.format[e]}asReadable(e){let t=new Re;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 z.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 z.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}}}}};q=S([_(),D(0,g(n.DI.Formatter.UnitController)),E(`design:paramtypes`,[Object])],q);let J=class{normalizeEmail(e){let t=e.trim();if(!y.isEmail(t))throw z.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 z.make(`Validation.INVALID_EMAIL_FORMAT`);return n}normalizePhoneToE164(e){try{return He(e).format(`E.164`)}catch{throw z.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}normalizePhoneToInternational(e){try{return He(e).format(`INTERNATIONAL`)}catch{throw z.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}normalizePhoneToNational(e){try{return He(e).format(`NATIONAL`).replace(/[^\d]/g,``)}catch{throw z.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}}};J=S([_()],J);let Tn=function(e){return e.Telegram=`telegram`,e}({}),Y=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||{}}};Y=S([_()],Y);async function En(){let e=await ue(),t=e.config.input,n=e.environment,r=await p(ht,t.build,{environment:n}),i=await dt(e.rootDir,r.outDir),a=await Dn(t,{buildMetadata:i,environment:n});global.apikit={build:i,environmentConfig:n,...a}}async function Dn(e,t){return{serverConfig:await p(Nt,e.server,t),loggerConfig:await p(St,e.logger,t),metricsConfig:await p(Et,e.metrics,t),healthConfig:await p(yt,e.health,t),emailConfig:await p(vt,e.email,t),notificationConfig:await p(Ot,e.notification,t),i18nConfig:await p(xt,e.i18n,t),staticFilesConfig:await p(Pt,e.staticFiles,t),basicAuthConfig:await p(mt,e.basicAuth,t),corsConfig:await p(gt,e.cors,t),multipartConfig:await p(Dt,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 fe(r,t))}return n}var kn=class{assemble(e){e.bind(T.DI.Configuration.Controller).to(Ft).inSingletonScope()}},An=class{assemble(e){e.bind(T.DI.Database.MongoDB.QueryFormatter).to(C)}},jn=class{assemble(e){e.bind(T.DI.Email.Controller).to(k).inSingletonScope()}},Mn=class{assemble(e){e.bind(T.DI.File.TemporaryRepository).to(V)}},Nn=class{assemble(e){e.bind(T.DI.Formatter.Controller).to(H),e.bind(T.DI.Formatter.MultipartController).to(U)}},Pn=class{assemble(e){e.bind(T.DI.Generator.RandomValueGenerator).to(K)}},Fn=class{assemble(e){e.bind(T.DI.I18n.Controller).to(Ut)}},In=class{assemble(e){e.bind(T.DI.Image.NormalizationController).to(q)}};let Ln=class extends ae{constructor(e){let t=e.logger,n=e.isDebug,r=t.enabled?{enabled:!0,debug:n,transports:t.transports}:{enabled:!1,debug:n};super(r)}};Ln=S([_(),D(0,g(T.DI.Configuration.Controller)),E(`design:paramtypes`,[Object])],Ln);var Rn=class{assemble(e){e.bind(n.DI.Logger).to(Ln).inSingletonScope()}},zn=class{assemble(e){e.bind(T.DI.Normalization.Controller).to(J)}};const Bn=`${Lt.name}.ApiKit.Internal.DI`,Vn={DI:{Notification:{ChannelController:Symbol.for(`${Bn}.Notification.ChannelController`)}}},X=`[Notification]`,Hn=`${X}:Telegram`;var Un=class{configuration;channel=`telegram`;constructor(e){this.configuration=e}async send(e){if(e.type!==this.channel)throw Error(`${Hn} 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:Wn(e.payload)})})}catch{throw Error(`${Hn} Request failed.`)}if(!t.ok)throw Error(`${Hn} Request failed with status ${t.status}.`)}};function Wn(e){return e.title===void 0?e.message:`${e.title}\n\n${e.message}`}let Gn=class{logger;channelControllers;constructor(e,t){this.logger=t,this.channelControllers=Kn(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(`${X} Channel "${e.type}" is unavailable.`);return await t.send(e),{channel:e.type,status:`sent`}}catch(r){if(this.logger.error(`${X} Delivery failed.`,{error:r,details:{channel:e.type}}),t)throw r;return n}}};Gn=S([_(),D(0,ge(Vn.DI.Notification.ChannelController)),D(0,_e()),D(1,g(n.DI.Logger)),E(`design:paramtypes`,[Object,Object])],Gn);function Kn(e){let t=new Map;for(let n of e){if(t.has(n.channel))throw Error(`${X} Channel "${n.channel}" is registered more than once.`);t.set(n.channel,n)}return t}let qn=class{channel=`telegram`;controller;constructor(e){let t=e.notification,n=t.enabled?t.channels.telegram:void 0;n&&(this.controller=new Un(n))}async send(e){if(!this.controller)throw Error(`${X} Channel "${this.channel}" is unavailable.`);await this.controller.send(e)}};qn=S([_(),D(0,g(T.DI.Configuration.Controller)),E(`design:paramtypes`,[Object])],qn);var Jn=class{assemble(e){e.bind(Vn.DI.Notification.ChannelController).to(qn).inSingletonScope(),e.bind(T.DI.Notification.Controller).to(Gn).inSingletonScope()}},Yn=class{assemble(e){e.bind(T.DI.OpenAPI.SchemaController).to(Y)}};let Z=class{digest(e,t){let n=Me(this.resolveDigestAlgorithm(t.algorithm)).update(e,`utf8`).digest();return this.encode(n,t.outputEncoding)}mac(e,t){let n=Ne(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 Ue.hash(e,{type:Ue.argon2id,memoryCost:t.memoryCost,timeCost:t.timeCost,parallelism:t.parallelism})}async verifyPassword(e,t){try{return await Ue.verify(t,e)}catch{return!1}}timingSafeEqual(e,t){let n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&Fe(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`}}};Z=S([_()],Z);var Xn=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 s(()=>this._payload[e]).orDefault(void 0)}},Zn=class{assemble(e){e.bind(T.DI.Security.CryptographyController).to(Z)}},Qn=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(We,{validate:$n(r,i),authenticate:n.authenticate,proxyMode:n.proxyMode,header:n.header,strictCredentials:n.strictCredentials})},{name:`apikit-basic-auth`});function $n(e,t){return async(n,r)=>{er({inputUsername:n,inputPassword:r,expectedUsername:e,expectedPassword:t})}}function er(e){let t=tr(e.inputUsername,e.expectedUsername),n=tr(e.inputPassword,e.expectedPassword);if(!t||!n)throw Error(`Access denied`)}function tr(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?je.timingSafeEqual(n,r):(je.timingSafeEqual(n,n),!1)}var nr=b(async e=>{await e.register(Te,{hook:`onRequest`,parseOptions:{}})},{name:`apikit-cookie`}),rr=b(async(e,t)=>{let n=t.apikitController.cors;n.enabled&&await e.register(Je,ir(n))},{name:`apikit-cors`});function ir(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`?cr(e,t):Array.isArray(e)?or(e,t):e)}function or(e,t){let n=[];for(let r of e)sr(n,r,t);return ur(n)}function sr(e,t,n){if(typeof t==`string`){e.push(...cr(t,n));return}if(t instanceof RegExp||typeof t==`boolean`){e.push(t);return}if(Array.isArray(t))for(let r of t)sr(e,r,n)}function cr(e,t){let n=lr(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 lr(e){try{let{protocol:t,host:n}=new URL(e);return`${t}//${n}`}catch{return null}}function ur(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 dr=`[ApiKit:Health]`;var fr=b(async(e,t)=>{let n=t.apikitController.health;if(!n.enabled){e.log.info(`${dr} Disabled — skipping`);return}await e.register(Xe,{exposeStatusRoute:n.url,maxEventLoopDelay:n.pressure.maxEventLoopDelay,maxHeapUsedBytes:n.pressure.maxHeapUsedBytes,maxRssBytes:n.pressure.maxRssBytes,maxEventLoopUtilization:n.pressure.maxEventLoopUtilization}),e.log.info(`${dr} Enabled`)},{name:`apikit-health`}),pr=b(async e=>{await e.register(Qe,{strict:!1,isAWS:!1})},{name:`apikit-ip`});const mr=`[ApiKit:Metrics]`;var hr=b(async(e,t)=>{let n=t.apikitController.metrics;if(!n.enabled){e.log.info(`${mr} Disabled — skipping`);return}await e.register(et,{endpoint:n.endpoint,name:n.name,defaultMetrics:n.defaultMetrics,routeMetrics:n.routeMetrics,clearRegisterOnInit:n.clearRegisterOnInit}),e.log.info(`${mr} Enabled`)},{name:`apikit-metrics`}),gr=b(async(e,t)=>{let n=t.apikitController.multipart;n.enabled&&await e.register(nt,n.options)},{name:`apikit-multipart`});function _r(e){let t=e.apikitController,n=t.logger;return n.enabled?Sr([t.health.enabled?t.health.url:void 0,t.metrics.enabled?yr(t.metrics.endpoint):void 0,...n.request?.ignoredPaths??[]]):[]}function vr(e,t){let n=xr(br(e));return t.some(e=>{let t=xr(e);return n===t||n.startsWith(`${t}/`)})}function yr(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 br(e){return e.split(/[?#]/,1)[0]||`/`}function xr(e){let t=e.trim(),n=t.startsWith(`/`)?t:`/${t}`;return n.length>1?n.replace(/\/+$/,``):n}function Sr(e){return[...new Set(e.filter(e=>!!e?.trim()).map(xr).filter(e=>e!==`/`))]}const Cr=`[ApiKit:Request]`,wr=`[ApiKit:Response]`;var Tr=b(async(e,t)=>{let n=t.logger,r=t.apikitController.logger,i=t.apikitController.isDebug,a=_r(t);r.enabled&&(e.addHook(`onRequest`,async e=>{if(vr(e.url,a))return;let t=new F(e.metadata);s(()=>{n.info(`${Cr} onRequest`,{metadata:t})})}),e.addHook(`preValidation`,async e=>{if(vr(e.url,a)||!i)return;let t=new F({requestId:e.metadata.requestId});s(()=>{n.debug(`${Cr} preValidation`,{metadata:t,details:{body:Er(e.body,e.headers)}})})}),e.addHook(`onSend`,async(e,t,r)=>(vr(e.url,a)||s(()=>{let a=new F({requestId:e.metadata.requestId}),o={elapsedTime:t.elapsedTime,statusCode:t.statusCode};i?n.debug(`${wr} onSend`,{metadata:a,details:{...o,body:Er(r,t.getHeaders())}}):n.info(`${wr} onSend`,{metadata:a,details:o})}),r)))},{name:`apikit-request-logger`,dependencies:[`apikit-request-metadata`]});function Er(e,t){return String(t?.[P.contentType]??``).toLowerCase().includes(`multipart/form-data`)?`[Multipart]`:Dr(e)}function Dr(e,t=new WeakSet,n=0){if(!l(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 ze)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=>Dr(e,t,n+1));let r={};for(let[i,a]of Object.entries(e))r[i]=Dr(a,t,n+1);return r}return String(e)}var Or=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:te(e.ip)?e.ips?.[0]??e.ip:e.ip,locale:n.parseLocale(e.headers[P.acceptLanguage]),headers:e.headers}})},{name:`apikit-request-metadata`}),kr=b(async e=>{e.addHook(`onRequest`,(e,t,n)=>{let r=e.metadata;I.run({metadata:r},()=>{n()})})},{name:`apikit-request-scope`,dependencies:[`apikit-request-metadata`]});const Ar=`[ApiKit:Static]`,Q={basicAuth:Qn,cookie:nr,cors:rr,health:fr,ip:pr,metrics:hr,multipart:gr,requestLogger:Tr,requestMetadata:Or,requestScope:kr,staticFiles:b(async(e,t)=>{let n=t.apikitController.staticFiles;if(!n.enabled){e.log.info(`${Ar} Disabled — skipping`);return}if(!n.publicDirectory){let t=`${Ar} publicDirectory is required when static files are enabled.`;throw e.log.error(t),Error(t)}await e.register(it,{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(`${Ar} Enabled from ${n.publicDirectory}`)},{name:`apikit-static`}),view:b(async e=>{await e.register(ot,{engine:{ejs:ye}})},{name:`apikit-view`})},$=`[Server]`;let jr=class{i18n;logger;configuration;server;constructor(e,t,n){this.i18n=e,this.logger=t,this.configuration=n,this.server=st({loggerInstance:this.logger.instance,logController:new ct({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=[Q.cookie,Q.ip,Q.requestMetadata,Q.requestScope,Q.requestLogger,Q.cors,Q.multipart,Q.basicAuth,Q.health,Q.metrics],r=[Q.staticFiles,Q.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=>`${$} Listening at ${e}`}),this.logger.info(`${$} Debug mode ${this.configuration.isDebug?`ON`:`OFF`}`),this.logger.info(`${$} Started on ${e}:${t}`)}async configureErrorHandler(){this.server.setErrorHandler(async(e,t,n)=>{let r=Array.isArray(e.validation),i=!e.statusCode||e.statusCode===500,a=z.make(`Server.INTERNAL_SERVER_ERROR`);switch(this.configuration.isDebug&&this.logger.debug(`${$} Error Handler:`,{error:e}),!0){case e instanceof A:return n.status(e.statusCode).send(e.toJSON());case r:{let t=z.make(`Validation.BAD_REQUEST`),r=e.statusCode||t.statusCode,i=new A({statusCode:r,code:t.code,message:t.message});return n.status(r).send(i.toJSON())}case i:return this.logger.error(`${$} Internal Server Error`,{flag:ie.Important,metadata:new F({requestId:t.metadata.requestId}),error:e}),n.status(500).send(a.toJSON());default:{let t=e.statusCode||500,r=new A({statusCode:t,code:e.code||e.name||a.code,message:e.message||a.message});return n.status(t).send(r.toJSON())}}})}async configureShutdownHandler(e){let t=async(t,n)=>{if(this.logger.warn(`${$} ⛔ Shutdown: ${t}`),e)try{await e()}catch(e){this.logger.error(`${$} ⚠️ Shutdown hook failed`,{error:e})}try{await this.server.close(),this.logger.info(`${$} ✅ Closed`)}catch(e){this.logger.error(`${$} ❌ Close failed`,{error:e})}n&&this.logger.error(`${$} 🚨 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)}};jr=S([_(),D(0,g(T.DI.I18n.Controller)),D(1,g(n.DI.Logger)),D(2,g(T.DI.Configuration.Controller)),E(`design:paramtypes`,[Object,Object,Object])],jr);const Mr=`[ApiKit:Request]`;let Nr=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,t){await c(()=>{let n=e.metadata.requestId;t instanceof A?this.logger.info(`${Mr} Api error response`,{error:t,metadata:new F({requestId:n})}):this.logger.error(`${Mr} Unexpected error`,{flag:ie.Important,error:t,metadata:new F({requestId:n})})})}};Nr=S([_(),D(0,g(n.DI.Logger)),D(1,g(T.DI.Server.ResponseController)),E(`design:paramtypes`,[Object,Object])],Nr);const Pr=`[ApiKit:Response]`;let Fr=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(`${Pr} 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(`${Pr} File response failed`,{error:t,metadata:new F({requestId:n})}),t}}createResponseHeaders(e){return{[P.cacheControl]:`no-store`,...e||{}}}};Fr=S([_(),D(0,g(n.DI.Logger)),E(`design:paramtypes`,[Object])],Fr);var Ir=class{assemble(e){e.bind(T.DI.Server.Controller).to(jr).inSingletonScope(),e.bind(T.DI.Server.RequestController).to(Nr).inSingletonScope(),e.bind(T.DI.Server.ResponseController).to(Fr).inSingletonScope()}};let Lr=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 lt){this.configuration.isDebug&&this.logger.debug(`[ApiKit:Validation] Dto validation failed`,{details:{tree:ut.treeifyError(e)}});let t=this.buildValidationDetails(e),n=this.buildValidationMessage(e);throw z.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?L.t(n,r):L.t(n)}return null}};Lr=S([_(),D(0,g(T.DI.Configuration.Controller)),D(1,g(n.DI.Logger)),E(`design:paramtypes`,[Object,Object])],Lr);let Rr=class{isValidEmail(e){return!!e&&y.isEmail(e)}isValidEmailThrowing(e){if(!this.isValidEmail(e))throw z.make(`Validation.INVALID_EMAIL_FORMAT`)}isValidPhoneNumber(e,t){if(!e)return!1;let n;return n=t?Ve(e,t):Ve(e),!!n?.isValid()}isValidPhoneNumberThrowing(e,t){if(!this.isValidPhoneNumber(e,t))throw z.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}isValidCode(e){return!!e&&/^\d{6}$/.test(e)}isValidCodeThrowing(e){if(!this.isValidCode(e))throw z.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 z.make(`Validation.INVALID_EMAIL_FORMAT`)}isPhoneNumber(e){return!!e&&y.isMobilePhone(e)}isPhoneNumberThrowing(e){if(!this.isPhoneNumber(e))throw z.make(`Validation.INVALID_PHONE_NUMBER_FORMAT`)}isNumber(e){return typeof e==`number`&&!isNaN(e)}isNumberThrowing(e){if(!this.isNumber(e))throw z.make(`Validation.INVALID_PROPERTIES`,{details:`Input is not a valid number`})}isString(e){return typeof e==`string`}isStringThrowing(e){if(!this.isString(e))throw z.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 z.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 z.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 z.make(`Validation.INVALID_DATE_FORMAT`);return new Date(e)}};Rr=S([_()],Rr);var zr=class{assemble(e){e.bind(T.DI.Validation.Controller).to(Rr),e.bind(T.DI.Validation.DtoController).to(Lr)}};function Br(){return[...i(),new kn,new An,new jn,new Mn,new Nn,new Pn,new Fn,new In,new Rn,new zn,new Jn,new Yn,new Zn,new Ir,new zr]}async function Vr(e={}){await En();let t=new r,n=e.hooks?.assemblies?.()??[];await t.registerAssemblies([...Br(),...n]);let i=t.getInstance(T.DI.I18n.Controller),a=t.getInstance(T.DI.Server.Controller),o={scope:t};await i.prepare();let s=e.hooks?.plugins;await a.preparePlugins(s?async(e,n)=>s({scope:t,server:e,options:n}):void 0);let c=e.hooks?.close;c&&a.instance.addHook(`onClose`,async()=>c(o)),await a.prepare(),await e.hooks?.prepare?.(o),await a.start()}export{A as ApiError,gn as ApiErrorCodes,z as ApiErrorFactory,Ft as ApiKitControllerImpl,N as ApiKitL10n,M as ApiKitL10nResource,T as ApiKitSymbols,fn as AuthorizationErrors,Bt as BaseEmailTemplate,mt as BasicAuthConfiguration,ht as BuildConfiguration,ln as CommonErrors,Qt as Cookie,gt as CorsConfiguration,Z as CryptographyControllerImpl,G as DEFAULT_GENERATE_STRING_OPTIONS,Lr as DtoValidationControllerImpl,vt as EmailConfiguration,k as EmailControllerImpl,Q as FastifyPlugins,rn as FileHttpResponse,mn as FormatErrors,Sn as FormatType,Cn as Formatter,H as FormatterControllerImpl,yt as HealthConfiguration,P as HttpHeaders,$t as HttpMethod,tn as HttpResponse,xt as I18nConfiguration,Ut as I18nControllerImpl,cn as I18nFactory,L as I18nProvider,hn as ImageErrors,q as ImageNormalizationControllerImpl,nn as JSONHttpResponse,dn as LimitErrors,St as LoggerConfiguration,Et as MetricsConfiguration,C as MongoDbQueryFormatterImpl,Dt as MultipartConfiguration,U as MultipartFormatterControllerImpl,J as NormalizationControllerImpl,Tn as NotificationChannel,Ot as NotificationConfiguration,Y as OpenAPISchemaControllerImpl,W as RANDOM_VALUE_GENERATOR_LIMITS,K as RandomValueGeneratorImpl,Nr as RequestControllerImpl,F as RequestLogMetadata,I as RequestScope,Fr as ResponseControllerImpl,en as ResponseType,Nt as ServerConfiguration,jr as ServerControllerImpl,un as ServerErrors,Pt as StaticFilesConfiguration,V as TemporaryFileRepositoryImpl,Xn as Token,Rr as ValidationControllerImpl,pn as ValidationErrors,It as defineConfig,R as defineErrors,Ge as fastifyBasicAuth,Ce as fastifyCookie,qe as fastifyCors,Ze as fastifyIp,$e as fastifyMetrics,tt as fastifyMultipart,rt as fastifyStatic,Ye as fastifyUnderPressure,at as fastifyView,Ke as fp,j as isApiErrorDefinition,Vr as runApiKit};
|
|
@@ -26,10 +26,10 @@ interface RequestMetadata {
|
|
|
26
26
|
locale: string;
|
|
27
27
|
}
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region src-
|
|
29
|
+
//#region src-test/request/request-metadata.d.ts
|
|
30
30
|
declare function makeRequestMetadataFixture(overrides?: Partial<RequestMetadata>): RequestMetadata;
|
|
31
31
|
//#endregion
|
|
32
|
-
//#region src-
|
|
32
|
+
//#region src-test/request/request-scope.d.ts
|
|
33
33
|
declare function withTestRequestScope<T>(callback: () => T, metadata?: Partial<RequestMetadata>): T;
|
|
34
34
|
//#endregion
|
|
35
35
|
export { makeRequestMetadataFixture, withTestRequestScope };
|
|
@@ -26,10 +26,10 @@ interface RequestMetadata {
|
|
|
26
26
|
locale: string;
|
|
27
27
|
}
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region src-
|
|
29
|
+
//#region src-test/request/request-metadata.d.ts
|
|
30
30
|
declare function makeRequestMetadataFixture(overrides?: Partial<RequestMetadata>): RequestMetadata;
|
|
31
31
|
//#endregion
|
|
32
|
-
//#region src-
|
|
32
|
+
//#region src-test/request/request-scope.d.ts
|
|
33
33
|
declare function withTestRequestScope<T>(callback: () => T, metadata?: Partial<RequestMetadata>): T;
|
|
34
34
|
//#endregion
|
|
35
35
|
export { makeRequestMetadataFixture, withTestRequestScope };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildplease/apikit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
"default": "./dist/src/index.cjs"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
|
-
"./
|
|
24
|
+
"./test": {
|
|
25
25
|
"import": {
|
|
26
|
-
"types": "./dist/src-
|
|
27
|
-
"default": "./dist/src-
|
|
26
|
+
"types": "./dist/src-test/index.d.mts",
|
|
27
|
+
"default": "./dist/src-test/index.mjs"
|
|
28
28
|
},
|
|
29
29
|
"require": {
|
|
30
|
-
"types": "./dist/src-
|
|
31
|
-
"default": "./dist/src-
|
|
30
|
+
"types": "./dist/src-test/index.d.cts",
|
|
31
|
+
"default": "./dist/src-test/index.cjs"
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
},
|
|
@@ -41,8 +41,7 @@
|
|
|
41
41
|
"resources"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@buildplease/core": "1.
|
|
45
|
-
"@dotenvx/dotenvx": "2.21.0",
|
|
44
|
+
"@buildplease/core": "1.1.1",
|
|
46
45
|
"@fastify/basic-auth": "6.3.0",
|
|
47
46
|
"@fastify/cookie": "11.1.2",
|
|
48
47
|
"@fastify/cors": "11.3.0",
|
|
File without changes
|
|
File without changes
|