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